如何解决尝试将COM类强制转换为接口时出现“ InvalidCastException”
我用C#写了一个非常简单的DLL,看起来像这样:
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[ComVisible(true)]
public interface IComClass1
{
void Do();
}
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F933"),ProgId("MyComProgId"),ComVisible(true)]
public class ComClass1 : IComClass1
{
void IComClass1.Do()
{
System.Windows.Forms.MessageBox.Show("ComClass1 ^^^^^ Test");
}
}
我的客户端看起来像这样:
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IComClass1
{
void Do();
}
class Program
{
static void Main(string[] args)
{
var type = Type.GetTypeFromProgID("MyComProgId");
var com = (IComClass1)Activator.CreateInstance(type); // ERROR: System.InvalidCastException
com.Do();
}
}
由于某种原因,这里有一个错误:InvalidCastException
。
为什么会发生错误?我错了吗?以及我该如何解决?
解决方法
由于.NET看到COM对象是.NET对象,因此无法在IComClass1
接口的两个定义之间进行对等,因此无效的强制转换异常。
一种解决方案是在与.idl文件分开的.tlb文件(类型库)中声明公共COM接口。
要创建一个.TLB,您可以想象使用regasm将.NET组件导出为TLB,不幸的是它可以工作,但是.NET项目无法引用生成的.TLB(同样,没有.NET-> COM- > .NET)。
但是,这仍然是一个好的开始,因为您可以从Windows SDK中查看带有OleView的.TLB,并基本上删除所有“自定义” IDL属性,这些属性表明它是.NET导出的.tlb。 / p>
所以,假设我在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或任何其他二进制文件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。