Reputation: 2361
I've got some pre-compiled WPF applications that I need to control without recompiling them by sending various messages (ex:WM_POINTERMOVE, WM_KEYDOWN, so on). The method of control that I have attempted was to inject messages into the applications message pump. As a test I attempted this with some other Win32 applications by getting the windows handle for the application and then using SendMessage to send messages.
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);
I retrieved the HWND for the application using EnumWindows (that works just fine). Then I use SendMessage and PostMessage to send my messages. While other applications respond to this WPF apps dont. As another test I made a WPF application and added some code so I could set a break point when it received a certain message.
ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
{
if(msg.message == MY_MESSAGE)
Debug.WriteLine("break");
};
The breakpoint is never hit indicating the messages are not making their way into the message pump. Attempting the same thing in other types of applications yield success. What am I doing wrong with injecting these messages.
Upvotes: 4
Views: 1370
Reputation: 2361
I want to put a more detailed response here but being short on time I'm putting a summary here. I did find a few others that were looking to do the same thing.
The WPF classes that handle windows messages do additional checks. If a mouse message is received instead of processing the information in the mouse message WPF will make another call to query the mouse cursor to see where it really is, it will check to see if it really has focus, and so on (similar checks are done for some other input messages). If any of these checks fail according to the comments in the WPF class libraries it is assumed that some condition occurred that caused the WPF to get the message by mistake. I was able to get things working for my scenario by ensuring the WPF application had focus.
Additionally I had to do some things that I would not suggest that any one ever do, such as making a proxy User32.dll for overriding some of the WPF behaviours. This worked for my purposes but only works on a single operating system version. Luckily my target machine will not be connected to the Internet and needs to perform it's task for a year or so and won't receive any OS updates in it's isolated environment; a Windows Update could easily kill this solution.
Upvotes: 2
Reputation: 2942
Unfortunately you need to explicitly override the WndProc
method in your WPF application like below in order to receive Windows messages - see here.
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
Obviously you can't do this without recompiling the source, so you need another way.
Edited
I previously suggested EasyHook to inject a redirect from the original method handler to some code of your choice. As comments rightly stated, this would not solve the problem as the original application would still not receive Windows messages. Suggestions to use UI Automation are welcomed.
Upvotes: 1