Background
I am currently trying to develop some test software that needs to be notified of window creation and activation events across the desktop, respond to these and walk widget trees in order to read all available text on those windows. This needs to work across 32 bit and 64 bit and from XP upwards ideally (sigh), but certainly 7 upwards.
What I've Done So Far
I have got a working a SetWindowsHookEx()
style system hook registered for WH_CBT
messages and I specifically process HCBT_ACTIVATE
and HCBT_CREATEWND
events. The hook is done in a DLL and there's a hooking program that controls it. The program is available and run for both 32 bit and 64 bit (as HCBT
messages don't seem to be routed back to the hooking process for different architectures (32/64 bit) unlike say keyboard messages). The software is all written in unmanaged C++ code, i.e. no dependency on CLI, and the program is a console app.
When I receive either of the two above events I then call EnumChildWindows()
with the given HWND
handle and call GetWindowText()
on each window. The results are currently written out to individual log files based upon PID.
This all works as expected but only goes so far...
The Problem
If I run up say MSVS I can see the top level stuff and even the text contents of `are you sure you want do that' simple warning dialogs, but for the options dialog all I get is the OK and Cancel window widgets and a few untitled windows.
Reading up on this I believe the reason is that I'm seeing a transition from old school Win32 API widgets to WPF control widgets.
Assumptions/Requirements
- This is due to a Win32 to WPF transition.
- Being a
SetWindowsEx()
style hook injected into each process from a DLL this has to be unmanaged code (i.e. you can't merrily start up the CLI inside some random process and use managed code). - The WPF library examples all use managed code.
- It has been observed that some applications don't use the accessibility API and so hooking that has been discounted by me.
- I need to cut down dependencies as much as possible as the systems under test have to be as representative as possible (I know, I'm injecting code everywhere, but that can't be helped). I don't want to have to install additional large runtimes etc if I can help it.
- During testing, UAC will be on at it's default level.
Questions
- Is there any way of traversing WPF widget hierarchies from unmanaged C++ code inside the DLL? Presumably there must be some sort of native/unmanaged API I could call?
- Failing this, is it possible to forward
HWND
handles to another process, say viaWM_COPYDATA
and a hidden window, that is actually a managed process that can then walk the widget tree on behalf of the injected DLL, accessing the Win32 widgets, switching into WPF as and when needed? My research would seem to say that this isn't possible... - Would a process have permission to do (2) with UAC turned on?
Lastly I should say that I am a Unix/Linux GUI/systems/kernel software engineer by background and so apologize in advance if the above seems rather basic, but I just couldn't find answers for this particular use case. It's also my first MS-Windows program!
Many thanks in advance,
John.