【发布时间】:2021-01-21 14:46:42
【问题描述】:
这几天我一直在绞尽脑汁,希望能得到一些帮助!当 CBT 钩子挂接到我的 WPF 应用程序的线程 ID 时,我能够使用 SetWindowsHookEx 检测到它,但是当该窗口成为前台应用程序时,我无法让它挂接到另一个进程窗口的线程 ID .
图 1:显示我可以获得 CBT 挂钩,用于检测主应用程序线程 ID 上的窗口最大化
图 2:显示我在监听另一个应用的线程 ID 时无法获取 CBT 钩子,它会导致应用崩溃!
我想避免发送 ThreadId=0 并使其成为一个完整的全局挂钩,因为我知道我只想听前台应用程序,而不是桌面上的所有应用程序。对于当前具有前景焦点的任何窗口,我希望能够在它们发生之前监听一些窗口事件(WH_CBT 根据我的理解这样做)。
同样,以下代码在当前 WPF 应用程序变为前台应用程序时有效,但当另一个应用程序的窗口变为前台时(例如记事本、Internet Explorer、文件资源管理器、Chrome 等),它会失败。
完整代码:(link to github zip file)
这里有一些代码的 sn-ps 来显示我做了什么:
定义回调的DLL(inject.dll):
inject.h:片段typedef void(__stdcall* MYFUNCPTR)(int code, WPARAM wparam, LPARAM lparam);
extern "C" __declspec(dllexport) void Init(MYFUNCPTR funcPtr);
extern "C" __declspec(dllexport) LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam);
WPARAM wparam, LPARAM lparam);
MYFUNCPTR _handler = 0;
inject.cpp:片段
void Init(MYFUNCPTR funcPtr)
{
_handler = funcPtr;
}
LRESULT CALLBACK CbtProcCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code >= 0)
{
// Only send the code if you are about to MAXIMIZE
if (code == HCBT_MINMAX)
{
if (lparam == SW_MAXIMIZE)
{
_handler(0, wparam, lparam);
}
}
}
return CallNextHookEx(NULL, code, wparam, lparam);
}
设置 CBT 挂钩的 DLL (dllwrapper.dll):
dllwrapper.cpp:片段 // Load library in which we'll be hooking our functions.
HMODULE dll = LoadLibrary(L"inject.dll");
if (dll == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-LoadLibrary failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("LoadLibrary passed!");
// Get the address of the function inside the DLL.
MYPROC iaddr = (MYPROC)GetProcAddress(dll, "Init");
if (iaddr == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for Init failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for Init passed!");
iaddr(OnInjectionCallback);
// Get the address of the function inside the DLL.
HOOKPROC cbtProcAddress = (HOOKPROC)GetProcAddress(dll, "CbtProcCallback");
if (cbtProcAddress == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-GetProcAddress for CbtProcCallback failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("GetProcAddress for CbtProcCallback passed!");
// Hook the function
cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProcAddress, dll, _threadId);
if (cbtProcHook == NULL) {
char errorMessage[100];
sprintf_s(errorMessage, "ERR-SetWindowsHookEx cbtProcAddress failed! ErrorCode=%d", GetLastError());
SendManagedMessage(errorMessage);
return false;
}
SendManagedMessage("SetWindowsHookEx for cbtProcAddress passed!");
片段导出到 C#
typedef void(__stdcall* CodeCallback)(int code, WPARAM wparam, LPARAM lparam);
typedef void(__stdcall* MessageCallback)(const char* message);
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
__declspec(dllexport) bool StartHooks(unsigned int threadId, MessageCallback messageCallback, CodeCallback codeCallback);
__declspec(dllexport) void StopHooks();
#ifdef __cplusplus
}
#endif
NativeMethods.cs:导入 WPF 应用程序的 C# dll 片段
public delegate void MessageCallback(string message);
public delegate void CodeCallback(int code, IntPtr wParam, IntPtr lParam);
[DllImport("dllwrapper.dll")]
public extern static bool StartHooks(uint threadId, MessageCallback messageHandler, CodeCallback codeHandler);
[DllImport("dllwrapper.dll")]
public extern static void StopHooks();
我可以从 WPF 应用程序窗口中的消息中看到,该挂钩正在传递并且没有返回任何 Win32 错误,但它只是在另一个窗口具有焦点时不执行回调(即使使用调试器时也是如此)。
任何帮助将不胜感激!
开发环境:
- Windows 10 1909
- VS2019 16.7.4
- C# .NET Framework 4.7.2,C++
【问题讨论】:
标签: c++ winapi hook setwindowshookex