• C#调用原生C++ COM对象(在C++中实现C#的接口)


    为了跨平台在.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等平台。架构师,程序员应合理利用。

  • 相关阅读:
    接口测试该怎么做
    Mac操作Github实现代码的下载、上传
    Django开发基础--操作数据库
    Django开发基础--创建项目/应用
    Python统计安卓log中Anr、Crash出现的数量
    Mac下PyCharm快捷键大全
    Selenium常用方法及函数、txt参数化
    Appium基于PO模型
    Selenium免登录、等待、unittest、PO模型
    Python接口请求及封装
  • 原文地址:https://www.cnblogs.com/fyter/p/csharp_netcore_impl_cpp_com_interface_cross_platform.html
Copyright © 2020-2023  润新知