0

我有这段代码,它为低级事件设置了一个键盘钩子,然后显示一个消息框。

HHOOK keyboardHook = SetWindowsHookEx (WH_KEYBOARD_LL, HookKey, hInstance, 0);

MessageBox(NULL, L"Click to exit", L"hook test", NULL);

UnhookWindowsHookEx(keyboardHook);

如何在不创建前台窗口的情况下运行应用程序的主循环,以及如何设置hInstance捕获全局事件?

4

2 回答 2

4

The answer is all contained on the MSDN docs page for SetWindowsHookEx. To experiment with a sample application, create a new solution, add two projects, a console app and a DLL. Each project just needs one file. The DLL will contain the hook, and the console app installs the hook.

The code for the hook must live inside a DLL, as the MSDN docs very clearly say:"If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL." Indeed, the hook clearly has to be in a DLL, or how could the shell run the code during another application's message loop? The DLL installs the hook using its HINSTANCE to identify where the function pointer lives.

The main application runs starts the hooks, and pumps messages, again just following the instructions in the MSDN docs: "...the hooking application must continue to pump messages or it might block the normal functioning of the 64-bit processes."

Note that this is very niche application — hardly ever will you need to inject a DLL like this. Please, please, think twice about doing this. For many applications, it's not necessary to capture low-level events, although immersive applications that suppress the Start menu are a reasonable use-case. More importantly though, you very rarely need to capture input sent to other applications. Check before using this code that you really need to do this. For example, recording a macro can be done just by hooking the input to your own application's window.

main.cpp

#include <windows.h>
#include <tchar.h>

__declspec(dllimport) void (__stdcall runHook)(BOOL startOrStop);
__declspec(dllimport) LRESULT (CALLBACK hookProc)(int code, WPARAM wParam, LPARAM lParam);

int _tmain(int argc, _TCHAR* argv[])
{
  runHook(true);
  MSG Msg;
  while(GetMessage(&Msg, NULL, 0, 0) > 0 && Msg.message != WM_QUIT) {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
  }
  runHook(false);
  return 0;
}

Dll.cpp

#include <assert.h>
#include <windows.h>

static HINSTANCE dllInst = 0;
static HHOOK hookSelf = 0;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
  dllInst = (HINSTANCE)dllInst;
  return TRUE;
}

__declspec(dllexport) LRESULT (CALLBACK hookProc)(int code, WPARAM wParam, LPARAM lParam)
{
  if (code >= 0) {
    UINT msgType = wParam;
    KBDLLHOOKSTRUCT* msgInfo = (KBDLLHOOKSTRUCT*)lParam;
    // The msgInfo contains the VK_CODE and flags.
  }  
  return hookSelf ? CallNextHookEx(hookSelf, code, wParam, lParam) : 0;
}

__declspec(dllexport) void (__stdcall runHook)(BOOL startOrStop)
{
  assert((bool)hookSelf != (bool)startOrStop);
  if (startOrStop)
    hookSelf = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, dllInst, 0);
  else {
    UnhookWindowsHookEx(hookSelf);
    hookSelf = 0;
  }
}
于 2013-09-02T18:39:54.900 回答
2

一种方法是在 Windows 上创建一个TSR(Terminate and Stay Resident)程序。

在 Windows 上,典型的 TSR 程序由以下组件组成:

  • 创建和隐藏主窗口。
  • 注册热键。
  • 循环测试事件。
  • 响应热键的功能。
  • 定时器定期调用的函数。

这是一篇很好的文章,其中包含有关在 Windows 上编写 TSR 的代码片段和详细说明。

于 2013-07-23T05:25:56.383 回答