如何在C#项目中正确使用旧ActiveX组件?
我有一些曾在Internet Explorer中使用的旧ActiveX库,在JavaScript中可通过new ActiveXObject("MyLib.MyClass")直接创建对象并使用,该类已注册,但在C#项目中遇到了以下问题:
问题1:引用路径依赖与COM引用失败
- 目前只能通过浏览按钮直接添加库引用,
.csproj文件中可见<HintPath>..\..\..\..\..\Program Files (x86)\MyLib\MyLib.dll</HintPath>,这种方式存在隐患,其他开发者将项目放在不同盘符会报错。 - 尝试用
RegAsm.exe /tlb生成类型库后,库在“添加引用>COM>类型库”列表中可见,但添加时提示错误:The ActiveX type library 'C:\Program Files (x86)\MyLib\MyLib.tlb' was exported from a .NET assembly and cannot be added as a reference. - 发现该ActiveX是.NET程序集,但在“添加引用>程序集>扩展”中找不到它;尝试用
gacutil.exe将其加入GAC,报错:Failure adding assembly to the cache: Attempt to install an assembly without a strong name - 疑问:如何正确将该ActiveX控件添加到C#项目中?遗漏了哪些步骤?
问题2:组件加载路径限制
该组件必须放在与宿主进程相同的目录才能加载,不符合ActiveX的使用逻辑。尝试将库路径加入PATH环境变量无效,推测解决问题1后该问题也会解决。
针对问题1:正确引用.NET编写的ActiveX组件
1. 规避相对路径依赖的方案
不要通过浏览添加本地路径引用,而是利用COM注册信息动态加载实例,彻底摆脱项目路径限制:
// 通过ProgID动态创建ActiveX实例,无需添加项目引用 Type myLibType = Type.GetTypeFromProgID("MyLib.MyClass"); object myLibInstance = Activator.CreateInstance(myLibType); // 通过反射调用组件方法(需提前知晓方法名与参数) myLibType.InvokeMember("TargetMethod", BindingFlags.InvokeMethod, null, myLibInstance, new object[] {参数1, 参数2});
2. 解决.NET程序集的COM引用报错问题
由于该ActiveX是.NET编写的,直接添加COM类型库会触发报错,可采用以下两种有效方式:
- 方式一:生成互操作程序集
使用tlbimp.exe工具将生成的.tlb文件转换为.NET互操作程序集,再引用这个生成的DLL:
将生成的tlbimp.exe "C:\Program Files (x86)\MyLib\MyLib.tlb" /out:Interop.MyLib.dllInterop.MyLib.dll复制到项目的本地引用目录(如Libs文件夹),再添加对该DLL的引用,通过项目相对目录避免路径问题。 - 方式二:修改项目引用配置
直接引用原始.dll,但修改.csproj中的引用配置,用系统宏替代硬编码路径:
这样无论项目放在哪个盘符,都会自动读取系统的Program Files(x86)路径。<Reference Include="MyLib"> <HintPath>$(ProgramFiles(x86))\MyLib\MyLib.dll</HintPath> <SpecificVersion>False</SpecificVersion> <Private>False</Private> </Reference>
3. 关于强名称的说明
JavaScript中使用ActiveX不需要强名称是因为直接通过COM ProgID注册加载,而GAC强制要求程序集带强名称。如果无法获取带签名的组件版本,不要强行加入GAC,采用上述动态加载或互操作程序集的方式即可满足需求。
针对问题2:组件加载路径限制
当你改用基于ProgID的动态加载或正确的互操作引用后,系统会从COM注册的路径中查找组件,而非依赖宿主进程目录。之前的路径限制是因为直接引用本地DLL时,程序优先从输出目录查找,而非读取COM注册位置。解决问题1后,该路径问题会自动消失。
内容的提问来源于stack exchange,提问作者Dialecticus

