Access Control Text on win32 application form from .NET - c#

In the past I've used the (P/Invoke) method GetWindowText to grab the window title text of a running application, regardless of it being Win32, .NET or otherwise.
What I'm trying to figure out is if there is a way to access text on actual controls, inside a form. I realize that this would probably be difficult and I will likely be address the controls by some random hex value or something and that it could break if the software every changes at all (it's something I have no control over). But, I'm just trying to do this to add some data polling to my media center setup and would like to be able to pull some information from a media player for which there is no API.
So, is there any sort of API (I'd imagine I would have to P/Invoke into it) that allows you to do this? Code examples would be greatly appreciated.

I believe GetWindowText takes the window handle as parameter, many controls ( but not all of them ) also have the window handle and you should be able to use the same API to get the text out of them.
How to get the handles of child controls is then another story but Win32 has all you need for it.

Send the WM_GETTEXT message to the control once you know its handle.
To work out its handle first of all use Spy++ or some such tool to find the name of the top level window and its window class name. Send this to FindWindow to get the top level window handle. Finally call EnumChildWindows to walk the children. Spy++ can also tell you how to identify which child is of interest.
Of course you may be unlucky and find that the control of interest is implemented without its own window handle, but Spy++ will tell you that too.

Related

Modifying owner drawn controls

I have a third party application I'm writing an add-in for and I need to be able to modify a specific dialog if possible. That dialog has many controls and groups that are .. it seems, owner drawn and thus don't expose window handles to tools like spy++ and others. I welcome any insight into how I might disable controls on the this dialog.
Since I am running in-process, I can use detours (https://www.microsoft.com/en-us/research/project/detours/) to intercept functions and use calls like enumwindows/enumchildwindows to find handles to controls that I can then use techniques like NativeWindow (C#) to override wndproc messages and do manipulation. I'm also familiar with setwindowshookex and hooking the message queues.
Just looking for some ideas and patterns for working with owner drawn controls. Thanks!
[Edit1] I am also familiar with the UI Automation (C#/C++) and IAccessible frameworks. Those will allow me some control (potentiall), like detecting mouse clicks and such, but I was hoping for something more elegant. For example: with a normal combobox, if I have a handle, I can use sendmessage() to send it CB_* messages to manipulate its contents. How do you do that with a combobox if you can't get the handle ... given that it is owner drawn (presumably) and part of another owner drawn parent.
thus don't expose window handles to tools like spy++ and others
Then they are not real controls as far as the OS is concerned, and so there is nothing you can do to access/manipulate them directly. The app would have to expose an API or UI Automation interface for them. Presumably the app will not provide more access than it really wants an add-on to have.
You should contact the app author for help fulfilling your goal.

Can I always be sure of the hierarchical order of controls found via FindWindowEx?

What am I doing?
I am automating a 3rd party application. The login window looks like this
Note: there is a background image embed within the form and both the USERNAME and PASSWORD are actually part of an image. Just in case anyone wonders why the below classes treeview from Window Detective doesn't have, possibly ยป Label controls.
Where am I at?
I don't have any problems getting handles of components. I mean, I can generally access each window/control using FindWindowEx function.
I can implement a GetWindowTextLength and/or GetWindowText functions for buttons to distinguish which one I have got a handle of. While this approach works fine with Buttons (.Caption) it would not benefit me when working with Edit controls. It seems that the Edit controls do not have any unique properties to distinguish which one is which. (correct me if I am wrong)...
The problem
Assume that I need to know at the compile stage which Edit control I am going to be handling, so I don't send a password to the username and other way around. There are only two but like I've said I'm not sure how to get the right one.
I wouldn't mind figuring it out at run-time but I am unsure of how to distinguish the difference without sending a message and actually visually identify which one is which...
Current solution
I wouldn't really call this a solution but for now I am relying only on the fact that each time I run my code I always get a handle of the second (password) Edit control as the first handle returned.
Question
Can I be 100% sure the second Edit control will always be returned first in the hierarchy returned by the FindWindowEx function?
If someone can confirm my idea than I'd already have had a solution BUT if I can't always expect the second Edit control to be returned then I would like to hear some insight on how to handle this situation.
Note: I didn't think any code is actually required for my question but if anyone would like to see the code then please leave a comment and I will add it to the question.
Thanks a lot for your time.
Each child HWND has a property called ID. Use GetWindowLongPtr( hWnd, GWLP_ID ) to get it. Depending on how the target application is coded, that ID may be a way to distinguish between child control. Knowing the ID you can get the child HWND with the GetDlgItem API (works fine when the parent is not a DialogBox, the API should have been called GetChildByID).
Beware: some target applications really use random/unreliable values for IDs.
It seems that there is a general consensus: Enumeration APIs rely on the Z-Order. See for example that SO answer (maybe making your question some sort of 'duplicate')
While some applications may "play" with the Z-Order of their child windows, in the standard case they won't, which means that the first created child window is at the top of the Z-order, and the last created one is at the bottom.

How can I read data from controls on window in a different application?

I have to write an application that observes another application and extracts information from the window. What is the best way to access windows from other applications and get data from their controls?
You'll need to P/Invoke the FindWindow and FindWindowEx functions to retrieve a handle to the other application's parent window and child controls.
Then you will need to use something like GetWindowText to access the text for a particular control.
Visit pinvoke.net for the definitions you'll need to call these functions from C#.
Be warned that this is not a completely straightforward pursuit. You should stop to consider whether you really have a good reason for wanting to do this, and if your goal couldn't be achieved in a simpler way.

C# Control at Mouse Location Outside of the Application

Is it possible to get a control at the current mouse location if its in a window not known by the application? (not in Application.OpenForms)
I implemented a low level mouse hook which can get the mouse location anywhere on the screen, but I can't seem to access controls outside of my application. What I want to be able to do is get a button in an OpenFileDialog. I can get a Handle to the dialog, but I can't get the control from the dialog using Control.FromHandle() since this only works for controls that are in the Application.
It's possible with the Win32 API. You need GetDlgItem() to get a handle to button you are looking for. Use Spy++ to find the control ID. An example of the kind of code you need is available in my post in this thread. That example is for an in-process dialog, it would work out-of-process as well.
Beware that your code is liable to break on the next version of Windows.
If you are trying to get a .NET Control, this is not possible. The reason for this is that the Control IS the HWND. With "HWND" here I mean the actual Windows window item. It is not possible to e.g. automatically wrap a new control instance around an existing window, much less as it's possible to get the Control instance from the other .NET application, if it were one.
If you are trying to insert a .NET Control into an OpenFileDialog, this also will not be possible because the OpenFileDialog is not a .NET form.
If you really want the HWND from the mouse location, you can use pinvoke to get it using the WindowFromPoint function.

Is it possible to sendkeys / Post Message directly to a HtmlElement rather than to a webbrowser control?

I would like to send keys to a c# web browser control element directly, not just the window with the correct focus.
Right now I am able to send a key using PostMessage and documentHandle and focus like this
i.e. Pseudo Code
HtmlElement el = getelement();
el.Focus();
IntPtr docptr = browser.Handle;
PostMessage(docptr,WM_KEYDOWN,1,0);
.... KEYCHAR, KEYUP..
I was wondering if anyone knows of any way to be able to do this in a background, so that the focus is not on the element. Basically is there a way to get a IntPtr to the HtmlElement itself, than use that instead in the PostMessage or SendKeys API rather than the browser handle/ptr.
You can't. Those are windowless controls, mouse/keyboard messages are handled by their parent window, and the parent only relay message for the active control.
This is the wrong way to go.
You can use the HtmlElement API to manipulate the element directly.
For precise instructions, please tell us what you're trying to do.
Have a look at things like WaitN and Selenium.
IE also has a good programming interface to control the browser.
But there are downsides...
I'm currently working on a program that uses image recognition and control of the mouse/keys to control a browser as I can only really do what I want with the visual representation.
However that will dominate the computer and need full control. Unless you run it in a virtual machine.
It took me a long time to find this, but you have to p/invoke GetWindow with the child command to repeatedly get child window handles until you get down to one that responds to GetClassName with "Internet Explorer_Server" or something like that.
Then PostMessage on that hWnd and the activeElement of the WebBrowser will recieve them. Make sure you have the WM_KEYUP in there as that seems to be the important one.

Categories

Resources