【问题标题】:Injecting Messages into WPF Application Message Pump将消息注入 WPF 应用程序消息泵
【发布时间】:2016-09-14 21:00:48
【问题描述】:

我有一些预编译的 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(效果很好)。然后我使用 SendMessagePostMessage 来发送我的消息。而其他应用程序对此 WPF 应用程序没有响应。作为另一项测试,我制作了一个 WPF 应用程序并添加了一些代码,以便在收到特定消息时设置断点。

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

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

【问题讨论】:

  • 我不知道,但你这里有内存泄漏:LPWSTR windowName = new TCHAR[256];
  • UI Automation 可能是一个更好的解决方案,尽管我们不知道您真正想要完成什么。
  • 这里试图总结一下我在做什么:有一个应用程序正在捕获几个应用程序的视频输出(并非所有应用程序都在同一台机器上运行)并将它们混合在一起。当窗口被捕获时,它不能再接收鼠标和触摸消息。我希望管理所有这些的应用程序将这些消息路由到 WPF 应用程序。这已经适用于捕获窗口的 Win32 应用程序,而不是 WPF。

标签: c++ wpf winapi


【解决方案1】:

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

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

显然你不能在不重新编译源代码的情况下做到这一点,所以你需要另一种方式。


已编辑

我之前建议 EasyHook 将重定向从原始方法处理程序注入到您选择的某些代码。正如 cmets 正确指出的那样,这并不能解决问题,因为原始应用程序仍然不会收到 Windows 消息。欢迎提出使用 UI 自动化的建议。

【讨论】:

  • 我计划发送的消息将是诸如 WM_KEYDOWN 之类的消息,我认为 WPF 应用程序已经能够处理常规键和鼠标方法。我现在正在针对一个测试应用程序尝试此操作,在该应用程序中我已经覆盖了消息泵处理程序,以便我可以看到发生了什么。它正在处理 Windows 消息,但我发送的消息没有通过它。不过会看看 EasyHook。
  • 是的,请查看 EasyHook。我们使用它通过将产生状态对话的调用重定向到存根来强制 FORTRAN 应用程序进入“静默模式”。辛苦了。
  • @Joel:“我打算发送WM_KEYDOWN之类的消息” - You can’t simulate keyboard input with PostMessage。使用 UI 自动化。 EasyHook 也不会有任何帮助。您没有尝试过滤传入的消息。您正在尝试伪造输入。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多