質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

6119閲覧

WM_POINTER*系のメッセージをグローバルフックしたい

tekka

総合スコア514

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/08/25 11:59

編集2018/08/26 09:18

前提・実現したいこと

Windows10(64bit)の各種ブラウザ上でスタイラスペンの挙動(とくにWM_POINTERENTER、WM_POINTERLEAVE)を取得したい。

発生している問題・エラーメッセージ

C++で作成したDLLにより、各種ブラウザのウィンドウにグローバルフックを設定し、WM_POINTER*のメッセージを取得しようとしましたが、出来ませんでした。

該当のソースコード

DLL

C++

1 2#include "stdafx.h" 3 4 5#pragma data_seg(".shareddata") 6HWND g_hWnd = 0; 7HHOOK hHook = 0; 8#pragma data_seg() 9 10HINSTANCE hInst; 11 12EXPORT_API_ int SetHook(HWND hWnd, DWORD dwThreadId) 13{ 14 15 hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, hInst, dwThreadId); 16 if (hHook == NULL) { 17 return -1; 18 } 19 else { 20 g_hWnd = hWnd; 21 } 22 return 0; 23} 24 25EXPORT_API_ int ResetHook() 26{ 27 if (UnhookWindowsHookEx(hHook) != 0) { 28 UnregisterPointerInputTarget(g_hWnd, PT_TOUCH); 29 } 30 return 0; 31} 32 33EXPORT_API_ LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp) 34{ 35 CWPSTRUCT *pcwp; 36 37 if (nCode < 0) return CallNextHookEx(0, nCode, wp, lp); 38 39 if(nCode == HC_ACTION ) { 40 41 const MSG& msg = *(MSG*)lp; 42 43 if (msg.message == WM_POINTERENTER) { 44 SendMessage(g_hWnd, WM_INRANGE, 0, 0); 45 } 46 else if (msg.message == WM_POINTERLEAVE) { 47 SendMessage(g_hWnd, WM_OUTRANGE, 0, 0); 48 } 49 } 50 51 return CallNextHookEx(hHook, nCode, wp, lp); 52} 53 54// エントリポイント 55BOOL APIENTRY DllMain(HMODULE hModule, 56 DWORD ul_reason_for_call, 57 LPVOID lpReserved 58) 59{ 60 switch (ul_reason_for_call) 61 { 62 case DLL_PROCESS_ATTACH: 63 // アタッチ 64 hInst = hModule; 65 //bSetHook = FALSE; 66 break; 67 case DLL_PROCESS_DETACH: 68 // デタッチ 69 break; 70 } 71 return TRUE; 72}

DLL呼び出し

C++

