Search code examples
c#.netwinformssetfocussetforegroundwindow

How to focus a process window over a running webbrowser window in c#?


I have a small Windows Forms program (agent) running in the Systray. The purpose of this agent written in C# is to start other programs, focus them and putting them into the foreground.

This agent receives the commands to start other programs from the browser and reports the successful start back to it. This means the browser is always up and running.

Starting external programs from the agent is working fine, but I have much trouble to get the focus and foreground topic to work. It seems like the browser is always in focus and the programs started from the agent are moved right behind the browser window.

I have tried the following methods from the User32.dll without success:

  • SetForegroundWindow(IntPtr handle)
  • SwitchToThisWindow(IntPtr hWnd, bool fAltTab)

The strange thing is that if I am running the agent in my Visual Studio the focus works perfect!

Help is much appreciated, since I am new to windows internals.

Update 1: I noticed if for instance a powershell window (could be anything arbitrary) lays over the browser window, focusing the started process window works as expected.

Update 2: I was able to get the right focus by calling

SetWindowPos(browserProcess.MainWindowHandle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

on the browser process window and

SetWindowPos(process.MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

on the started process window. But I think this is a bad approach since the browser window may vanish behind other open windows. I have also tried

SetWindowPos(browserProcess.MainWindowHandle, process.MainWindowHandle, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

to switch the Z order of the browser window and the process window, but without success.

Question: How I can switch the Z order of the browser process and the started process?


Solution

  • Seems like SendKeys.SendWait("%"); was the magic I needed.% is the ALT key.

    From the documentation of LockSetForegroundWindow

    The system automatically enables calls to SetForegroundWindow if the user presses the ALT key or takes some action that causes the system itself to change the foreground window (for example, clicking a background window).

    Calling AllowSetForegroundWindow returned FALSE in the first place so I was not able to set the foreground window. A call to GetLastError revealed the error code ERROR_ACCESS_DENIED. Calling SendKeys.SendWait("%") before User32dll.SetForegroundWindow(windowHandle) enables calls to SetForegroundWindow to be successful.

    To put it together it looks like this:

    var windowHandle = User32dll.FindWindow(null, nameOfWindow);
    SendKeys.SendWait("%");
    User32dll.SetForegroundWindow(windowHandle);
    

    If the window is minimized, using User32dll.ShowWindow(windowHandle, User32dll.SW_RESTORE) is sufficient.