zoukankan      html  css  js  c++  java
  • C# 互操作(一) 编写一个C++ COM组件

        C# 如何与C++ 编写的COM 组件进行交互,首先编写一个C++ ATL COM 组件,打开vs,新建一个ATL项目,将项目命名为COMServer,在Application Setting中,选择Dynamic Link Library(动态链接库)。创建项目后,右键点击项目,添加-类,选择ATL标签,选择ATL Simple Object (ATL 简单对象),在对话框中简称填写COMDemo,接口填写IWelcome,ProgId填写COMServer.COMDemo

    image

    然后在类视图下,选择接口IWelcome,并使用下面的参数添加方法Greeting

    HRESULT Greeting( [in] BSTR name, [out,retval] BSTR* message);

    image

    IDL 文件COMServer.idl 定义了COM的接口,向导在COMServer.idl文件中生成的代码应该与下面类似,唯一标识符(uuid)会不同。IWelcome接口定义了Greeting方法,关键字interface之前的中括号定义了该接口的一些特性。uuid定义额了接口ID,dual标记了接口类型。

    [
        object,
        uuid(4704A15D-CDE1-4BF1-A28E-E1477E7C74B8),
        dual,
        nonextensible,
        pointer_default(unique)
    ]
    interface IWelcome : IDispatch
    {
        [id(1)] HRESULT Greeting([in] BSTR name, [out, retval] BSTR* message);
    };

    IDL文件也定义了类型库的内容,它是实现了IWelcome接口的COM对象(coclass)

    [
        uuid(FBB80A75-06E1-452B-88BA-F7B00ED151A9),
        version(1.0),
    ]
    library COMServerLib
    {
        [
            uuid(85567ACE-7031-4246-9E81-CA5AA470F212),
        ]
        coclass COMDemo
        {
            [default] interface IWelcome;
        };
    };

    在IWelcome接口的头部,使用上述标识符和名称Learning.Interop.Server.IWelcome添加custom特性。在coclass COMDemo中使用对应的名称天界类似的custom特性:

    [
        object,
        uuid(4704A15D-CDE1-4BF1-A28E-E1477E7C74B8),
        dual,
        nonextensible,
        pointer_default(unique),
        custom(67412B27-B0FB-425A-A7D2-DAB66BD6768B, "Learning.Interop.Server.IWelcome")
    ]
    interface IWelcome : IDispatch
    {
        [id(1)] HRESULT Greeting([in] BSTR name, [out, retval] BSTR* message);
    };
    
    [
        uuid(FBB80A75-06E1-452B-88BA-F7B00ED151A9),
        version(1.0),
    ]
    library COMServerLib
    {
        [
            uuid(85567ACE-7031-4246-9E81-CA5AA470F212),
            helpstring("COMDemo Class"),
            custom(67412B27-B0FB-425A-A7D2-DAB66BD6768B, "Learning.Interop.Server.COMDemo")
        ]
        coclass COMDemo
        {
            [default] interface IWelcome;
        };
    };

    现在可以在COMServer.idl文件中再添加一个接口,可以把IWelcome的接口头部直接复制到新建的IMath接口的头部,但要记得修改uuid关键字定义的唯一标识符。

    IMath接口提供两个方法Add,Sub:

    //IMath
    [
        object,
        uuid(2158751B-B96E-461d-9012-EF1680BE0628),
        dual,
        nonextensible,
        pointer_default(unique),
        custom(67412B27-B0FB-425A-A7D2-DAB66BD6768B, "Learning.Interop.Server.IMath")
    ]
    interface IMath : IDispatch
    {
        
        [id(1)] HRESULT Add([in] LONG val1, [in] LONG val2, [out, retval] LONG* result);
        [id(2)] HRESULT Sub([in] LONG val1, [in] LONG val2, [out, retval] LONG* result);
    };

    还必须修改coclass COMDemo,使其同时实现接口IWelcome和IMath。IWelcome接口设为默认接口:

    [
        uuid(85567ACE-7031-4246-9E81-CA5AA470F212),
        helpstring("COMDemo Class"),
        custom(67412B27-B0FB-425A-A7D2-DAB66BD6768B, "Learning.Interop.Server.COMDemo")
    ]
    coclass COMDemo
    {
        [default] interface IWelcome;
        interface IMath;
    };

    现在可以将注意力从IDL文件转移到C++代码。COMDemo.h文件包含了COM对象的定义。类COMDemo使用多继承派生自模板类CComObjectRootEx,CComCoClass 和 IDispatchImpl.CComObjectRootEx 类实现了IUnknow接口的功能,例如AddRef和Release方法。CComCoClass类创建了一个工厂实例化模板参数对象,在这里是CComDemo。IDispatchImple实现了IDispathc接口的方法。

    包含在BEGIN_COM_MAP 和 END_COM_MAP中的宏创建了一个映射,用于定义COM类实现的所有COM接口。QuerInterface方法的实现会使用此映射

    class ATL_NO_VTABLE CCOMDemo :
        public CComObjectRootEx<CComSingleThreadModel>,
        public CComCoClass<CCOMDemo, &CLSID_COMDemo>,
        public IDispatchImpl<IWelcome, &IID_IWelcome, &LIBID_COMServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    {
    public:
        CCOMDemo()
        {
        }
    
    DECLARE_REGISTRY_RESOURCEID(IDR_COMDEMO1)
    
    
    BEGIN_COM_MAP(CCOMDemo)
        COM_INTERFACE_ENTRY(IWelcome)
        COM_INTERFACE_ENTRY2(IDispatch,IWelcome)
    END_COM_MAP()
    
    
    
        DECLARE_PROTECT_FINAL_CONSTRUCT()
    
        HRESULT FinalConstruct()
        {
            return S_OK;
        }
    
        void FinalRelease()
        {
        }
    
    public:
    
    
    
        STDMETHOD(Greeting)(BSTR name, BSTR* message);
    };
    
    OBJECT_ENTRY_AUTO(__uuidof(COMDemo), CCOMDemo)

    在这个类定义中,还需要添加第二接口IMath,以及IMath接口定义的方法:

    class ATL_NO_VTABLE CCOMDemo :
        public CComObjectRootEx<CComSingleThreadModel>,
        public CComCoClass<CCOMDemo, &CLSID_COMDemo>,
    public IDispatchImpl<IWelcome, &IID_IWelcome, &LIBID_COMServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
        public IDispatchImpl<IMath, &IID_IMath, &LIBID_COMServerLib, 1, 0>,
    {
    public:
        CCOMDemo()
        {
        }
    
    DECLARE_REGISTRY_RESOURCEID(IDR_COMDEMO1)
    
    
    BEGIN_COM_MAP(CCOMDemo)
        COM_INTERFACE_ENTRY(IWelcome)
        COM_INTERFACE_ENTRY(IMath)
        COM_INTERFACE_ENTRY2(IDispatch,IWelcome)
    END_COM_MAP()
    
    
    
        DECLARE_PROTECT_FINAL_CONSTRUCT()
    
        HRESULT FinalConstruct()
        {
            return S_OK;
        }
    
        void FinalRelease()
        {
        }
    
    public:
    
    
    
        STDMETHOD(Greeting)(BSTR name, BSTR* message);
        STDMETHOD(Add)(LONG val1, LONG val2, LONG* result);
        STDMETHOD(Sub)(LONG val1, LONG val2, LONG* result);
    };
    
    OBJECT_ENTRY_AUTO(__uuidof(COMDemo), CCOMDemo)

    现在可以关注一下COMDemo.cpp了,在cpp文件中实现头文件中声明的方法:

    STDMETHODIMP CCOMDemo::Greeting(BSTR name, BSTR* message)
    {
        // TODO:  在此添加实现代码
        CComBSTR tmp("Welcome, ");
        tmp.Append(name);
        *message = tmp;
        return S_OK;
    }
    
    STDMETHODIMP CCOMDemo::Add(LONG val1, LONG val2, LONG* result)
    {
        *result = val1 + val1;
        Fire_Completed();
        return S_OK;
    }
    
    STDMETHODIMP CCOMDemo::Sub(LONG val1, LONG val2, LONG* result)
    {
        *result = val1 - val2;
        Fire_Completed();
        return S_OK;
    }

    现在就可以生成组件了。生成过程会在注册表中配置组件,需要管理员身份,所以请务必以管理员身份运行VS。

  • 相关阅读:
    【MySQL】MySQL Workbench 8.0 CE 界面汉化
    【SQLite】批处理脚本BAT读取SQLite数据
    UnityShader顶点着色器输入的语义
    Unity-Editor按钮和菜单显示
    unity使用文件流操作streamingassets下的文件
    DOTween Sequence的使用
    Luaframework中关于按钮点击事件监听时按钮名称不能重复的问题
    LUA中判断GameObject是否被Destory
    关于多线程并发同时使用lock时的疑问
    FairyGUI合并进Luaframework使用框架的LUA例子
  • 原文地址:https://www.cnblogs.com/yayaxxww/p/4286633.html
Copyright © 2011-2022 走看看