问题描述
我正在尝试使用从 WH_CALLWNDPROC
获得的 HWND
在窗口上设置 WindowFromPoint
挂钩,然后发送消息 WM_USER+x
。但是根据 HWND
我使用它会导致窗口崩溃。
让我解释一下这个场景:
当通过 HWND
函数获得 WindowFromPoint
时,您有时会获得其中一个子窗口而不是主窗口。
使用 spy++ 中的 Finder 工具可视化非常好
所以我只是得到了窗口
wcout << "INFO: Waiting 1 second before first hwnd...\n";
this_thread::sleep_for(chrono::milliseconds(1000));
HWND targetHwnd = getHwndFromMousePos(); //Gets hwnd from mouse pos with WindowFromPoint
outHwndData(targetHwnd);
DWORD targetPID;
DWORD targetTID = GetwindowThreadProcessId(targetHwnd,&targetPID);
然后使用dll的导出函数设置hook。
hook = setHook(targetTID); //hook is the global HHOOK and setHook is a exported function in a dll
if (hook == NULL) {
cout << "ERROR: Could not set hook\n";
return 1;
}
dll里面的函数是这样的
extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid) {
return SetwindowsHookEx(WH_CALLWNDPROC,wmProcCallback,hInst,targetTid);
}
当 targetHwnd
是孩子 HWND
时,我钩住,发送消息 -> 工作正常
但是当 targetHwnd
是上面的 HWND
(绿色标记的)时,我钩住它,发送消息 -> 它崩溃了。
所以最后 SetwindowsHookEx
有效,但如果它是上面的 HWND
(绿色标记的),我无法向找到的窗口发送任何消息。为什么会这样?
这个完整的演示代码将等待 1 秒钟,然后再拿起 HWND
。通过将鼠标悬停在 explorer.exe 窗口的标题栏上,您可以获得导致崩溃的 HWND
。
应用代码:
//This is the app
#include <Windows.h>
#include <iostream>
#include <thread>
using namespace std;
typedef HHOOK(WINAPI* DLLFUNC_SETHOOK) (DWORD);
HINSTANCE dllInstance;
DLLFUNC_SETHOOK setHook;
HHOOK hook;
HWND getHwndFromMousePos() {
POINT cursorPos;
if (GetCursorPos(&cursorPos) == FALSE) {
cout << "ERROR: Could not get Cursor position...\n";
return NULL;
}
HWND wnd = WindowFromPoint(cursorPos);
if (wnd == NULL) {
cout << "ERROR: No window found on this point\n";
return NULL;
}
return wnd;
}
int main() {
wcout << "INFO: Waiting 1 second before first hwnd...\n";
this_thread::sleep_for(chrono::milliseconds(1000));
HWND targetHwnd = getHwndFromMousePos();
wcout << targetHwnd << endl;
DWORD targetPID;
DWORD targetTID = GetwindowThreadProcessId(targetHwnd,&targetPID);
dllInstance = LoadLibrary(L"DLL1.dll");
setHook = (DLLFUNC_SETHOOK)GetProcAddress(dllInstance,"setHook");
if (dllInstance == NULL) {
cout << "ERROR: dllInstance is NULL\n";
return 1;
}
if (setHook == NULL) {
cout << "ERROR: setHook function is NULL\n";
return 1;
}
hook = setHook(targetTID);
if (hook == NULL) {
cout << "ERROR: Could not set hook\n";
return 1;
}
cout << "INFO: Hooked successfully\n";
//Works only when targetHwnd is a children
SendMessage(targetHwnd,WM_USER + 1,0); //This causes the crash
cin.ignore();
BOOL success = UnhookWindowsHookEx(hook);
if (success == FALSE) {
cout << "ERROR: Could not unhook\n";
}
else {
cout << "INFO: Unhooked hook. Exiting...\n";
}
}
DLL(DLL1):
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <fstream>
extern HINSTANCE hInst;
extern std::wofstream logfile;
extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid);
HINSTANCE hInst;
std::wofstream logfile;
BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
hInst = hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
logfile.open("D:\\projects\\crashDemo\\log.txt"); //run "Get-Content -Path "log.txt" -Wait" in Powershell for realtime logs
break;
}
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: {
logfile.close();
break;
}
}
return TRUE;
}
LRESULT CALLBACK wmProcCallback(int nCode,WParaM wParam,LParaM lParam) {
if (nCode >= HC_ACTION) {
PcwpSTRUCT cwpStruct = (PcwpSTRUCT)lParam;
switch (cwpStruct->message) {
case WM_USER + 1:
logfile << "WM_USER+1 Message received" << std::endl;
break;
}
}
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid) {
return SetwindowsHookEx(WH_CALLWNDPROC,targetTid);
}
编辑:我确实调试通过了。看起来 dll 一切正常。它加载并且 wmProcCallback
被调用多次。
我的 WM_USER+1
也被识别,但在处理 wmProcCallback
中的所有消息后,它立即关闭窗口并留下以下错误消息。
所以我总共收到了 4 条错误消息:
-
& 2.
An outgoing call cannot be made since the application is dispatching an input-asynchronous call
-
The operation is not permitted because the calling application is not the owner of the data on the clipboard.
-
Unspecified error
有人知道其中哪些是相关的,因为我不知道这些错误中的任何一个吗?现在要做一些研究。如果有人可以提供帮助,那就太好了。
解决方法
简单修复,不要使用 WM_USER+1 :)