用于Java互操作的C ++(ATL,MFC或纯C ++)处理COM事件

我目前正在尝试构建一个与COM组件接口的C ++库(DLL文件),以使其可用于Java。 我的想法是,我将构建一个非常小的C ++ DLL,其中包含一个围绕COM组件“包装”的类,然后使用SWIG将其导出。 通过使用#import语句,我得到了很多:

#import "ComponentName.dll"

调用CoInitialize()并创建组件的实例(通过由Visual Studio生成的IComponentNamePtr类)。 这适用于所有正常的COM方法调用,这很好。

但是,我无法弄清楚如何让事件发挥作用。 我看到有一个IComponentNameEventsPtr补充了主要的“智能指针”类,但我无法弄清楚如何才能使它工作

我已经尝试了以下所有事件以使事件有效:

  • 纯C ++ - 我无法解决如何做到这一点。 我尝试创建一个从IComponentNameEvents类继承的新类,为所有抽象函数创建存根,并覆盖函数,但函数未标记为虚拟,因此不起作用。
  • MFC - 我无法正确地调用AfxOleInit。 谷歌搜索告诉我,从DLL调用时调用失败,因为它假定OLE已经被初始化。 我不太清楚如何解决这个问题。 每次尝试创建COM组件的实例时,我的库都会崩溃(我假定COM未正确初始化)
  • ATL - 我无法弄清楚如何在ATL中完成这些事件。 我可以创建类(通过“简单ATL”向导,然后是“实现接口”向导),但无法解决如何使用它。 我在MSDN上阅读使用IDispEventImpl,但无法解决如何使用该howto生成的类。 我是否也需要通过ATL使用COM对象(或者我可以使用#import自动生成的类)? 我如何“附加”事件监听器类?
  • 我使用event_receiver属性(新的Visual C ++统一事件模型的一部分)阅读COM中的事件处理。 最初我无法弄清楚如何将它与使用通过#import语句创建的COM组件相结合。 我终于搞定了(并且在页面上提到了它),我需要在#import语句中使用“embedded_idl”标志,但是这打破了其他一些东西(我有一堆“期望类型规范接近”错误.tlh文件)
  • 有谁知道如何做到这一点? 最简单的方法是什么? 我的背景是在C#和PHP中,所以我没有太多关于在C ++中使用COM的经验。

    tldr:在C ++ DLL中使用COM事件的最简单方法是什么?


    在代码中实现源接口(使用任何机制,包括使用midl编译器生成纯C代码)。 在您的外部类型库(您正在使用的那个)中查找如下所示的界面:

     [source] interface IOutGoing;
    

    一旦你实现了它,使用Advise在注册事件的对象上进行注册(使用Unadvise注销它)

    下面是一个典型用法的片段,假设你使用MIDL方式(使用ATL / MFC你必须编写更少的代码,但知道更多的宏/模板)

    class CSink : public IOutGoing
    {
    public:
        // IUnknown
        ULONG __stdcall AddRef();
        ULONG __stdcall Release();
        HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
    
        // IOutGoing
        HRESULT __stdcall GotMessage(int Message);
    
        CSink() : m_cRef(0) { }
        ~CSink() { }
    
    private:
        long m_cRef;
    };
    
    
    IUnknown* pUnknown;
    CoCreateInstance(CLSID_XXXXXXXXX, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);
    
    IConnectionPointContainer* pConnectionPointContainer;
    hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
    
    hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint);
    
    // Instantiate the sink object.
    CSink* mySink = new CSink;
    
    // Give the connectable object a pointer to the sink.
    DWORD dwCookie;
    pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);
    

    我实际上使用统一事件模型自己工作。 一些笔记从我的经验得到它的工作:

  • 您需要初始化ATL,否则在连接事件时会发生空指针错误。 如果你不想在你的项目中使用ATL(就像我没有 - 我的项目是普通的C ++),在dllmain.cpp中这样的东西可以正常工作(用虚拟模块初始化ATL):

    class CDummyModule : public CAtlDllModuleT<CDummyModule> {};
    CDummyModule _Module;
    
  • 您需要将“embedded_idl”添加到#import行的末尾。

    #import "ComponentName.dll" embedded_idl
    
  • 如果组件中嵌入了任何结构体,由于Visual Studio中的错误,您可能会遇到一些MIDL2025错误(“预计类型规范接近”)(请参阅https://connect.microsoft.com/VisualStudio/feedback/details/ 333473 / midl2025-migrating-an-attributed-com-project-to-vs-2008-pro-with-exported-structures和http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/ 03b78133-5eac-4754-b9af-fc864a9389a3)。 解决方案是添加:

    [importidl("vsbugfix.idl")];
    
  • 然后添加一个

    typedef struct StructName StructName;
    

    对于每个引发错误的结构

  • 完成之后,您应该能够初始化COM并创建对象的实例。 丑陋的示例代码:

    IComponentName blah;
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        MessageBox(NULL, "Failed to initialize COM", "Hi!", 0);
        throw "Failed to initialize COM";
    }
    
    try
    {
        hr = blah.CreateInstance("Something.Something");
        if (FAILED(hr))
        {
            CoUninitialize();
            MessageBox(NULL, "Failed to initialize the COM library!!", "Hi!", 0);
            throw "Failed to initialize the COM library";
        }
    }
    catch (...)
    {
        MessageBox(NULL, "Exception occured when initialising library!", "Error", 0);
        CoUninitialize();
        throw "Exception occured when initialising library!";
    }
    
  • 一旦拥有了COM对象,就可以根据MSDN的“COM中的事件处理”文章连接事件:

    __hook(&IComponentNameEvents::OnWhatever, blah, &EventHandlerClass::OnWhatever);
    

    在调用CoUninitialize()之前,一定要解除所有事件,否则会出错。

    链接地址: http://www.djcxy.com/p/81309.html

    上一篇: Handling COM events in C++ (ATL, MFC or pure C++) for Java interop

    下一篇: smartdevice C# dll in VC++