我有一些预编译的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");
};
断点永远不会被点击,表明消息没有进入消息泵。在其他类型的应用程序中尝试相同的事情会产生成功。注入这些消息我做错了什么。
答案 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可以轻松杀死此解决方案。