Correct way (in .NET) to switch the focus to another application

Viewed 80485

This is what I have so far:

Dim bProcess = Process.GetProcessesByName("By").FirstOrDefault
If bProcess IsNot Nothing Then
    SwitchToThisWindow(bProcess.MainWindowHandle, True)
Else
    Process.Start("C:\Program Files\B\B.exe")
End If

It has two problems.

  1. Some people have told me that SwitchToThisWindow is deprecated.
  2. If application B is minimized, this function silently fails from the user's perspective.

So what's the right way to do this?

8 Answers

Get the window handle (hwnd), and then use this user32.dll function:

VB.net declaration:

Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer 

C# declaration:

[DllImport("user32.dll")] public static extern int SetForegroundWindow(int hwnd) 

One consideration is that this will not work if the window is minimized, so I've written the following method which also handles this case. Here is the C# code, it should be fairly straight forward to migrate this to VB.

[System.Runtime.InteropServices.DllImport("user32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);

private enum ShowWindowEnum
{
    Hide = 0,
    ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
    Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
    Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
    Restore = 9, ShowDefault = 10, ForceMinimized = 11
};

public void BringMainWindowToFront(string processName)
{
    // get the process
    Process bProcess = Process.GetProcessesByName(processName).FirstOrDefault();

    // check if the process is running
    if (bProcess != null)
    {
        // check if the window is hidden / minimized
        if (bProcess.MainWindowHandle == IntPtr.Zero)
        {
            // the window is hidden so try to restore it before setting focus.
            ShowWindow(bProcess.Handle, ShowWindowEnum.Restore);
        }

        // set user the focus to the window
        SetForegroundWindow(bProcess.MainWindowHandle);
    }
    else
    {
        // the process is not running, so start it
        Process.Start(processName);
    }
}

Using that code, it would be as simple as setting the appropriate process variables and calling BringMainWindowToFront("processName");

This work for me

[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool turnOn);
[STAThread]
        static void Main()
        {
            Process bProcess = Process.GetProcessesByName(processnamehere).FirstOrDefault() ;
            if (bProcess != null)
                    {
                        SwitchToThisWindow(bProcess.MainWindowHandle, true);
                    }
                GC.Collect();
        }   

Following worked for me, when I tried for applications like SQL Server Management Studio and Visual Studio, running as Administrator, using the exe got from the following code.

Toggle Helper

public class ToggleHelper
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
    private static extern bool ShowWindow(IntPtr hWnd, EnumForWindow enumVal);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern int SetForegroundWindow(IntPtr hwnd);

    private enum EnumForWindow
    {
        Hide = 0,
        ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
        Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
        Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
        Restore = 9, ShowDefault = 10, ForceMinimized = 11
    };

    public void SetForeGroundMainWindowHandle(string processName)
    {

        Console.WriteLine("SetForeGroundMainWindowHandle Called - for "+ processName);
        Process p = Process.GetProcessesByName(processName).FirstOrDefault();

        if (p != null)
        {
            Console.WriteLine(p.MainWindowHandle.ToString());
            ShowWindow(p.MainWindowHandle, EnumForWindow.Restore);
            System.Threading.Thread.Sleep(5000);
            ShowWindow(p.MainWindowHandle, EnumForWindow.ShowMaximized);
            //System.Threading.Thread.Sleep(5000);
            SetForegroundWindow(p.MainWindowHandle);
        }
        else
        {
            Process.Start(processName);
        }
    }
}

Client

class Program
{
    static void Main(string[] args)
    {
        //RUN AS Administrator
        var y = Process.GetProcesses().Where(pr => pr.MainWindowHandle != IntPtr.Zero);
        foreach (Process proc in y)
        {
            Console.WriteLine(proc.ProcessName);
        }

        ToggleHelper t = new ToggleHelper();

        int a = 0;
        while (a <= 1)
        {
            t.SetForeGroundMainWindowHandle("Ssms");
            System.Threading.Thread.Sleep(30000);
            t.SetForeGroundMainWindowHandle("devenv");
            System.Threading.Thread.Sleep(18000);
        }
        Console.ReadLine();
    }
}
Related