将消息注入WPF应用程序消息泵

时间:2016-09-14 21:00:48

标签: c++ wpf winapi

我有一些预编译的WPF应用程序需要控制而不需要通过发送各种消息来重新编译它们(例如:WM_POINTERMOVE,WM_KEYDOWN等)。我尝试过的控制方法是将消息注入应用程序消息泵。作为测试,我通过获取应用程序的Windows句柄然后使用 SendMessage 发送消息来尝试使用其他一些Win32应用程序。

BOOL CALLBACK EnumWindowsProc(
_In_ HWND   hwnd,
_In_ LPARAM lParam
)
{
    LPWSTR windowName = new TCHAR[256];
    GetWindowText(hwnd, windowName, 256);
    std::wstring windowNameString(windowName);
    int position = windowNameString.find(std::wstring(L"MyApplicationWindowName"));
    if (position > -1) {
        hTargetWindow = hwnd;
        delete windowName;
        return FALSE;//stop enumerating windows
    }
    delete windowName;
    return TRUE;
}

 .....
 EnumWindows(EnumWindowsProc, NULL);;
 SendMessage(hTargetWindow, MY_MESSAGE, 0, 0);

我使用 EnumWindows 检索了应用程序的HWND(工作正常)。然后我使用 SendMessage PostMessage 发送我的消息。而其他应用程序响应此WPF应用程序不。作为另一个测试我做了一个WPF应用程序并添加了一些代码,所以我可以在收到某个消息时设置一个断点。

ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
{
    if(msg.message == MY_MESSAGE)
        Debug.WriteLine("break");
};

断点永远不会被点击,表明消息没有进入消息泵。在其他类型的应用程序中尝试相同的事情会产生成功。注入这些消息我做错了什么。

2 个答案:

答案 0 :(得分:1)

不幸的是,您需要在WPF应用程序中明确覆盖WndProc方法,以便接收Windows消息 - 请参阅here

HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));

显然,如果不重新编译源代码就不能这样做,所以你需要另一种方式。

<强>被修改

我之前建议EasyHook将原始方法处理程序的重定向注入到您选择的某些代码中。正如评论所说,这不会解决问题,因为原始应用程序仍然不会收到Windows消息。欢迎使用UI自动化的建议。

答案 1 :(得分:1)

我想在这里做一个更详细的回复,但是时间紧迫我在这里总结一下。我确实找到了其他一些想要做同样事情的人。

处理Windows消息的WPF类会执行其他检查。如果接收到鼠标消息而不是处理鼠标消息中的信息,WPF将再次调用查询鼠标光标以查看其实际位置,它将检查它是否确实具有焦点,等等(类似的检查是完成一些其他输入消息)。如果根据WPF类库中的注释,这些检查中的任何一个失败,则假定发生了一些导致WPF错误地获取消息的情况。通过确保WPF应用程序具有焦点,我能够为我的场景工作。

此外,我不得不做一些我不建议任何人做过的事情,比如制作代理User32.dll来覆盖一些WPF行为。这适用于我的目的,但仅适用于单个操作系统版本。幸运的是,我的目标机器不会连接到互联网,需要执行一年左右的任务,并且在其隔离的环境中不会收到任何操作系统更新; Windows Update可以轻松杀死此解决方案