将WiX中TypeLib注册逻辑迁移至C#自定义操作代码
问题描述
我有一个WiX项目,使用以下代码注册COM库:
<Fragment> <ComponentGroup Id="COMObjectComponent" Directory="APPLICATIONFOLDER"> <Component Id="myCOMObject.lib" Guid="{AB4304B8-C9BA-49C7-5423-112CB1210000}"> <File Id="myCOMObject.exe" KeyPath="yes" Source="$(var.myCOMDir)\myCOMObject.exe"> <TypeLib Id="{86000350-400E-00F1-00DF-6F00F0CD0BBC}" Description="myCOMObjectLib" HelpDirectory="APPLICATIONFOLDER" Language="0" MajorVersion="1" MinorVersion="0" Advertise="yes"> <Class Id="{4326682B-657B-4DFE-A68D-47252874C000}" Context="LocalServer32" Description="myCOMObject Class" ThreadingModel="apartment" Version="1.0" /> <Interface Id="{225E49AF-4575-4876-A53B-81A5AB281111}" Name="ImyCOMObject" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" /> <Interface Id="{24592647-A858-5555-B01F-BE4DCB8C86A1}" Name="ImyCOMObjectCallbacks" ProxyStubClassId32="{11120424-1111-0000-C000-000000000046}" /> </TypeLib> </File> </Component> </ComponentGroup> </Fragment>
这段代码运行正常。现在我通过C#自定义操作从远程文件服务器下载上述文件,该文件不再嵌入WiX MSI包中。我希望在自定义操作中完成文件下载后,按照上述TypeLib标签的逻辑注册该组件,请问如何将该TypeLib部分的逻辑转换为可在自定义操作中执行的C#代码?
解决方案
要在C#自定义操作中实现WiX里TypeLib标签的注册逻辑,可通过以下几种方式完成:
方法一:调用系统自带的COM注册工具
最简单的方式是直接调用EXE的自注册功能(如果你的EXE支持自注册,即实现了DllRegisterServer入口):
using System.Diagnostics; string exePath = @"C:\Path\To\Downloaded\myCOMObject.exe"; // 调用EXE自注册,通常使用 /regserver 参数 ProcessStartInfo psi = new ProcessStartInfo(exePath, "/regserver") { CreateNoWindow = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden }; Process.Start(psi).WaitForExit();
这种方式会自动处理TypeLib、Class和Interface的所有注册项,效果和WiX完全一致,但需要确保目标EXE支持自注册。
方法二:手动操作注册表(精确复刻WiX逻辑)
如果需要完全匹配WiX中TypeLib标签的注册细节,可以手动在注册表中创建对应键值,以下是对应配置的C#代码示例:
首先引用Microsoft.Win32命名空间,然后编写注册逻辑:
using Microsoft.Win32; string exePath = @"C:\Path\To\Downloaded\myCOMObject.exe"; string appFolder = @"C:\Path\To\ApplicationFolder"; // 对应WiX的APPLICATIONFOLDER // 1. 注册TypeLib string typeLibId = "{86000350-400E-00F1-00DF-6F00F0CD0BBC}"; string typeLibKeyPath = $@"SOFTWARE\Classes\TypeLib\{typeLibId}\1.0\0"; using (RegistryKey typeLibKey = Registry.LocalMachine.CreateSubKey(typeLibKeyPath)) { typeLibKey.SetValue("", "myCOMObjectLib"); // 设置TypeLib描述 typeLibKey.SetValue("win32", exePath); typeLibKey.SetValue("HelpDirectory", appFolder); } // 2. 注册Class string classId = "{4326682B-657B-4DFE-A68D-47252874C000}"; string classKeyPath = $@"SOFTWARE\Classes\CLSID\{classId}"; using (RegistryKey classKey = Registry.LocalMachine.CreateSubKey(classKeyPath)) { classKey.SetValue("", "myCOMObject Class"); // 设置Class描述 using (RegistryKey localServerKey = classKey.CreateSubKey("LocalServer32")) { localServerKey.SetValue("", exePath); localServerKey.SetValue("ThreadingModel", "apartment"); } // 关联TypeLib using (RegistryKey typeLibSubKey = classKey.CreateSubKey("TypeLib")) { typeLibSubKey.SetValue("", typeLibId); } // 设置版本 using (RegistryKey versionSubKey = classKey.CreateSubKey("Version")) { versionSubKey.SetValue("", "1.0"); } } // 3. 注册Interface ImyCOMObject string interfaceId1 = "{225E49AF-4575-4876-A53B-81A5AB281111}"; string interfaceKeyPath1 = $@"SOFTWARE\Classes\Interface\{interfaceId1}"; using (RegistryKey interfaceKey1 = Registry.LocalMachine.CreateSubKey(interfaceKeyPath1)) { interfaceKey1.SetValue("", "ImyCOMObject"); using (RegistryKey proxyStubKey = interfaceKey1.CreateSubKey("ProxyStubClsid32")) { proxyStubKey.SetValue("", "{00020424-0000-0000-C000-000000000046}"); } // 关联TypeLib using (RegistryKey typeLibSubKey = interfaceKey1.CreateSubKey("TypeLib")) { typeLibSubKey.SetValue("", typeLibId); } } // 4. 注册Interface ImyCOMObjectCallbacks string interfaceId2 = "{24592647-A858-5555-B01F-BE4DCB8C86A1}"; string interfaceKeyPath2 = $@"SOFTWARE\Classes\Interface\{interfaceId2}"; using (RegistryKey interfaceKey2 = Registry.LocalMachine.CreateSubKey(interfaceKeyPath2)) { interfaceKey2.SetValue("", "ImyCOMObjectCallbacks"); using (RegistryKey proxyStubKey = interfaceKey2.CreateSubKey("ProxyStubClsid32")) { proxyStubKey.SetValue("", "{11120424-1111-0000-C000-000000000046}"); } // 关联TypeLib using (RegistryKey typeLibSubKey = interfaceKey2.CreateSubKey("TypeLib")) { typeLibSubKey.SetValue("", typeLibId); } }
注意事项
- 自定义操作必须以管理员权限运行,否则无法写入
HKLM注册表项。 - 64位系统下需注意注册表重定向,可使用
RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)操作64位注册表。 - 卸载时需对应删除这些注册表项,避免残留。
方法三:使用WiX的DTF库
如果自定义操作项目引用了WiX的DTF(Deployment Tools Foundation)库,可以用更贴合WiX逻辑的方式实现注册:
using Microsoft.Deployment.WindowsInstaller; using Microsoft.Deployment.WindowsInstaller.Com; string exePath = @"C:\Path\To\Downloaded\myCOMObject.exe"; // 提取并注册TypeLib TypeLib typeLib = TypeLib.FromFile(exePath); typeLib.Register(TypeLibRegistrationMode.Register); // 如需精细化控制Class和Interface,可使用DTF封装的类进行操作,逻辑与方法二一致但更简洁
这种方式完全对齐WiX的原生注册逻辑,需要在项目中添加WiX DTF相关程序集引用。
内容的提问来源于stack exchange,提问作者Willy
相关产品推荐
相关产品推荐