1// hook_exe.cpp: アプリケーションのエントリ ポイントを定義します。 2// 3 4#include "stdafx.h" 5#include "hook_exe.h" 6 7#define MAX_LOADSTRING 100 8 9// グローバル変数: 10HINSTANCE hInst; // 現在のインターフェイス 11WCHAR szTitle[MAX_LOADSTRING]; // タイトル バーのテキスト 12WCHAR szWindowClass[MAX_LOADSTRING]; // メイン ウィンドウ クラス名 13 14HMODULE hDll; 15 16// このコード モジュールに含まれる関数の宣言を転送します: 17ATOM MyRegisterClass(HINSTANCE hInstance); 18BOOL InitInstance(HINSTANCE, int); 19LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 20INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 21int _is_hooked = 0; 22 23//共有セグメント 24#pragma data_seg(".shareddata") 25HHOOK hKeyHook = 0; 26HWND g_hWnd = 0; //キーコードの送り先のウインドウハンドル 27#pragma data_seg() 28 29int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 30 _In_opt_ HINSTANCE hPrevInstance, 31 _In_ LPWSTR lpCmdLine, 32 _In_ int nCmdShow) 33{ 34 UNREFERENCED_PARAMETER(hPrevInstance); 35 UNREFERENCED_PARAMETER(lpCmdLine); 36 37 // TODO: ここにコードを挿入してください。 38 39 // グローバル文字列を初期化しています。 40 LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 41 LoadStringW(hInstance, IDC_HOOKEXE, szWindowClass, MAX_LOADSTRING); 42 MyRegisterClass(hInstance); 43 44 // アプリケーションの初期化を実行します: 45 if (!InitInstance (hInstance, nCmdShow)) 46 { 47 return FALSE; 48 } 49 50 HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HOOKEXE)); 51 52 MSG msg; 53 54 // メイン メッセージ ループ: 55 while (GetMessage(&msg, nullptr, 0, 0)) 56 { 57 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 58 { 59 TranslateMessage(&msg); 60 DispatchMessage(&msg); 61 } 62 } 63 64 return (int) msg.wParam; 65} 66 67 68ATOM MyRegisterClass(HINSTANCE hInstance) 69{ 70 WNDCLASSEXW wcex; 71 72 wcex.cbSize = sizeof(WNDCLASSEX); 73 74 wcex.style = CS_HREDRAW | CS_VREDRAW; 75 wcex.lpfnWndProc = WndProc; 76 wcex.cbClsExtra = 0; 77 wcex.cbWndExtra = 0; 78 wcex.hInstance = hInstance; 79 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HOOKEXE)); 80 wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); 81 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 82 wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_HOOKEXE); 83 wcex.lpszClassName = szWindowClass; 84 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 85 86 return RegisterClassExW(&wcex); 87} 88 89BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 90{ 91 hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 92 93 HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 94 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); 95 96 if (!hWnd) 97 { 98 return FALSE; 99 } 100 101 RegisterTouchWindow(hWnd, 0); 102 103 ShowWindow(hWnd, nCmdShow); 104 UpdateWindow(hWnd); 105 106 return TRUE; 107} 108 109LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 110{ 111 switch (message) 112 { 113 case WM_TEST: 114 115 _is_hooked = 2; 116 InvalidateRect(hWnd, NULL, TRUE); 117 118 break; 119 case WM_INRANGE: 120 121 _is_hooked = 3; 122 InvalidateRect(hWnd, NULL, TRUE); 123 124 break; 125 case WM_OUTRANGE: 126 127 _is_hooked = 4; 128 InvalidateRect(hWnd, NULL, TRUE); 129 130 break; 131 case WM_HOOKSTART: 132 133 hook_start(hWnd); 134 135 _is_hooked = 1; 136 InvalidateRect(hWnd, NULL, TRUE); 137 138 break; 139 case WM_HOOKEND: 140 141 //TODO:フック終了 142 143 hook_end(); 144 145 _is_hooked = 0; 146 InvalidateRect(hWnd, NULL, TRUE); 147 148 break; 149 case WM_COMMAND: 150 { 151 152 int wmId = LOWORD(wParam); 153 // 選択されたメニューの解析: 154 switch (wmId) 155 { 156 case IDM_TEST: 157 158 //テスト用フック開始メニューを受け取る 159 160 SendMessage(hWnd, WM_HOOKSTART, 0, 0); 161 162 break; 163 case IDM_ABOUT: 164 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 165 break; 166 case IDM_EXIT: 167 DestroyWindow(hWnd); 168 break; 169 default: 170 return DefWindowProc(hWnd, message, wParam, lParam); 171 } 172 } 173 break; 174 case WM_CREATE: 175 176 //DLL読み込み 177 hDll = LoadLibrary(_T("hook.dll")); 178 179 InvalidateRect(hWnd, NULL, TRUE); 180 break; 181 case WM_DESTROY: 182 183 //DLL解放 184 185 hook_end(); 186 187 FreeLibrary(hDll); 188 189 PostQuitMessage(0); 190 break; 191 default: 192 return DefWindowProc(hWnd, message, wParam, lParam); 193 } 194 return 0; 195} 196 197// バージョン情報ボックスのメッセージ ハンドラーです。 198INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 199{ 200 UNREFERENCED_PARAMETER(lParam); 201 switch (message) 202 { 203 case WM_INITDIALOG: 204 return (INT_PTR)TRUE; 205 206 case WM_COMMAND: 207 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 208 { 209 EndDialog(hDlg, LOWORD(wParam)); 210 return (INT_PTR)TRUE; 211 } 212 break; 213 } 214 return (INT_PTR)FALSE; 215} 216 217std::vector<int> hook_start(HWND hWnd) { 218 219 int ret = 0; 220 std::vector<int> ret_ary; 221 222 FUNC_SetHook lpFunc = (FUNC_SetHook)GetProcAddress(hDll, "SetHook"); 223 224 DWORD process_id_ary[1000] = {}; 225 226 FindProcessId("firefox.exe", process_id_ary); 227 228 for (int ii = 0; ii < 1000; ii++) { 229 230 DWORD process_id = process_id_ary[ii]; 231 232 if (process_id == NULL) { 233 break; 234 } 235 236 HWND hwnd_ary[1000] = {}; 237 238 GetWindowHandle(process_id, hwnd_ary); 239 240 for (int jj = 0; jj < 1000; jj++) { 241 242 HWND hwnd = hwnd_ary[jj]; 243 244 if (hwnd == NULL) { 245 break; 246 } 247 248 DWORD dwPid = 0; 249 DWORD thread_id = GetWindowThreadProcessId(hwnd, &dwPid); 250 251 ret = lpFunc(hWnd, thread_id); 252 ret_ary.push_back(ret); 253 } 254 } 255 return ret_ary; 256} 257 258int hook_end() { 259 260 //TODO:unhook 261 262 FUNC_ResetHook lpFunc = (FUNC_ResetHook)GetProcAddress(hDll, "ResetHook"); 263 264 return 0; 265} 266 267void FindProcessId(const char *processname, DWORD * process_id_ary) 268{ 269 HANDLE hProcessSnap; 270 PROCESSENTRY32 pe32; 271 //DWORD result_ary[1000]; 272 int idx = 0; 273 274 // Take a snapshot of all processes in the system. 275 hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 276 if (INVALID_HANDLE_VALUE == hProcessSnap) { 277 //return(FALSE); 278 return; 279 } 280 281 pe32.dwSize = sizeof(PROCESSENTRY32); // <----- IMPORTANT 282 283 // Retrieve information about the first process, 284 // and exit if unsuccessful 285 if (!Process32First(hProcessSnap, &pe32)) 286 { 287 CloseHandle(hProcessSnap); // clean the snapshot object 288 return; 289 } 290 291 do 292 { 293 if (0 == strcmp(processname, _bstr_t (pe32.szExeFile))) 294 { 295 process_id_ary[idx] = pe32.th32ProcessID; 296 idx++; 297 } 298 } while (Process32Next(hProcessSnap, &pe32)); 299 300 process_id_ary[idx] = NULL; 301 302 CloseHandle(hProcessSnap); 303 304} 305 306void GetWindowHandle(const DWORD TargetID, HWND * hwnd_ary) 307{ 308 int idx = 0; 309 HWND hWnd = GetTopWindow(NULL); 310 311 do { 312 //if (GetWindowLong(hWnd, GWL_HWNDPARENT) != 0 || !IsWindowVisible(hWnd)) 313 //continue; 314 DWORD ProcessID; 315 GetWindowThreadProcessId(hWnd, &ProcessID); 316 if (TargetID == ProcessID) { 317 318 hwnd_ary[idx] = hWnd; 319 idx++; 320 //return hWnd; 321 } 322 } while ((hWnd = GetNextWindow(hWnd, GW_HWNDNEXT)) != NULL); 323 324 hwnd_ary[idx] = NULL; 325}

