我已在程序内成功创建了 WH_KEYBOARD_LL 挂钩。我已将回调放入 DLL 中,并隐式链接到主 EXE。一切都很好(该应用程序帮助我完成 PC 自动化类型的任务)。
我现在想添加一个 WH_SHELL 钩子,但运气不太好。
EXE 项目(Visual C++ 2022):
// pcautomation.h
#pragma once
#define WINVER 0x0500
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
// pcautomation.cpp
#include "<path>\pcautomation.h"
#include "<path>\keyboardCallback.h"
#include "<path>\shellCallback.h"
using namespace std;
HHOOK hhKybd;
HHOOK hhShell;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int cmdShow) {
// ... <register application window, etc> ...
// THIS WORKS JUST FINE
hhKybd = SetWindowsHookExW(WH_KEYBOARD_LL, (HOOKPROC) KeyboardHookProc, NULL, 0);
if (NULL == hhKybd) return 0;
// THIS DOES NOT WORK. hhShell IS SET TO NULL, INDICATING FAILURE
hhShell = SetWindowsHookExW(WH_SHELL, (HOOKPROC) WHShellProc, NULL, 0);
if (NULL == hhShell) return 0;
// ... <message loop, etc> ...
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
// ...
return DefWindowProc(hwnd, msg, wParam, lParam);
}
DLL项目:
// pcautomation-dll.h
#pragma once
#ifdef NAX_PCA_DLL_EXPORTS
#define NAX_PCA_DLL_API __declspec(dllexport)
#else
#define NAX_PCA_DLL_API __declspec(dllimport)
#endif
#define WINVER 0x0500
#include <Windows.h>
// pcautomation-dll.cpp
#include "<path>\pcautomation-dll.h"
#include "<path>\keyboardCallback.h"
#include "<path>\shellCallback.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// keyboardCallback.h
#pragma once
#include <Windows.h>
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
// keyboardCallback.cpp
#include "<path>\keyboardCallback.h"
using namespace std;
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
...
CallNextHookEx(NULL, nCode, wParam, lParam);
}
// shellCallback.h
#pragma once
#include <Windows.h>
LRESULT CALLBACK WHShellProc(int nCode, WPARAM wParam, LPARAM lParam);
// shellCallback.cpp
#include "<path>\shellCallback.h"
using namespace std;
LRESULT CALLBACK WHShellProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < 0) return(CallNextHookEx(NULL, nCode, wParam, lParam));
if (nCode == HSHELL_WINDOWCREATED) {
...
}
return 0;
}
// source.def
LIBRARY pcautomation-dll
EXPORTS
KeyboardHookProc
WHShellProc
VS 2022 使用我理解的隐式 DLL 链接所需的配置进行设置:
正如您在代码中看到的,我将两个钩子的
dwThreadId
的 SetWindowsHookExW
设置为 0,因为我不想限制哪些线程响应钩子,它们应该全局工作。
关于
hmod
参数,我知道docs说“如果dwThreadId参数指定当前进程创建的线程并且钩子过程位于与当前进程关联的代码内,则必须将其设置为NULL process”,尽管 dwThreadId
没有指定这样的线程,但我还是这样做了。这似乎适用于键盘挂钩。 WH_SHELL 钩子有什么不同吗?它需要显式的DLL句柄吗?
我担心我必须重新配置整个设置才能使用显式 DLL 链接才能获取该句柄(并且 DLL 的代码和使用比我在这里显示的要多得多)。
尽管 dwThreadId 没有指定这样的线程,但我还是这样做了。 这似乎适用于键盘挂钩。是WH_SHELL钩子 不同的?它需要显式 DLL 句柄吗?
根据SetWindowsHookEx,您需要将
hmod
设置为包含lpfn
参数所指向的钩子过程的DLL,就像其他钩子一样。
问题应该是,
WH_KEYBOARD_LL
钩子不同吗?
解释可能是
WH_KEYBOARD_LL
是 全局的 并且 在安装它的线程的上下文中调用。通过向安装钩子的线程发送消息来进行调用。