OBJREFモニカーなど、過去複数の記事でIDisptachを自前実装しました。が、自前実装しないで済むならそれに越したことはないと思っています。そこで、今回はCreateDispTypeInfo関数とCreateStdDispatch関数を使うプログラムを作ってみることにしました。

というわけで、上記過去記事で作ったHogeクラスを基に書き換えます。今回は単独で動作を見られるよう、VBScriptのプログラムを起動する処理を廃止しています。

#define _ATL_NO_AUTOMATIC_NAMESPACE
 
#include <iostream>
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlutil.h>
#include <boost/implicit_cast.hpp>
 
class Module : public ATL::CAtlExeModuleT<Module> {};
Module module;
 
interface DECLSPEC_UUID("6ae160da-9e37-4f46-83bd-bf166a82f871") IFunc :
  IUnknown
{
  virtual void STDMETHODCALLTYPE Func() = 0;
};
 
class ATL_NO_VTABLE Hoge
  : public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
  , public ATL::CComCoClass<Hoge>
  , public IFunc
{
public:
  BEGIN_COM_MAP(Hoge)
    COM_INTERFACE_ENTRY(IFunc)
    COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(IDispatch), m_pdisp.p)
  END_COM_MAP()
 
  HRESULT FinalConstruct()
  {
    auto hrTI = InitializeTypeInfo();
    ATLENSURE_RETURN_HR(SUCCEEDED(hrTI), hrTI);
    // 集成に対応させるなら、DECLARE_GET_CONTROLLING_UNKNOWNを使用した上で、
    // GetUnknown()をGetControllingUnknown()に変更する。
    return CreateStdDispatch(
      GetUnknown(), boost::implicit_cast<IFunc*>(this),
      s_typeInfo, &m_pdisp);
  }
 
  void STDMETHODCALLTYPE Func() override
  {
    std::cout << "Hoge::Invoke" << std::endl;
  }
 
private:
  ATL::CComPtr<IUnknown> m_pdisp;
 
  static HRESULT InitializeTypeInfo()
  {
    if (s_typeInfo != nullptr)
    {
      return S_OK;
    }
    static METHODDATA md[]
    {
      {
        L"Func",
        nullptr,
        DISPID_VALUE,
        3, // 0~2はIUnknownの各メソッドのため、Funcのインデックスは3となる。
        CC_STDCALL,
        0,
        DISPATCH_METHOD,
        VT_EMPTY
      },
    };
    static INTERFACEDATA id
    {
      md, ARRAYSIZE(md),
    };
    return CreateDispTypeInfo(&id, LOCALE_SYSTEM_DEFAULT, &s_typeInfo);
  }
 
  static ATL::CComPtr<ITypeInfo> s_typeInfo;
};
 
ATL::CComPtr<ITypeInfo> Hoge::s_typeInfo;
 
int main()
{
  try
  {
    ATLENSURE_SUCCEEDED(CoInitializeEx(
      nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE));
 
    ATL::CComPtr<IDispatch> hoge;
    ATLENSURE_SUCCEEDED(Hoge::CreateInstance(&hoge));
 
    hoge.Invoke0(static_cast<DISPID>(DISPID_VALUE));
  }
  catch (const ATL::CAtlException& e)
  {
    std::clog << std::hex << std::showbase;
    std::clog << e.m_hr << ' ';
    std::clog << ATL::AtlGetErrorDescription(e) << std::endl;
  }
 
  CoUninitialize();
}

INTERFACEDATAとMETHODDATAの組み立てが面倒です。なお、仮引数を持たせるなら、PARAMDATAも必要です。C++自体のメタプログラミング能力が向上して、全自動で組み立てられるようになれば良いのですが。

以下、MSDNライブラリの関連する項目へのリンクです。

スポンサード リンク

この記事のカテゴリ

  • ⇒ CreateDispTypeInfoとCreateStdDispatchを使ってみる
  • ⇒ CreateDispTypeInfoとCreateStdDispatchを使ってみる