試したこと

  • Spyxxで確認しましたが、スタイラスペンで各種ブラウザ(Edge,Firefox)のウィンドウにタッチしてもWM_POINTER系メッセージは取得できませんでした。

VisualStudioのウィンドウ上では、WM_POINTER系のメッセージが取得できました。

  • ブラウザ側からJavaScriptでペンの挙動を取得することも考えましたが、得られる挙動の情報が少ないため、断念しました。

補足情報(FW/ツールのバージョンなど)

ウィンドウハンドルの取得方法、グローバルフックの設定方法も、正直怪しいですが、よろしくお願いします。

追記

  • Spyxxでメッセージが取得できない原因は、64bitのプロセスに対して32bitのSpyxxで監視しようとしていたからでした。

Spyxx(amd64)によって監視したところ、ブラウザのウィンドウでWM_POINTERのメッセージが確認できました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

SetWindowsHookExに対して別プロセスのdwThreadIdを指定しているのでエラーになっているんじゃないでしょうか?
SetWindowsHookExが成功しているか確認してみてください。

SetWindowsHookEx

An error may occur if the hMod parameter is NULL and the dwThreadId parameter is zero or specifies the identifier of a thread created by another process.

投稿2018/08/26 11:22

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tekka

2018/08/26 11:41

ご回答ありがとうございます。 SetWindowsHookExの戻り値は、正常でした。 確認して頂いたのに、自己解決しまして、お手数をお掛けしまして申し訳ありません。 またよろしくお願い致します。
guest

0

自己解決

プロジェクトを再作成したところ、正常にフックが設定できました。
プロジェクト構成を弄ってどこかおかしくなっていたんだと思います。
お騒がせしました。

投稿2018/08/26 11:36

編集2018/08/26 11:42
tekka

総合スコア514

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問