You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Xamarin/Mono调用Marshal.GetObjectForIUnknown抛PlatformNotSupportedException咨询

在Xamarin.Android(Mono)环境下使用COM模型的可行方案

很遗憾告诉你,在Xamarin.Android的Mono运行环境中,原生的.NET COM互操作API(比如Marshal.GetObjectForIUnknownMarshal.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对象都实现了IUnknownAddRefRelease

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;如果需要持有对象更长时间,记得在合适的时机调用AddRefRelease来维护计数平衡。
  • 签名匹配:确保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

火山引擎 最新活动