本記事は、COM Advent Calendar 2014 – Qiitaの25日目の記事です。今日で最後です。
COMには、CoInitializeやCoUninitializeが呼び出されたことの通知を受け取る手段が用意されています。IInitializeSpyおよびCoRegisterInitializeSpyそしてCoRevokeInitializeSpyです。
#include <iostream> #include <windows.h> #include <shlwapi.h> #include <roapi.h> #include <comdef.h> class InitializeSpy : public IInitializeSpy { public: InitializeSpy() = default; InitializeSpy(const InitializeSpy&) = delete; InitializeSpy& operator=(const InitializeSpy&) = delete; ~InitializeSpy() = default; IFACEMETHOD(QueryInterface)( _In_ REFIID riid, _COM_Outptr_ void** ppv) override { static const QITAB qit[] = { {&__uuidof(IInitializeSpy), OFFSETOFCLASS(IInitializeSpy, InitializeSpy)}, {}, }; return QISearch(this, qit, riid, ppv); } IFACEMETHOD_(ULONG, AddRef)() override { return 0; } IFACEMETHOD_(ULONG, Release)() override { return 0; } IFACEMETHOD(PreInitialize)( _In_ DWORD dwCoInit, _In_ DWORD dwCurThreadAptRefs) override { std::cout << "PreInitialize: " << std::dec << dwCurThreadAptRefs << ", dwCoInit: " << std::hex << dwCoInit << std::endl; return S_OK; } IFACEMETHOD(PostInitialize)( _In_ HRESULT hrCoInit, _In_ DWORD dwCoInit, _In_ DWORD dwNewThreadAptRefs) override { std::cout << "PostInitialize: " << std::dec << dwNewThreadAptRefs << ", dwCoInit: " << dwCoInit << ", hrCoInit: " << std::hex << hrCoInit << std::endl; return S_OK; } IFACEMETHOD(PreUninitialize)( _In_ DWORD dwCurThreadAptRefs) override { std::cout << "PreUninitialize: " << std::dec << dwCurThreadAptRefs << std::endl; return S_OK; } IFACEMETHOD(PostUninitialize)( _In_ DWORD dwNewThreadAptRefs) override { std::cout << "PostUninitialize: " << std::dec << dwNewThreadAptRefs << std::endl; return S_OK; } }; int main() { try { InitializeSpy spy; ULARGE_INTEGER cookie; _com_util::CheckError(CoRegisterInitializeSpy(&spy, &cookie)); std::cout << std::showbase; std::cout << "---- CoInitialize" << std::endl; _com_util::CheckError(CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)); _com_util::CheckError(CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)); CoUninitialize(); CoUninitialize(); std::cout << "---- CoInitialize (failed)" << std::endl; _com_util::CheckError(CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)); _com_util::CheckError(CoInitializeEx( nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)); CoUninitialize(); std::cout << "---- OleInitialize" << std::endl; OleInitialize(nullptr); OleUninitialize(); std::cout << "---- RoInitialize (MTA)" << std::endl; RoInitialize(RO_INIT_MULTITHREADED); RoUninitialize(); std::cout << "---- RoInitialize (STA)" << std::endl; RoInitialize(RO_INIT_SINGLETHREADED); RoUninitialize(); _com_util::CheckError(CoRevokeInitializeSpy(cookie)); } catch(const _com_error& e) { std::cout << std::hex << std::showbase << e.Error() << std::endl; } } |
実行結果は以下のようになりました。Windows 8.1です。
---- CoInitialize PreInitialize: 0, dwCoInit: 0x6 PostInitialize: 1, dwCoInit: 6, hrCoInit: 0 PreInitialize: 1, dwCoInit: 0x6 PostInitialize: 2, dwCoInit: 6, hrCoInit: 0x1 PreUninitialize: 2 PostUninitialize: 1 PreUninitialize: 1 PostUninitialize: 0 ---- CoInitialize (failed) PreInitialize: 0, dwCoInit: 0x6 PostInitialize: 1, dwCoInit: 6, hrCoInit: 0 PreInitialize: 1, dwCoInit: 0x4 PostInitialize: 1, dwCoInit: 4, hrCoInit: 0x80010106 PreUninitialize: 1 PostUninitialize: 0 ---- OleInitialize PreInitialize: 0, dwCoInit: 0x2 PostInitialize: 1, dwCoInit: 2, hrCoInit: 0 PreUninitialize: 1 PostUninitialize: 0 ---- RoInitialize (MTA) PreInitialize: 0, dwCoInit: 0 PostInitialize: 1, dwCoInit: 0, hrCoInit: 0 PreUninitialize: 1 PostUninitialize: 0 ---- RoInitialize (STA) PreInitialize: 0, dwCoInit: 0x6 PostInitialize: 1, dwCoInit: 6, hrCoInit: 0 PreUninitialize: 1 PostUninitialize: 0
変更前または変更後の参照カウントや、初期化関数に渡されたCOINIT値、初期化関数の結果 (HRESULT)などが渡されます。
dwCoInitの0x2はCOINIT_APARTMENTTHREADED、0x6はCOINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDEになります。RoInitialize(RO_INIT_SINGLETHREADED)がCOINIT_DISABLE_OLE1DDEを組み合わせて指定していることが分かりますね。
また、hrCoInitの0x80010106はRPC_E_CHANGED_MODEで、MSDNライブラリの記載どおりの挙動です。
なお、CoRegisterInitializeSpyはMSDNライブラリに記載があるとおり、呼び出したスレッドのみに有効です。
なんとか25日すべてが終わりました。候補に挙げたものの、結局取り上げなかったものがまだまだあるのが心残りですが、いったんこれでおしまいです。26日目はありません。もし12月26日にブログを書いたとしても、おそらくCOMに関係ない話にすると思います。
ここまですべて読んでいただいた皆さま、お疲れ様でした。また、「読んでいます」と声を掛けてくださった方、大変励みになりました。これにてCOM Advent Calendar 2014終わります。
スポンサード リンク |
この記事のカテゴリ
- COM ⇒ CoInitializeとCoUninitializeが呼び出されたことを知る