我编写了一个COM组件,通过WIX生成的MSI文件进行分发。
该COM组件具有相当复杂和非静态的注册逻辑,这意味着直接将注册信息嵌入Windows Installer WXS文件中不是可行的选择 - 必须使用regsvr32进行注册 - 并且它是一个32位的COM组件,因此必须使用32位版本的regsvr32.exe - 在64位Windows上是%SystemRoot%\SysWow64\regsvr32.exe,在x86 Windows上是%SystemRoot%\System32\regsvr32.exe。
我注意到在这个WXS XML中存在两个问题:
该COM组件具有相当复杂和非静态的注册逻辑,这意味着直接将注册信息嵌入Windows Installer WXS文件中不是可行的选择 - 必须使用regsvr32进行注册 - 并且它是一个32位的COM组件,因此必须使用32位版本的regsvr32.exe - 在64位Windows上是%SystemRoot%\SysWow64\regsvr32.exe,在x86 Windows上是%SystemRoot%\System32\regsvr32.exe。
我注意到在这个WXS XML中存在两个问题:
<InstallExecuteSequence>
<Custom Action="COMRegister" After="InstallFinalize">NOT Installed</Custom>
<Custom Action="COMUnregister" After="InstallInitialize">Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="COMRegister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s "[APPLICATIONROOTDIRECTORY]Component.dll"' />
<CustomAction Id="COMUnregister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s /u "[APPLICATIONROOTDIRECTORY]Component.dll"' />
- 错误的
regsvr32.exe
被调用。我注意到64位系统上运行了x64版本的resgvr32.exe
而不是32位版本。 regsvr32.exe
没有以提升的权限运行,因此COM注册失败并出现E_ACCESSDENIED
。
对于第一个问题,如果我使用[WindowsFolder]\SysWOW64\regsvr32.exe
硬编码路径到regsvr32.exe可执行文件,则可以解决该问题,但在真正的32位机器上无法运行,因为SysWow64
不存在。
对于第二个问题,我在网上看到将After="InstallFinalize"
更改为After="RemoveExistingProducts"
会导致以提升的权限运行,但实际上只会产生关于RemoveExistingProducts
未解决符号名称的错误。
如何解决这两个问题?
更新
(在与这个问题斗争了2个小时之后,我相信WIX的作者是H.P. Lovecraft的近亲)
我通过编写自己的中间步骤程序来解决第一个问题,它是一个32位可执行文件,因此它将始终在WOW上下文下运行,因此将可靠地调用32位的regsvr32.exe
程序。
我发现第二个问题的原因是这些条件:为了使CustomAction以提升的权限运行(在与主安装程序作业相同的安全上下文中),必须满足以下条件:
<Custom/>
必须具有Before="InstallFinalize"
,而不是After=""
。任何其他值都不能可靠地工作,因为WIX或Windows Installer可能会重新排列操作(奇怪)。<CustomAction />
必须明确设置以下属性:Execute="deferred"
Impersonate="off"
即使如此,我仍希望不必使用我的辅助程序来正确解决32位的regsvr32.exe
。有哪些选项?