引き続き、C++でIDispatchを実装する話です。

ATLにおいて、簡易的なIDispatchの実装クラスとしてATL::IDispEventSimpleImplがあります。本来の目的は、IConnectionPointなどによるイベント処理の実装です。イベントの通知に使われるインタフェース(アウトゴーイングインタフェース)がIDispatchベース (dispinterface)であることがよくあり、その実装のためのものです。

しかし、今回はただIDispatch (dispinterface)実装のためだけに使います。今回はコードを2つ掲載します。

まず、コード例1つ目です。ATL::CComObjectRootExを使わない場合です。参照カウントが不要ならATL::CComObjectRootExすら不要なのです。ATL::IDispEventSimpleImpl内部では、常に1を返すAddRefとReleaseが定義されているためです。

#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <boost/implicit_cast.hpp>
 
constexpr UINT ID_Hoge = 0;
 
class Hoge :
  public ATL::IDispEventSimpleImpl<ID_Hoge, Hoge, &IID_NULL>
{
public:
  static auto GetFuncInfo()
  {
    static ATL::_ATL_FUNC_INFO FuncInfo = { CC_STDCALL, VT_EMPTY, 0, {} };
    return &FuncInfo;
  }
 
  BEGIN_SINK_MAP(Hoge)
    SINK_ENTRY_INFO(ID_Hoge, IID_NULL, DISPID_VALUE, &Hoge::Func, GetFuncInfo())
  END_SINK_MAP()
 
  void STDMETHODCALLTYPE Func()
  {
    std::cout << "Hoge::Invoke" << std::endl;
  }
 
  IDispatch* GetDispatch()
  {
    return reinterpret_cast<IDispatch*>(
      boost::implicit_cast<IDispEventSimpleImpl*>(this));
  }
};
 
int main()
{
  if (FAILED(OleInitialize(nullptr)))
  {
    std::quick_exit(-1);
  }
 
  Hoge obj;
  ATL::CComPtr<IDispatch> hoge = obj.GetDispatch();
  auto hr = hoge.Invoke0(static_cast<DISPID>(DISPID_VALUE));
  if (FAILED(hr))
  {
    std::clog << "Failed: " << std::hex << hr << std::endl;
  }
  std::quick_exit(0);
}

2つ目は、ATL::CComObjectRootExと併用する例です。

#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
 
constexpr UINT ID_Hoge = 0;
 
class Hoge :
  public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>,
  public ATL::IDispEventSimpleImpl<ID_Hoge, Hoge, &IID_NULL>
{
public:
  static auto GetFuncInfo()
  {
    static ATL::_ATL_FUNC_INFO FuncInfo = { CC_STDCALL, VT_EMPTY, 0, {} };
    return &FuncInfo;
  }
 
  BEGIN_COM_MAP(Hoge)
    COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispEventSimpleImpl)
  END_COM_MAP()
 
  BEGIN_SINK_MAP(Hoge)
    SINK_ENTRY_INFO(ID_Hoge, IID_NULL, DISPID_VALUE, &Hoge::Func, GetFuncInfo())
  END_SINK_MAP()
 
  void STDMETHODCALLTYPE Func()
  {
    std::cout << "Hoge::Invoke" << std::endl;
  }
};
 
int main()
{
  if (FAILED(OleInitialize(nullptr)))
  {
    std::quick_exit(-1);
  }
 
  ATL::CComObjectStackEx<Hoge> obj;
  ATL::CComQIPtr<IDispatch> hoge = obj.GetUnknown();
  auto hr = hoge.Invoke0(static_cast<DISPID>(DISPID_VALUE));
  if (FAILED(hr))
  {
    std::clog << "Failed: " << std::hex << hr << std::endl;
  }
  std::quick_exit(0);
}

いずれの例でも、BEGIN_SINK_MAP~END_SINK_MAPで、DISPIDと受け付ける関数の対応を記述しています。

ATL::IDispEventSimpleImplの目的外利用という、邪道な感じのIDispatch実装方法の話でした。

スポンサード リンク

この記事のカテゴリ

  • ⇒ ATL::IDispEventSimpleImplでIDispatchを実装する
  • ⇒ ATL::IDispEventSimpleImplでIDispatchを実装する