.NET 注册 COM 组件
2024-06-13 22:19:17

生成密钥文件

提前准备好一个密钥文件,因为将注册为 COM 组件时要求提供签名。
打开 Visual Studio 命令行工具,执行:

1
sn -k xxx.snk

得到文件后放到工程目录下即可。

.NET Framework 工程设置

传统风格的工程文件和新的 SDK style 稍微有些区别,所以分开说。

传统风格工程

默认 COM 可见性
打开工程设置窗口,点击程序集设置


这里不建议勾选,因为 .NET 默认会将程序集中所有访问权限为public的类都对外公开,这当然是不合适的。
所以这里默认没有勾选,实际上,这里的选项会影响AssemblyInfo.cs文件中ComVisible属性值。

为 COM 互操作注册选项决定在编译后是否自动注册 DLL,根据自身需要设置。

对应的工程属性为:

1
<RegisterForComInterop>true</RegisterForComInterop>


设置签名文件

对应的工程属性为:

1
2
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>xxx.snk</AssemblyOriginatorKeyFile>

然后编写一个测试接口和其实现即可,注意要在实现类上设置[ComVisible(true)]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Runtime.InteropServices;

namespace ClassLibrary2
{
public interface ICalc
{
int Add(int a, int b);
}

[ComVisible(true)]
[Guid("365BBAE2-A911-4078-952A-9B5734538C35")]
[ClassInterface(ClassInterfaceType.None)]
public sealed class Calc : ICalc
{
public int Add(int a, int b)
{
return a + b;
}
}
}

手动注册 COM 组件

如果设置了RegisterForComInterop属性的话会在编译后自动注册,否则就需要手动注册。
而用 .NET Framework 开发的 COM 组件不能用传统的regsvr32去注册,要用运行时自带的RegAsm.exe工具注册:

1
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe ClassLibrary2.dll /tlb:ClassLibrary2.tlb /codebase

注意我这里用的是 x64 架构注册,注册 COM 组件时要确认架构一致性。
卸载的话使用/u选项:

1
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe ClassLibrary2.dll /u

我们可以用 RegDllView 软件查看系统 COM 注册情况。

测试接口

COM 组件的好处是语言无关性,我们可以编写一个 VBScript 脚本测试接口:

1
2
3
4
5
Dim obj
Set obj = CreateObject("ClassLibrary2.Calc")
Dim result
result = obj.Add(5, 3)
MsgBox "The result is: " & result

结果正确

NET.Sdk 风格工程

.NET Sdk 风格的工程文件因为没有界面,所以需要手动编辑

1
2
3
4
5
6
7
8
9
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>xxx.snk</AssemblyOriginatorKeyFile>
<RegisterForComInterop>true</RegisterForComInterop>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
</Project>

因为 .NET Sdk 风格工程没有AssemblyInfo.cs文件设置程序集属性,这导致项目默认会将所有public的类都公开。
这就需要我们手动将程序集属性ComVisible设置为false

1
2
3
4
5
6
7
8
9
10
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.InteropServices.ComVisibleAttribute">
<_Parameter1>false</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>

不同于传统风格工程文件是将属性写在代码中,Sdk 风格将属性配置在工程文件中。

.NET 工程设置

对于新的 .NET 框架,使用EnableComHosting属性决定是否生成 COM Host(一个用于注册的本机 DLL 文件)。

1
2
3
4
5
6
7
8
9
10
11
12
13
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>net8</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>xxx.snk</AssemblyOriginatorKeyFile>
<EnableComHosting>true</EnableComHosting>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
</Project>

EnableComHosting属性为true时,编译后会多出一个[ProjectName].comhost.dll文件。

这不是 .NET 程序集,而是一个本机的 DLL 文件。

而这个 DLL 文件导出了注册 COM 需要的几个标准方法,用 C++ 开发过 COM 组件的一定都明白了。

可以看出 .NET 不同于 .NET Framework 框架的处理方式。所以这里不再需要用RegAsm.exe去注册了,直接原生注册即可。

1
regsvr32 ClassLibrary2.comhost.dll

卸载:

1
regsvr32 /u ClassLibrary2.comhost.dll

相关阅读

向 COM 公开 .NET Core 组件
在项目文件中设置程序集属性