views:

832

answers:

2

Hello,

I need to get the Handler to the child Window of a certain application that is running. I have the main window handler, but I need to know which specific child window is active, in order to use the SendMessage/PostMessage.

I finally managed to do this using the following code, using firefox:

    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    [DllImport("user32.dll", EntryPoint = "GetGUIThreadInfo")]
    internal static extern bool GetGUIThreadInfo(uint idThread, out GUITHREADINFO threadInfo);


    private void button1_Click(object sender, EventArgs e)
    {
        //start firefox
        firefox = new Process();
        firefox.StartInfo.FileName = @"C:\Program Files\Mozilla Firefox\firefox.exe";
        firefox.Start();
        Thread.Sleep(10000);

        // get thread of the main window handle of the process
        var threadId = GetWindowThreadProcessId(firefox.MainWindowHandle, IntPtr.Zero);

        // get gui info
        var info = new GUITHREADINFO();
        info.cbSize = (uint)Marshal.SizeOf(info);
        if (!GetGUIThreadInfo(threadId, out info))
            throw new Win32Exception();


        // send the letter W to the active window
        PostMessage(info.hwndActive, WM_KEYDOWN, (IntPtr)Keys.W, IntPtr.Zero);

    }

This works very well! However, if the application is not active, for example, if notepad is covering firefox, the GUIThreadInfo comes with every member null. Only if firefox is the top-most (active) application of windows, will the structure be filled.

I know this could be fixed by bringing firefox to the foreground but I needed to avoid doing this. Does anyone have any other idea to get the active child window of an application that is not the top-most window in Windows?

Thanks

+1  A: 

If you have the topmost window handle for the process, you should be able to use GetTopWindow to receive the window at the top of the Z order. This should be the window that would be active if the application were set to be the active/current app.


Edit:

What about using AttachThreadInput to attach your thread to the other process thread?

Once you've done that, GetFocus() and PostMessage()/SendMessage() should work. Just make sure you detach the input when you're done.

The only sample I can find of this is unfortunately in Delphi, but would be easy to translate.

Reed Copsey
It doesn't work, always returns the same handler, doesn't matter if the focus is on the child window with the search box of the google page or the child window with the address bar
Noyoudont
I think the reason is that the mainWindow of firefox has one child. This child is where the address bar is. But this child also has a child, and that's where the google page is.So I think that the GetTopWindow doesn't work in depth, just checks the childs of the parent window (not the grandchilds, etc), so it always returns the same handler...
Noyoudont
@Noyoudont: See the approach in the sample above. It uses AttachThreadInput to work around this issue, and is probably a much more reliable approach. IF you need me to translate this to C#, let me know.
Reed Copsey
I didn't get any progress with that solution because unfortunately, it still requires the application to be active... If I minimize the application, or put another application in front, the GetFocus returns a null handler =(Any other idea?
Noyoudont
Not really - other than potentially tracking the current active app, switching firefox to be active (so GetFocus works), then switching back afterwards. I was under the impression that this worked, though, since attaching your thread's input to that app basically makes it active, even if it's in the background...
Reed Copsey
A: 

You could consider obtaining the child window handle using the GetWindow Function (hWnd, GW_CHILD) and Post the message on this handle.

Also be aware that on Microsoft Windows Vista and later. Message posting is subject to User Interface Privilege Isolation (UIPI). The thread of a process can post messages only to message queues of threads in processes of lesser or equal integrity level.

atVelu