引き続き、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実装方法の話でした。
スポンサード リンク |