Xamarin/Mono调用Marshal.GetObjectForIUnknown抛PlatformNotSupportedException咨询
在Xamarin.Android(Mono)环境下使用COM模型的可行方案
很遗憾告诉你,在Xamarin.Android的Mono运行环境中,原生的.NET COM互操作API(比如Marshal.GetObjectForIUnknown、Marshal.QueryInterface)确实是不支持的——你找到的Mono源码也验证了这一点,移动平台下这些方法被标记为未实现,直接抛出异常。
不过不用自己从头写复杂的桥接库,我们可以换一种思路来实现需求,核心是绕开Mono不支持的COM互操作API,直接通过P/Invoke来操作COM对象:
替代方案:手动通过P/Invoke调用COM接口方法
既然你已经能通过工厂方法拿到COM对象的IntPtr,那我们不需要把它转换成.NET对象,而是直接针对每个COM接口的方法定义P/Invoke签名,以IntPtr作为对象实例参数来调用,同时手动管理COM对象的引用计数。
举个具体的例子:
假设你有一个COM接口IMyObject,包含DoSomething(int param)方法,同时所有COM对象都实现了IUnknown的AddRef和Release:
1. 定义P/Invoke签名
// 调用IUnknown的AddRef,手动增加引用计数 [DllImport("your-native-library.so", CallingConvention = CallingConvention.Cdecl)] private static extern int IUnknown_AddRef(IntPtr comObject); // 调用IUnknown的Release,手动减少引用计数,释放对象 [DllImport("your-native-library.so", CallingConvention = CallingConvention.Cdecl)] private static extern int IUnknown_Release(IntPtr comObject); // 调用IMyObject的DoSomething方法 [DllImport("your-native-library.so", CallingConvention = CallingConvention.Cdecl)] private static extern int IMyObject_DoSomething(IntPtr myObject, int param);
2. 使用方式
// 通过工厂方法创建对象 IntPtr myObjPtr = NativeBridge.CreateMyObject(); try { // 调用接口方法 int result = IMyObject_DoSomething(myObjPtr, 123); // 处理返回结果... } finally { // 记得释放对象,避免内存泄漏 IUnknown_Release(myObjPtr); }
关键注意事项
- 引用计数管理:Mono不会帮你自动处理COM对象的引用计数,所以必须在使用完对象后调用
Release;如果需要持有对象更长时间,记得在合适的时机调用AddRef和Release来维护计数平衡。 - 签名匹配:确保P/Invoke的方法签名(参数类型、返回值、调用约定)和原生C++接口的方法完全一致,安卓平台下通常使用
CallingConvention.Cdecl。 - QueryInterface替代:如果需要从一个COM对象获取另一个接口的指针,可以直接定义
IUnknown_QueryInterface的P/Invoke签名,手动调用:
这样就能替代[DllImport("your-native-library.so", CallingConvention = CallingConvention.Cdecl)] private static extern int IUnknown_QueryInterface(IntPtr comObject, ref Guid iid, out IntPtr outInterfacePtr);Marshal.QueryInterface的功能。
为什么原来的方法行不通?
Mono的移动平台版本(包括Xamarin.Android)对.NET的COM互操作API做了裁剪,这些API原本是为Windows平台设计的,依赖系统级的COM基础设施,而安卓等移动平台并没有原生的COM支持,所以Mono直接跳过了这些方法的实现,导致调用时抛出异常。
内容的提问来源于stack exchange,提问作者KennnyCZ




