如何为COM对象方法创建Delegate?解决签名不兼容错误
解决COM方法创建Delegate的签名不兼容问题
这个错误的核心原因是你的Delegate签名和COM方法的实际封送行为不匹配,加上创建Delegate时没有正确绑定到COM实例对象。下面是具体的修复步骤和解释:
1. 修正Delegate的定义,匹配COM的封送规则
COM对象的方法参数和返回值通常使用BSTR字符串类型,而且默认采用StdCall调用约定。你需要显式指定这些封送属性,确保Delegate和COM方法的签名完全兼容:
<UnmanagedFunctionPointer(CallingConvention.StdCall)> Public Delegate Function GetDriveNameDelegate( <MarshalAs(UnmanagedType.BStr)> path As String ) As <MarshalAs(UnmanagedType.BStr)> String
2. 正确创建Delegate(绑定到COM实例)
你之前调用Delegate.CreateDelegate时只传入了MethodInfo,这是用于绑定静态方法的重载。而COM方法是实例方法,必须传入目标COM对象实例来完成绑定:
Public Function GetDelegateFromCOM(comObj As Object, methodName As String) As GetDriveNameDelegate Dim result As Type CType(comObj, IDispatchInfo).GetTypeInfo(0, 0, result) Dim mi As MethodInfo = result.GetMethod(methodName) ' 使用绑定实例的重载:Delegate.CreateDelegate(委托类型, 目标实例, 方法信息) Return DirectCast([Delegate].CreateDelegate(GetType(GetDriveNameDelegate), comObj, mi), GetDriveNameDelegate) End Function
3. 简化替代方案(无需自定义IDispatchInfo)
其实你不需要手动实现IDispatchInfo来获取类型信息,直接通过Type.GetTypeFromProgID拿到的类型就能正确获取MethodInfo,代码可以更简洁:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim fsoType As Type = Type.GetTypeFromProgID("Scripting.FileSystemObject") Dim fsoInstance As Object = Activator.CreateInstance(fsoType) ' 直接从类型获取方法信息 Dim mi As MethodInfo = fsoType.GetMethod("GetDriveName") ' 创建绑定到实例的Delegate Dim fsoDelegate As GetDriveNameDelegate = DirectCast([Delegate].CreateDelegate(GetType(GetDriveNameDelegate), fsoInstance, mi), GetDriveNameDelegate) MessageBox.Show(fsoDelegate.Invoke("C:\Windows")) End Sub
为什么之前的代码会报错?
- COM方法的底层签名和.NET方法有差异:COM方法本质是返回
HRESULT,实际结果通过[out, retval]参数传递,.NET会自动包装成返回值,但需要Delegate的封送属性匹配这个逻辑。 - 你使用了错误的
CreateDelegate重载:没有绑定到COM实例,导致无法正确关联到对象的实例方法。
内容的提问来源于stack exchange,提问作者Zeki Gürsoy
相关产品推荐
相关产品推荐

