【问题标题】:SetWindowsHookEx with WH_KEYBOARD doesn't work for me, what do I wrong?带有 WH_KEYBOARD 的 SetWindowsHookEx 对我不起作用,我做错了什么?
【发布时间】:2012-06-24 09:41:58
【问题描述】:
#include <iostream>
#include <fstream>
#define _WIN32_WINNT 0x501
#include <windows.h>

using namespace std;

HHOOK hKeyboardHook = 0;
LRESULT CALLBACK KeyboardCallback(int code,WPARAM wParam,LPARAM lParam) {  
  cout << "a key was pressed" << endl;
  ofstream myfile;
  myfile.open ("hookcheck.txt", ios::ate | ios::app);
  myfile << "a key was pressed\n";
  myfile.close();
  return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
}

int main() {

  HWND consoleWindow = GetConsoleWindow();
  HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( consoleWindow, GWL_HINSTANCE );
  hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardCallback, (HINSTANCE)consoleWindow, GetCurrentThreadId());

  MessageBox(NULL, "It is keyboard time!", "Let's Go", MB_OK);

}

循环进行时每次按键的这段代码都应该在控制台上打印消息并创建一个文件,但是什么也没有发生。我哪里错了?

【问题讨论】:

  • SetWindowsHookEx 挂钩 Windows 消息。控制台应用程序不使用消息。您必须编写一个本机 Windows 应用程序来泵送消息循环。
  • 顺便说一下,Windows 控制台确实提供了低级输入 API,您应该使用它们而不是使用钩子。
  • @MatteoItalia:这很有趣,你能给我手册的链接吗,我不太清楚你在说哪个 api,我一直在寻找。
  • here开始。
  • This 页面尤其应该与您的目标相关。

标签: c++ windows winapi console keyboard-hook


【解决方案1】:

我会引用another topic:

控制台窗口完全由 CSRSS 处理,这是一个系统 过程。在进程中安装钩子意味着注入你的 DLL 进去。由于 CSRSS 是如此重要(它对于运行 系统,其中的代码作为本地系统运行,这是本地的 超级管理员用户),您不能向其中注入代码。那么你 不能钩住它的任何窗口。

在您的简单控制台应用程序中没有发生真正的窗口消息,因此不必调用您的钩子,在您的情况下,您甚至没有注入钩子,而仅使用线程模式钩子。根据 MSDN 文档,当消息即将被处理时调用它:

应用程序定义或库定义的回调函数,用于 SetWindowsHookEx 函数。系统在任何时候调用这个函数 应用程序调用 GetMessage 或 PeekMessage 函数 是要处理的键盘消息(WM_KEYUP 或 WM_KEYDOWN)。

现在让我向您展示如何开始在挂钩上接听电话:

MessageBox(NULL, _T("It is keyboard time!"), _T("Let's Go"), MB_OK);

//for(int i=0; i<=10; i++) {
//  cout << i << endl;
//  Sleep(1000);
//}

执行MessageBox 并在关闭它之前开始输入 - 您将开始收到挂钩调用。

【讨论】:

  • 如果我理解您引用的文字是什么意思,SetWindowsHookEx 不适用于控制台应用程序,对吧?我更新了有问题的代码,但它仍然不起作用。
  • 为我工作。确保您的消息框窗口在前台,但不要按按钮将其关闭。在那里输入一些东西。这会在您安装挂钩的线程中生成键盘消息。你的钩子将被调用。
  • 对不起,我没有在这里做错什么,但没有任何事件显示给我。 (我使用 gcc 4.7.0 mingw)
  • 我不太确定这是否会有所帮助,但这是我的源代码和二进制文件alax.info/trac/public/browser/trunk/Utilities/… 此外,您可能希望使用Spy++ 工具来检查您的进程中出现的消息.
  • 这是因为您没有按照 Scott Langham 的建议进行检查。你没有在 XP 中安装钩子,因为在 XP 中 GetWindowLong 返回非 NULL 结果并且你必须有 NULL 那里(见更新的代码)。
【解决方案2】:

阅读 SetWindowsHookEx 的文档。是否正常工作,如果失败会返回 NULL,并且可以调用 GetLastError() 来获取错误代码以帮助诊断问题所在。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

【讨论】:

  • GetLastError() 返回0。 - 我在哪里可以找到它的含义?
  • 确实如此。发生了一些奇怪的事情,代码编译没有错误,代码中的任何地方都没有显示错误,只是回调没有初始化。
【解决方案3】:

Sleep(1000) 暂停当前线程的执行,直到超时间隔结束。这意味着您的程序在此睡眠期间实际上并未运行(即处理消息)。

您需要使用不同类型的命令来保持消息循环运行。最简单的事情就是等待用户输入

while(true)
   std::cin.get(); 

【讨论】:

    【解决方案4】:

    我创建了一个连接键盘的 dll,并在其中使用了DllMain函数来检索可以在SetWindowsHookEx 中使用的HINSTANCE

    除此之外,我还使用 0 作为 threadid,以便所有线程都被钩住。

    也许您也可以尝试类似的策略。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-21
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      • 2014-08-21
      相关资源
      最近更新 更多