【问题标题】:Handling COM events in C++ (ATL, MFC or pure C++) for Java interop在 C++(ATL、MFC 或纯 C++)中处理 Java 互操作的 COM 事件
【发布时间】:2011-08-05 10:22:26
【问题描述】:

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

#import "ComponentName.dll"

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

但是,我不知道如何让事件发挥作用。我看到有一个 IComponentNameEventsPtr 补充了主要的“智能指针”类,但我不知道该怎么做才能让它工作

我已经尝试了以下所有方法来让事件正常工作:

  • Pure C++——我不知道该怎么做。我尝试创建一个从 IComponentNameEvents 类继承的新类,为所有抽象函数创建存根,并覆盖这些函数,但这些函数未标记为虚拟函数,因此不起作用。
  • MFC — 我无法正确调用 AfxOleInit。谷歌搜索告诉我,从 DLL 调用时调用失败,因为它假定 OLE 已经初始化。我不太确定如何解决这个问题。每次我尝试创建 COM 组件的实例时,我的库都会崩溃(我假设是因为 COM 未正确初始化)
  • ATL — 我不知道如何在 ATL 中处理事件。我可以创建类(通过“简单 ATL”向导,然后是“实现接口”向导),但不知道如何使用它。我阅读了Using IDispEventImpl on MSDN,但无法弄清楚如何使用该howto 生成的类。我是否也需要通过 ATL 使用 COM 对象(或者我可以使用#import 自动生成的类)?如何“附加”事件侦听器类?
  • 我阅读了Event Handling in COM,它使用了 event_receiver 属性(新的 Visual C++ 统一事件模型的一部分)。最初我不知道如何将它与通过#import 语句创建的 COM 组件的使用结合起来。我终于解决了(并且在页面上提到了!)我需要在#import 语句上使用“embedded_idl”标志,但这破坏了其他事情(我在.tlh 文件)

有人知道怎么做吗?最简单的方法是什么?我的背景是 C# 和 PHP,所以我没有太多在 C++ 中使用 COM 的经验。

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

【问题讨论】:

    标签: c++ visual-studio com


    【解决方案1】:

    我实际上使用统一事件模型自己完成了这项工作。我在让它工作的经验中的一些注意事项:

    然后添加一个

    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() 之前一定要解开所有事件,否则会出错。

    【讨论】:

      【解决方案2】:

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

       [source] interface IOutGoing;
      

      实现后,在事件源对象上使用Advise 注册它(使用Unadvise 取消注册)

      这是一个显示典型用法的 sn-p,假设您采用 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);
      

      【讨论】:

      • 我实际上使用统一事件模型自己完成了这项工作。有空我会在这里写一个答案:)
      • 我正在尝试自己完成这项工作,但我不确定 IOutGoing 应该是什么,我没有 COM 库的所有权,并且它不包含出现的类型就像 IOutGoing 一样。如何创建我的 CSink 类?
      猜你喜欢
      • 2010-12-16
      • 2011-05-12
      • 1970-01-01
      • 2012-06-11
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      相关资源
      最近更新 更多