首页 > 编程 > C++ > 正文

C#如何调用原生C++ COM对象详解

2020-05-23 13:58:15
字体:
来源:转载
供稿:网友

前言

最近在工作中遇到一个问题,为了跨平台在.net core中使用COM,不能使用Windows下的COM注册机制,但是可以直接把IUnknown指针传给C#,转换为指针,再转换为C#的接口(interface)。

做了这方面的研究,但最终我没有使用这套技术,因为对IDispatch::Invoke的分发太麻烦了,又不能借助ATL与VS开发环境的IDL能力。所以没有继续研究事件订阅(C#是event,C++COM是IConnectionPoint)。

C++中需要做的:

简单点,实现IDispatch就可以了,全面一点,实现IManagedObject或IProvideClassInfo,后者可是个大工程。

如果我们要实现C#中定义的接口,那么最好给(不给也可以,编译器会给每个接口一个默认的GUID)接口一个GUID,.net到你的对象QueryInterface时要处理这个IID,把IDispatch指针与S_OK返回即可。

如果跨平台,把__uuidof换成实际的UUID即可。

struct foo : public IDispatch{  // 通过 IDispatch 继承  virtual ULONG AddRef(void) override{return 0;}  virtual ULONG Release(void) override{return 0;}    virtual HRESULT QueryInterface(REFIID riid, void ** ppvObject) override     {      if (riid == __uuidof(IUnknown))      {    *ppvObject = (IUnknown*)this;    return S_OK;      }      IID uid;      IIDFromString(L"{C#声明接口的GUID/IID}", &uid);      if (riid == uid)      {         *ppvObject = (IDispatch*)this;// (IUnknown*)this;         return S_OK;       }       if (riid == __uuidof(IDispatch))       {         *ppvObject = (IDispatch*)this;         return S_OK;       }       return E_NOTIMPL;   }   virtual HRESULT GetTypeInfoCount(UINT * pctinfo) override{return S_OK;}  virtual HRESULT GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo) override{return S_OK;}  virtual HRESULT GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId) override  {        *rgDispId = 1;    return S_OK;  }   virtual HRESULT Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr) override  {        cout << "be called" << endl;    return S_OK;  }};  

再导出一个DLL的函数把指针给.net运行时

extern "C" __declspec(dllexport)foo* WINAPI GetTestObject(){  return new foo;// 简单粗暴leak :)}

C#代码:

[DllImport(@"foo.dll")]static extern IntPtr GetTestObject();  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)][Guid("your uiid")]interface Test{  int func();} var v = GetTestObject();obj = (Test)Marshal.GetObjectForIUnknown(v);var value = obj.func();// 输出be called

I love COM

COM思想很重要,COM最近不但活跃在Windows平台,更是蔓延到了Linux,安卓,iOS等平台。架构师,程序员应合理利用。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表