由于 .NET 认为 COM 对象是一个 .NET 对象,它无法在 IComClass1 接口的两个定义之间建立等价关系,因此出现了无效强制转换异常。
一种解决方案是在独立于 .idl 文件的 .tlb 文件(类型库)中声明通用 COM 接口。
要创建 .TLB,您可以想象使用 regasm 将 .NET 组件导出为 TLB,不幸的是它可以工作,但生成的 .TLB 不能被 .NET 项目引用(同样,没有 .NET->COM- >.NET)。
不过,这仍然是一个好的开始,因为您可以查看来自 Windows SDK 的带有 OleView 的生成 .TLB,并基本上删除所有表明它是 .NET 导出的 .tlb 的“自定义”IDL 属性。
所以,假设我在 C# 中有这个定义:
namespace ClassLibrary2
{
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[ComVisible(true)]
public interface IComClass1
{
void Do();
}
}
例如,我编译并运行它(或使用 TlbExp):
c:\MyProject\ClassLibrary2\bin\Debug>tlbexp ClassLibrary2.dll
Microsoft (R) .NET Framework Assembly to Type Library Converter 4.8.3928.0
Copyright (C) Microsoft Corporation. All rights reserved.
Assembly exported to 'c:\MyProject\ClassLibrary2\bin\Debug\ClassLibrary2.tlb'
这是它在 OleView 中的样子:
如果您尝试从 .NET 项目中引用它,它会说:
---------------------------
Microsoft Visual Studio
---------------------------
A reference to 'c:\MyProject\ClassLibrary2\bin\Debug\ClassLibrary2.tlb' could not be added. Please make sure that the file is accessible, and that it is a valid assembly or COM component.
---------------------------
OK
---------------------------
恕我直言,这真是愚蠢。无论如何,因此,您必须修改 .tlb。将 OleView 结果复制粘贴到一些 test.idl 文本文件中,删除所有 "custom" idl attributes,如下所示:
[
uuid("your tlb guid here"),
version(1.0),
]
library ClassLibrary2 // some name or keep ClassLibrary2
{
importlib("mscorlib.tlb");
importlib("stdole2.tlb");
[
odl,
uuid(EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F), // your interface id
version(1.0),
dual,
oleautomation,
]
interface IComClass1 : IDispatch { // if the interface is IDispatch
[id(0x60020000)]
HRESULT Do();
};
};
现在在 test.idl 文件上运行 MIDL compiler:
c:\MyProject\ClassLibrary2\ClassLibrary1>midl test.idl
Microsoft (R) 32b/64b MIDL Compiler Version 8.01.0622
Copyright (c) Microsoft Corporation. All rights reserved.
Processing .\test.idl
test.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um\oaidl.idl
oaidl.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um\objidl.idl
objidl.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um\unknwn.idl
unknwn.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\wtypes.idl
wtypes.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\wtypesbase.idl
wtypesbase.idl
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\basetsd.h
basetsd.h
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared\guiddef.h
guiddef.h
Processing C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um\oaidl.acf
oaidl.acf
这将创建一个 .TLB,然后您现在可以使用标准 .NET 工具在两个项目中引用。请注意,它包含的类型应该自动嵌入到您的程序集中,无需发送 .tlb 或任何其他二进制文件。