グローバルフックをするには、DLLにする必要がある。
また、イベントがあったことを知るために、FindWindowで送信先のウィンドウクラス名を指定してSendMessageしている。
マウスフックの時は、SetWindowsHookExに渡す引数はWH_MOUSEとなる。また、フックプロシージャのwParamにはイベントが入っている。
#pragma once #include <Windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ); HINSTANCE GetDllInstance();
HINSTANCE hDLLInstance = nullptr; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { hDLLInstance = hModule; return TRUE; } HINSTANCE GetDllInstance() { return hDLLInstance; }
フックをかけるときにインスタンスハンドルが必要になるので、DllMainの中で保存しておく。
DLL側にはプリプロセッサにDLL_EXPORT_DOをセットする。
#ifdef DLL_EXPORT_DO /* DLLを作る場合 */ #define __DLL_PORT extern "C" __declspec(dllexport) #define __DLL_PORT_CLS __declspec(dllexport) #else /* DLLを使う場合 */ #define __DLL_PORT extern "C" __declspec(dllimport) #define __DLL_PORT_CLS __declspec(dllimport) #endif
このファイルは次のMouseHook.hでincludeされるが、結果的にexe側でもincludeされることになるので、両方のプロジェクトから読める必要がある。
#pragma once #include <Windows.h> #include "../DLLDefs.h" //マウスがクリックされたら、本体のプログラムへこのメッセージを送信する constexpr UINT WM_HOOKED_MOUSEDOWN = WM_USER + 2; class __DLL_PORT_CLS CMouseHook { static HHOOK hHook; static LRESULT CALLBACK MouseProcedure(int p_nCode, WPARAM p_wParam, LPARAM p_lParam); public: BOOL Set(); BOOL Unset(); ~CMouseHook(); };
フック関数とフックハンドルはstaticにする。
#include "MouseHook.h" #include "dllmain.h" #include <tchar.h> #pragma warning(disable:4996) #pragma data_seg( ".CMouseHookHandle" ) HHOOK CMouseHook::hHook = nullptr; #pragma data_seg() BOOL CMouseHook::Set() {//フックをセットする関数 hHook = ::SetWindowsHookEx(WH_MOUSE //種類はマウスフック , (HOOKPROC)CMouseHook::MouseProcedure , GetDllInstance(), 0);//このDLLのインスタンスハンドルを指定 if (!hHook) return FALSE; return TRUE; } BOOL CMouseHook::Unset() {//フックを外す BOOL ret = FALSE; if (hHook) ret = ::UnhookWindowsHookEx(hHook); hHook = nullptr; return ret; } //フックの処理 LRESULT CALLBACK CMouseHook::MouseProcedure(int p_nCode, WPARAM p_wParam, LPARAM p_lParam) { if (p_nCode < 0) return ::CallNextHookEx(hHook, p_nCode, p_wParam, p_lParam); if (p_nCode == HC_ACTION) { MOUSEHOOKSTRUCT *pmh = (MOUSEHOOKSTRUCT *)p_lParam; if (pmh) { if (p_wParam == WM_LBUTTONDOWN || p_wParam == WM_NCLBUTTONDOWN) { //このNU_WND_CLASS_NAMEは、exe側で作成するウィンドウのウィンドウクラス名 PostMessage(FindWindow(_T("NU_WND_CLASS_NAME"), nullptr), WM_HOOKED_MOUSEDOWN, p_wParam, p_lParam); //exe側にWM_HOOKED_MOUSEDOWNを送る } } } return ::CallNextHookEx(hHook, p_nCode, p_wParam, p_lParam);; } CMouseHook::~CMouseHook() { Unset(); }
SECTIONS .CMouseHookHandle READ WRITE SHARED
#pragma comment(lib, "MouseHook.lib") #include "../MouseHook/MouseHook.h" #include<windows.h> #include <tchar.h> //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_DESTROY: DestroyWindow(hwnd); PostQuitMessage(0); return 0; case WM_HOOKED_MOUSEDOWN: OutputDebugString(_T("どこかの窓でマウスがクリックされました\n")); return 0; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS winc; //ウィンドウクラスの登録 winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("NU_WND_CLASS_NAME"); if (!RegisterClass(&winc)) return 0; //フックをかける CMouseHook hm; hm.Set(); //ウィンドウ作成 hwnd = CreateWindow( TEXT("NU_WND_CLASS_NAME"), TEXT("test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 0; while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); //フックを外す hm.Unset(); return msg.wParam; }