C# Native AoT:如何获取托管类指针传递给COM对象
解决方案:兼容Trim/Native AOT的COM事件接收器注册
在Trim和Native AOT场景下,无法依赖Marshal类的方法,需使用.NET原生支持的ComWrappers机制实现托管对象到COM IUnknown*的转换,进而完成IConnectionPoint::Advise的调用。以下是具体步骤和代码示例:
1. 确认接口与托管类的实现
确保CsWin32生成的INetworkListManagerEvents接口带有正确的COM特性(CsWin32生成COM接口时会自动添加[ComImport]、[Guid]等特性),同时你的托管类要正确实现该接口:
// CsWin32生成的INetworkListManagerEvents接口示例 [ComImport] [Guid("DCB00C01-570F-4A9B-8D69-199FDBA5723B")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public partial interface INetworkListManagerEvents { void NetworkListManagerConnectivityChanged(NLM_CONNECTIVITY newConnectivity); } // 自定义事件接收器类 public class NetworkEventsReceiver : INetworkListManagerEvents { public void NetworkListManagerConnectivityChanged(NLM_CONNECTIVITY newConnectivity) { // 编写网络连接状态变化的处理逻辑 } }
2. 通过ComWrappers获取IUnknown指针
.NET 7及以上版本提供的ComWrappers.GetOrCreateComInterfaceForObject方法完全兼容Trim和Native AOT,可直接将托管对象转换为COM接口指针:
// 创建接收器实例 var receiver = new NetworkEventsReceiver(); // 获取IUnknown*对应的nint指针 nint unknownPtr = ComWrappers.GetOrCreateComInterfaceForObject( receiver, CreateComInterfaceFlags.None ); // 将指针转换为CsWin32生成的IUnknown接口实例 IUnknown unknown = unsafe { MarshalInterface<IUnknown>.FromPointer((IUnknown*)unknownPtr); };
3. 调用IConnectionPoint::Advise完成注册
拿到IUnknown实例后,即可传入Advise方法,同时保存返回的cookie用于后续取消注册:
// 假设已通过INetworkListManager.FindConnectionPoint获取到IConnectionPoint实例 IConnectionPoint connectionPoint = ...; uint cookie; HRESULT hr = connectionPoint.Advise(unknown, &cookie); if (hr.Succeeded) { // 保存cookie,后续取消注册时调用connectionPoint.Unadvise(cookie) } else { // 处理注册失败的逻辑 }
4. 通用场景适配
其他需要将托管类作为事件接收器传入Advise方法的场景,流程完全一致:
- 确保托管类正确实现对应的COM事件接口
- 使用
ComWrappers.GetOrCreateComInterfaceForObject获取IUnknown指针 - 将指针转换为目标COM接口类型后传入
Advise
注意事项
- 不再需要接收器时,务必调用
IConnectionPoint::Unadvise并释放COM接口指针(可通过MarshalInterface<IUnknown>.Release或ComWrappers.ReleaseComInterface) - .NET 6及以下版本需自定义
ComWrappers子类并手动注册,推荐升级到.NET 7+简化操作
内容的提问来源于stack exchange,提问作者Guezt
相关产品推荐
相关产品推荐

