C++/CLI でふ
コード
/*---------------------------------------------* * ヘッダー * 重要なのは WindowActiveHooker::INSTANCE; * WindowActiveHooker::GetInstance() で参照してる。 *---------------------------------------------*/ ref class OfficeWindow : System::Windows::Forms::IWin32Window { public: OfficeWindow(System::IntPtr hWnd) : m_hWnd(hWnd){} property IntPtr Handle { virtual IntPtr get () { return m_hWnd; } } private: System::IntPtr m_hWnd; }; public ref class WindowActiveHooker { public: delegate void FNWindowActiveCallback(System::Windows::Forms::IWin32Window^ wnd); static WindowActiveHooker^ GetInstance(); public: bool Start(); bool Shutdown(); event FNWindowActiveCallback^ activeEvent; internal: void InvokeActiveEvent(OfficeWindow^ mWnd); private: WindowActiveHooker(); static void DummyFunction(System::Windows::Forms::IWin32Window^ wnd){} private: static WindowActiveHooker^ INSTANCE = nullptr; }; /*------------------------------------------* * cpp *------------------------------------------*/ #include "stdafx.h" #include "header.h" #pragma managed(push, off) LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam); HHOOK n_hHook = NULL; #pragma managed(pop) /*------------------------------------------* * static *------------------------------------------*/ WindowActiveHooker^ WindowActiveHooker::GetInstance() { if(INSTANCE == nullptr) INSTANCE = gcnew WindowActiveHooker(); return INSTANCE; } /*------------------------------------------* * instance *------------------------------------------*/ WindowActiveHooker::WindowActiveHooker() { ::OutputDebugString(TEXT("*** kashira?\n")); // activeEvent += gcnew FNWindowActiveCallback(DummyFunction); } bool WindowActiveHooker::Start() { if(n_hHook != NULL) return false; n_hHook = ::SetWindowsHookEx(WH_CBT, &CBTProc, n_hInstance, ::GetCurrentThreadId()); return n_hHook != NULL; } bool WindowActiveHooker::Shutdown() { if(n_hHook == NULL) return false; if(::UnhookWindowsHookEx(n_hHook)) n_hHook = NULL; return n_hHook == NULL; } void WindowActiveHooker::InvokeActiveEvent(OfficeWindow^ mWnd) { activeEvent(mWnd); } // global funtion void ReciveActiveMessageProxy(HWND hWnd) { System::IntPtr h(hWnd); OfficeWindow mWnd(h); WindowActiveHooker::GetInstance()->InvokeActiveEvent(%mWnd); } #pragma managed(off) /*---------------------------------------------------------------------* * * dll main * *---------------------------------------------------------------------*/ LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode == HCBT_ACTIVATE) { const CBTACTIVATESTRUCT* activeStruct = (CBTACTIVATESTRUCT*)lParam; HWND hWnd = (HWND)wParam; ReciveActiveMessageProxy(hWnd); } return ::CallNextHookEx(n_hHook, nCode, wParam, lParam); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if(fdwReason == DLL_PROCESS_ATTACH) { n_hInstance = hinstDLL; } return true; }
使いはじめ
// C# void init() { // 使い始め // ウィンドウが作成された後に実行される WindowActiveHooker.GetInstance().Start(); WindowActiveHooker.GetInstance().activeEvent += new WindowActiveHooker.FNWindowActiveCallback(INSTANCE_activeEvent); } void INSTANCE_activeEvent(IWin32Window wnd) { // ごにょごにょ実行 }
これで、C++/CLI 側で event が invoke されて、C# 側の INSTANCE_activeEvent() がコールバックされるよねー! …と思ったら全然されない。
色々確認すると
→ WindowActiveHooker::INSTANCE が2つある…?
なーぜーやー… Singleton の意味が無いじゃないですか…
ちなみに、このクラスが定義されているライブラリは2つのプロジェクトから利用されています。 C# lib プロジェクトから static 変数を見るケースと、Office AddInプロジェクトから見るケースと。 …コレがイケナイ…と思ったけど、全然関係無いや(たぶん)
C# AddInプロジェクト ――┐(2) | ↓ |(1) C++/CLI プロジェクト ↓ ↑ C# libプロジェクト ――――┘(1)
追記
C# Window アプリケーションからこれらライブラリを利用してみたところ、期待度どおりに Callback してくれました。 INSTANCE は複数出来てない模様。
となると、Office の何かが何かしてる…のかなぁ…あああどないせいっちゅーねん… orz