Windows Journal回放挂钩(WH_JOURNALPLAYBACK)忽略EVENTMSG HWND参数

时间:2014-11-28 11:22:05

标签: c++ winapi

我正在编写一个以编程方式模拟键盘和鼠标点击的程序。它需要将点击发送到目标窗口句柄(例如:记事本编辑控件)。我得到了记事本窗口的句柄,并为该窗口生成WM_KEYDOWN,WM_SYSKEYDOWN,WM_KEYUP,WM_SYSKEYUP消息。事件存储在队列中,稍后使用WH_JOURNALPLAYBACK挂钩进行播放。

对于下面的代码段,虽然设置正确,但播放过程中的目标hwnd仍然无法到达目标句柄。如果我将记事本带到前台,它会收到消息。

我不确定为什么WH_JOURNALPLAYBACK会忽略handle参数。我本来希望为各种句柄生成一系列自动化消息并播放它,这样即使不将窗口置于焦点,我们也可以发送键盘和鼠标事件。

请告诉我

  • 如果可以使用日志发送到各种目标句柄的消息 回放挂钩
  • 为什么在hwnd下面的代码被忽略

...

#include <queue> 
#include <iostream> 
#include <windows.h> 
using std::cout; 
using std::endl; 
using std::error; 

struct Event
{
    UINT msg; 
    UINT wparam; 
    UINT lparam; 
    HWND hwnd;

    Event(UINT m, UINT wp, UINT lp, HWND h)
        :msg(m), 
        wparam(wp), 
        lparam(lp), 
        hwnd(h) 
    {}
};

HHOOK jhook= NULL; 
std::queue<Event> events; 

bool gotoNextMsg = false; 
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
    switch( code )
    {

    case HC_SKIP:
        cout<<"skip: "<<endl; 
        if(!events.empty())
        {
            events.pop(); 
        }
        break; 

    case HC_GETNEXT:
        {
            cout<<"next: "<<events.size()<<endl; 
            gotoNextMsg = true; 
            EVENTMSG * evm = (EVENTMSG*) lParam; 
            Event e = events.front(); 
            switch(e.msg)
            {
            case WM_KEYDOWN:
                cout<<"WM_KEYDOWN"<<endl; 
                break; 
            case WM_KEYUP:
                cout<<"WM_KEYUP"<<endl; 
                break; 
            case WM_SYSKEYDOWN:
                cout<<"WM_SYSKEYDOWN"<<endl; 
                break; 
            case WM_SYSKEYUP:
                cout<<"WM_SYSKEYUP"<<endl; 
                break; 
            }
            cout<<"handle: "<<e.hwnd<<endl; 
            cout<<"handle1:"<<evm->hwnd<<endl; 
            evm->message = e.msg;
            evm->paramL = e.wparam; 
            evm->paramH = e.lparam; 
            evm->hwnd = e.hwnd; 
            evm->time = ::GetTickCount(); 
        }
        break;

    default:
        if( code < 0 )
            ::CallNextHookEx(jhook, code, wParam, lParam); 
        break;
    }

    if(events.empty())
    {
        cout<<"uinstalled"<<endl; 
        ::UnhookWindowsHookEx(jhook);
        ::PostMessage(NULL, WM_USER+100, 0, 0); 
    }

    return 0; 
}

1 个答案:

答案 0 :(得分:1)

日记挂钩将事件注入系统消息队列。对于键盘和鼠标消息,系统会将它们分派到当前聚焦窗口,就像用户手动输入它们一样。您未在事件中指定的HWND在调度期间被替换。

如果您认为录制的日志可以多次播放,并且其数据可以在应用程序实例中持续存在甚至重新启动,并且HWND可以随着时间的推移重复用于不同的事情,那么为什么期刊播放不能即使没有涉及系统消息队列,也要使用事件的HWND。

因此,您无法使用WH_JOURNALPLAYBACK来定位不在前台的特定窗口。您必须自己发送录制的消息。但请注意Raymond Chen撰写的一些警告:

You can't simulate keyboard input with PostMessage

Simulating input via WM_CHAR messages may fake out the recipient but it won't fake out the input system