views:

292

answers:

2

I'm trying to find a reliable way to activate / set focus to a window of an external application using C#. Currently I'm attempting to achieve this using the following Windows API calls:

SetActiveWindow(handle);
SwitchToThisWindow(handle, true);

Previously I also had ShowWindow(handle, SW_SHOWMAXIMIZED); executing before the other 2, but removed it because it was causing strange behavior.

The problem I'm having with my current implementation is that occasionally the focus will not be set correctly. The window will become visible but the top part of it will still appear grayed out as if it wasn't in focus.

Is there a way to reliably do this which works 100% of the time, or is the inconsistent behavior a side-effect I can't escape? Please let me know if you have any suggestions or implementations that always work.

+1  A: 

If it's all internal in your application then you can get the parent window or that window, and in this way activate it (vb sorry):

Public Class Form1 : Inherits Form

    Protected Overrides Sub OnLoad(e As EventArgs)
        Dim form2 As New Form2
        form2.Show()
    End Sub
End Class

Class Form2 : Inherits Form

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        Me.Owner.Activate()
    End Sub
End Class
Shimmy
Unfortunately it is not within my application. It's an external application which I cannot access the code of. I will clarify in my post. Thanks for your effort.
gtaborga
+2  A: 

You need to use AttachThreadInput

Windows created in different threads typically process input independently of each other. That is, they have their own input states (focus, active, capture windows, key state, queue status, and so on), and they are not synchronized with the input processing of other threads. By using the AttachThreadInput function, a thread can attach its input processing to another thread. This also allows threads to share their input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread. This also allows threads to get key-state information. These capabilities are not generally possible.

I am not sure of the ramifications of using this API from (presumably) Windows Forms. That said, I've used it in C++ to get this effect. Code would be something like as follows:

     DWORD currentThreadId = GetCurrentThreadId();
     DWORD otherThreadId = GetWindowThreadProcessId(targetHwnd, NULL);
     if( otherThreadId == 0 ) return 1;
     if( otherThreadId != currentThreadId )
     {
       AttachThreadInput(currentThreadId, otherThreadId, TRUE);
     }

     SetActiveWindow(targetHwnd);

     if( otherThreadId != currentThreadId )
     {
       AttachThreadInput(currentThreadId, otherThreadId, FALSE);
     }

targetHwnd being the HWND of the window you want to set focus to. I assume you can work out the P/Invoke signature(s) since you're already using native APIs.

Logan Capaldo
Your post was very informative. Thank you so much. I will try this as soon as I get a chance to. I've got the P/Invoke signatures down, I just never really understood the full picture behind the input queues but you put it quite clearly. :)
gtaborga