【发布时间】:2021-04-13 14:07:43
【问题描述】:
我有一个 Win32 GUI 应用程序,其中一个线程在按下按钮时启动,如下所示:
...
switch (wmId)
{
case int(BTN::Test) :
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)dllTest, &hWnd, 0, NULL);
...
HHOOK hhookSysMsg = nullptr;
HINSTANCE hinstDLL = nullptr;
void dllTest() {
HOOKPROC hkprcSysMsg;
hinstDLL = LoadLibraryA("F:\\projects\\_dll_hook\\x64\\Release\\hook.dll");
if (hinstDLL == NULL) {
prnt("Error loading dll: #%d", PV, GetLastError());
return;
}
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
if (hkprcSysMsg == NULL) {
prnt("Error getting address of dll.SysMessageProc: #%d", PV, GetLastError());
return;
}
hhookSysMsg = SetWindowsHookExA(
WH_CALLWNDPROC,
hkprcSysMsg,
hinstDLL,
0);
if (hhookSysMsg == NULL) {
prnt("Error hooking dll.SysMessageProc: #%d", PV, GetLastError());
return;
}
Sleep(5000);
UnhookWindowsHookEx(hhookSysMsg);
FreeLibrary(hinstDLL);
}
这是 DLL 代码:
std::unordered_map<int, std::string> map;
void loadMsg() {
std::fstream stream("F:\\tmp\\_dll\\msg.txt");
if (stream.is_open()) {
std::string line;
while (std::getline(stream, line)) {
auto index = line.find(' ');
if (index != std::string::npos)
map.insert(std::make_pair(std::stoi(line.substr(0, index)), line.substr(index + 1)));
}
stream.close();
}
}
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {
switch (Reason) {
case DLL_PROCESS_ATTACH:
OutputDebugStringA("DLL attach function called");
loadMsg();
break;
case DLL_PROCESS_DETACH:
OutputDebugStringA("DLL detach function called");
break;
case DLL_THREAD_ATTACH:
OutputDebugStringA("DLL thread attach function called");
break;
case DLL_THREAD_DETACH:
OutputDebugStringA("DLL thread detach function called");
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) auto SysMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);
if (nCode == HC_ACTION) {
CWPSTRUCT* pCWP = (CWPSTRUCT*)lParam;
HWND hWnd = pCWP->hwnd;
char wclass[256]; wclass[0] = 0;
if (GetClassNameA(hWnd, wclass, 255) != 0) {
std::string msg = map[pCWP->message];
if (1 || msg == "WM_NOTIFY") {
char out[256]; out[0] = 0;
sprintf_s(out, 255, "class: '%s', msg: %s %08X\n", wclass, msg.c_str(), pCWP->message);
OutputDebugStringA(out);
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
此代码有效,但它从不打印(在 DebugView 或 MSVS 调试输出中)来自其他程序(如记事本)的消息。
如果我将 OutputDebugStringA 替换为文件的输出,目标程序和 explorer.exe 经常会崩溃或程序冻结。但是,如果我查看该文件,我可以看到那里捕获了来自不同程序的消息。
那么在这种情况下显示消息的正确方法是什么,它既快又能从其他程序中捕获消息,就像在 Spy++ 中所做的那样?
【问题讨论】:
-
你可以试试 Mark Russinovich 的DebugView utility。
-
正如我所提到的,我确实使用该程序来查看调试输出以及 MSVS 内部
-
哦,原来如此 - 抱歉。