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,因为它会影响整个系统,而我需要同时将不同的输入发送到不同的窗口。有什么方法可以做到吗?你还会在堆栈中找到其他函数。这并不意味着它们都负责调用键盘挂钩函数。只有一个是。你可能选错了一个。。。