Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a reliable way to activate / set focus to a window using C#?

Tags:

c#

focus

windows

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.

like image 391
gtaborga Avatar asked Apr 19 '10 23:04

gtaborga


3 Answers

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.

like image 169
Logan Capaldo Avatar answered Oct 15 '22 17:10

Logan Capaldo


    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetForegroundWindow(IntPtr hWnd);

This one worked for me

like image 36
Guillaume Massé Avatar answered Oct 15 '22 19:10

Guillaume Massé


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
like image 22
Shimmy Weitzhandler Avatar answered Oct 15 '22 19:10

Shimmy Weitzhandler