【问题标题】:does not go inside the Windows GetMessage loop on console application不会进入控制台应用程序上的 Windows GetMessage 循环
【发布时间】:2015-01-30 18:33:15
【问题描述】:

我想检测 C++ 中的按键,我需要使用 Windows 系统调用。所以,我做了一些研究,这就是我使用 Hooks 和 Message 得到的结果:

#include <Windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>

using namespace std;

LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code == HC_ACTION) {
        switch (wParam) {
        case WM_KEYDOWN:
            PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
            char c = char(MapVirtualKey(p->vkCode, MAPVK_VK_TO_CHAR));
            cout << c << endl;
        }
    }
    return CallNextHookEx(NULL, code, wParam, lParam);
}

int main() {    
    HHOOK HKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);

    MSG msg;
    BOOL bRet;

    while ((bRet = GetMessage(&msg, NULL, 0, 0)) > 0) {
        cout << "bRet = " << bRet << endl; // I want to do something here, but the program doesn't seem to go in here
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    UnhookWindowsHookEx(HKeyboard);
    return 0;
}

我的问题是为什么我的程序没有进入循环内部(而是停留在 GetMessage 函数上)?我需要它来设置几秒钟后终止的条件,那么我应该把条件放在哪里?我知道 GetMessage 函数读取 Message,但是当我按下键盘上的键时它仍然无法进入,并且回调函数工作正常。

【问题讨论】:

  • 没关系。 Windows 内部的挂钩逻辑是直接调用 hook proc - 您只需要消息循环,以便 Windows 知道您的服务线程处于已知的空闲状态。
  • 我明白了。但是,既然它根本没有进入循环,我可以只使用GetMessage(&amp;msg, NULL, 0, 0) 而不是整个循环吗?另外,如果想在 10 秒后终止,我的“if process > 10s then terminate”代码会去哪里?

标签: c++ windows console getmessage


【解决方案1】:

事件被发布到活动窗口。控制台窗口由控制台子系统 csrss.exe 拥有,它接收事件,然后将它们转换为字符并将它们放入控制台对象中,即您的应用程序的 stdin

如果您想以 Win32 GUI 方式处理事件,您应该使用 Win32 窗口(例如 RegisterClassCreateWindow),而不是控制台窗口。

如果您只想让回调在一段时间内工作,您可以使用警报等待,例如 SleepExMsgWaitForMultipleObjects,它们接受超时。

【讨论】:

    【解决方案2】:

    这并不奇怪,您的线程队列中实际上没有任何消息,并且您没有窗口,因此也没有窗口队列。

    如果您想使用从钩子返回的值,请将代码放入钩子回调函数中。

    我应该警告你,像这样的钩子在控制台应用程序中不起作用,因为控制台窗口驻留在另一个进程中。另外,如果您查看SetWindowsHookEx 的MSDN 页面,您会看到WH_KEYBOARD_LL 只是一个全局挂钩,即您必须将挂钩处理程序放在DLL 库中并将挂钩注入其他应用程序中。然后你必须自己处理 32/64 位的问题。

    最后一点,当您在处理程序中说cout &lt;&lt; c; 时,这将是在进程的输出文件句柄中打印,而不是您自己的。

    【讨论】:

    • 我以为按键盘会根据link“系统在每个输入事件时生成一条消息-例如,当用户键入时”生成消息,我理解错了吗?但是,为什么我的代码没有 DLL 也能工作?
    • @kucingimbalance:该链接是正确的,但它没有解释与您的情况相关的一些细节。事件被发布到活动窗口。控制台窗口由控制台子系统 csrss.exe 拥有,它接收事件,然后将它们转换为字符并将它们放入作为应用程序标准输入的控制台对象中。如果你想用 Win32 GUI 方式处理事件,你应该使用 Win32 窗口,而不是控制台窗口。
    猜你喜欢
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多