c++ - 使用钩子向 explorer.exe 主窗口发送消息会导致崩溃?
问题描述
我正在尝试使用我从中获取的信息在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 = 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, 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, wmProcCallback, hInst, 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 :)
推荐阅读
- python - 随着搜索深度的增加,Alpha-beta 剪枝代理似乎会选择更差的动作
- c# - 如何在不检索所有行的情况下使用 Entity Framework Core 3.0 实现分组分页?
- python - Python仅对列表中的数字求和
- javascript - 选项卡的子项都不匹配 `[object Object]`。您可以提供以下值之一:0、1
- python - 这个 if 语句有什么作用(列表)?
- azure - Azure Policy - 拒绝 vnet 中没有特定标记的新网络接口
- stanza - 如何在节中的字符串中查找和替换字符?
- python - 寻找避免“列表索引超出范围错误”的方法
- rust - 在特征实现中未指定关联类型
- excel - Excel VBA,通过范围加速 For 循环