我正在尝试开发一个应用程序,它可以在整个系统范围内创建和销毁顶级窗口。我做了一个代码来利用CBT的钩子。该解决方案包含两个项目,DLL和EXE。EXE项目具有对DLL项目的引用。钩子是从DLL中设置的。EXE项目中有一个消息循环。问题是CBT钩子不起作用。在VS调试器的帮助下,我发现钩子回调永远不会被调用,而来自SetWindowsHookEx的返回代码是非零的,这意味着钩子被设置了。什么是错误?我该怎么解决呢?
下面是一个很小的例子。DLL,main.cpp:
#include <windows.h>
typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);
HINSTANCE hInst = nullptr;
HHOOK hHook = nullptr;
DECODERPROC fpDecoder = nullptr;
LRESULT CALLBACK cbtProc(int code, WPARAM wParam, LPARAM lParam) {
// FIXME: never called
if (code > 0 && fpDecoder) {
fpDecoder(code, wParam, lParam);
}
return CallNextHookEx(hHook, code, wParam, lParam);
}
__declspec(dllexport) bool InstallHook(DECODERPROC decoder) {
if (hHook) return false;
fpDecoder = decoder;
return (hHook = SetWindowsHookEx(WH_CBT, cbtProc, hInst, 0)) != NULL;
}
__declspec(dllexport) bool UninstallHook() {
if (!hHook) return false;
bool res = UnhookWindowsHookEx(hHook) != NULL;
if (res) hHook = NULL;
return res;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
hInst = reinterpret_cast<HINSTANCE>(hModule);
return TRUE;
}EXE,main.cpp
#include <iostream>
#include <locale>
#include <windows.h>
#include <fcntl.h>
#include <io.h>
using namespace std;
typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);
__declspec(dllimport) bool InstallHook(DECODERPROC);
__declspec(dllimport) bool UninstallHook();
int main() {
_setmode(_fileno(stdout), _O_U8TEXT);
WNDCLASS windowClass = {};
windowClass.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
if (message == WM_DESTROY)
UninstallHook();
return DefWindowProc(hWnd, message, wParam, lParam);
};
LPCWSTR windowClassName = L"Foobar";
windowClass.lpszClassName = windowClassName;
if (!RegisterClass(&windowClass)) {
wcerr << L"Failed to register window class" << endl;
return 1;
}
HWND messageWindow = CreateWindow(windowClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);
if (!messageWindow) {
wcerr << L"Failed to create message-only window" << endl;
return 1;
}
InstallHook([](int code, WPARAM wParam, LPARAM lParam) {
wcout << L"Never called" << endl;
});
MSG msg;
while (GetMessage(&msg, 0, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}发布于 2014-10-28 18:52:15
如果在Windows 64位上运行,则需要32位和64位版本的DLL才能挂钩每个正在运行的进程。32位DLL不能连接64位进程,反之亦然.因此,您需要从32位进程调用SetWindowsHookEx()来挂起32位进程,从64位进程调用挂钩64位进程。
更重要的是,DLL的一个单独实例被注入到每个正在运行的进程中,因此在DLL的每个实例中,除了调用InstallHook()的实例之外,您的DLL回调指针都是空的。因此,您需要重新设计您的钩子,以便使用进程间通信(窗口消息、命名管道、邮件插槽、套接字等)与您的主EXE通信,您不能使用函数指针。
根据实际调试的进程,您可能不会看到cbtProc()被调用。如果正在调试主EXE进程,则一旦安装了钩子,代码就不会在EXE的进程中触发任何CBT活动,调试器也不会向您显示在其他进程中发生的任何CBT活动,这些活动不是它正在调试的。
根据您在钩子中实际要寻找的内容,您可以考虑使用SetWinEventHook(),因为它可以与DLL一起使用,也可以不使用DLL,而且它比SetWindowsHookEx()具有更灵活的过滤功能。
https://stackoverflow.com/questions/26611982
复制相似问题