C++ 为什么PeekMessage没有';对PostMessage发布的消息调用键盘钩子进程?

C++ 为什么PeekMessage没有';对PostMessage发布的消息调用键盘钩子进程?,c++,windows,hook,C++,Windows,Hook,我有一个通过键盘挂钩处理键盘输入的应用程序。它通过SetWindowsHookEx(WH_键盘,…)设置钩子 当消息处理循环中的PeekMessage从实际硬件键盘接收到通常的WM_KEYUP和WM_KEYDOWN消息时,它调用回调,一切正常,但它完全忽略PostThreadMessage(以及任何其他消息传递函数)发送的消息。它只是不调用钩子过程 下面有一段糟糕的代码(大部分由VisualStudio自动生成)来说明这种行为。有一个带有消息处理循环和线程的窗口,每1秒发送WM_KEYDOWN消

我有一个通过键盘挂钩处理键盘输入的应用程序。它通过
SetWindowsHookEx
WH_键盘
,…)设置钩子

当消息处理循环中的
PeekMessage
从实际硬件键盘接收到通常的
WM_KEYUP
WM_KEYDOWN
消息时,它调用回调,一切正常,但它完全忽略
PostThreadMessage
(以及任何其他消息传递函数)发送的消息。它只是不调用钩子过程

下面有一段糟糕的代码(大部分由VisualStudio自动生成)来说明这种行为。有一个带有消息处理循环和线程的窗口,每1秒发送
WM_KEYDOWN
消息。键盘回调的所有调用都会将日志记录写入控制台窗口,当我按下键盘上的键时,我可以看到它们,但没有第二个线程发送的消息的记录

我无法更改主应用程序实现。出于许多原因,它应该通过键盘挂钩工作。但我如何让
GetMessage
PeekMessage
像处理来自硬件键盘的消息一样处理我的键盘消息呢?非常感谢您的帮助,我花了整整一周的时间来解决这个问题

我已经在Windows 8.1 64位和32位应用程序上进行了测试

代码如下:

#include "windows.h"
#include <iostream>
#include <fstream>

using namespace std;

#define MAX_LOADSTRING 100

HINSTANCE hInst;                                
TCHAR *szTitle = TEXT("Title");                 
TCHAR *szWindowClass = TEXT("HookedWindowClass");       

LRESULT CALLBACK KeyboardCallback(
    _In_  int code,
    _In_  WPARAM wParam,
    _In_  LPARAM lParam
    )
{
    wcout << L"KeyboardCallback " << endl; 
    MSG *msg = (MSG*)lParam;
    wcout << L"KBHOOK " << code << L" wParam " << hex << wParam << L" lParam " << lParam << dec << endl; 
    return CallNextHookEx(NULL,code,wParam,lParam);
}


ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);


DWORD mainThreadId = 0 ;
HWND window = 0;

DWORD threadFn(void*)
{
    while(true)
    {
        if(!PostThreadMessage(mainThreadId,WM_KEYDOWN,0xd,0x1c0001))
        {
            cout << "Error posting message to " << hex << mainThreadId << " error " << GetLastError() << endl; 
        }

        Sleep(1000);
    }
}

int APIENTRY WinMain(_In_ HINSTANCE hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPSTR    lpCmdLine,
                       _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);


    MSG msg;

    MyRegisterClass(hInstance);

    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }



    AllocConsole();

    wfstream console_out("CONOUT$");
    wcout.rdbuf(console_out.rdbuf());


    HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardCallback,GetModuleHandle(NULL),GetCurrentThreadId());


    mainThreadId = GetCurrentThreadId();

    CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadFn,NULL,0,NULL);



    while (GetMessage(&msg, NULL, 0, 0))
    {


        switch (msg.message)
        {

        case WM_KEYDOWN:
            wcout << L"WM_KEYDOWN" << L" wParam " << hex << msg.wParam << L" lParam " << msg.lParam << dec << endl; 
            break;
        default:
            break;
        }

        TranslateMessage(&msg);
        DispatchMessage(&msg);

    }

    return (int) msg.wParam;
}


ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = NULL;
    wcex.hIconSm = NULL;
    wcex.lpszClassName  = szWindowClass;
    return RegisterClassEx(&wcex);
}


BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    hInst = hInstance; 

    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    window = hWnd;
    return TRUE;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_QUIT:
        ExitProcess(0);
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
#包括“windows.h”
#包括
#包括
使用名称空间std;
#定义最大加载字符串100
HINSTANCE hInst;
TCHAR*szTitle=文本(“标题”);
TCHAR*szWindowClass=文本(“HookedWidowClass”);
LRESULT回调键盘回调(
_In_uuint代码,
_在WPARAM WPARAM,
_In_lparamlparam
)
{

根据设计,PeekMessage与键盘挂钩无关。WH_键盘挂钩回调仅用于从设备驱动程序或SendInput()接收的键盘输入输入。如果您还想监视发布的消息,请使用WH_GETMESSAGE。我在KeyboardProc处理键盘消息时,在debugger下的调用堆栈上看到PeekMessage。我不想监视输入,我想将输入消息发送到已编写且无法更改的应用程序。不幸的是,我无法使用SendInput,因为它会影响整个系统,而我需要同时将不同的输入发送到不同的窗口。有什么方法可以做到吗?你还会在堆栈中找到其他函数。这并不意味着它们都负责调用键盘挂钩函数。只有一个是。你可能选错了一个。。。