10

I'm using SetForegroundWindow API in .NET using PInvoke.

When I use the API while debugging in Visual Studio its works perfectly. But it doesn't work always when the application is running normally.

I put some logs just before a call to SetForegroundWindow and its confirmed that the API is getting called but doesn't take effect at times. I have also seen a couple of posts regarding this issue but I want to know why is it failing.

The links of the post are a follows:

Community
  • 1
  • 1
Aster Veigas
  • 866
  • 3
  • 13
  • 34
  • 2
    For the benefit of searchers, I moved this to be in a Task and it fixed my problem. Not posting as an answer as it could be specific to my appication. Still, might help someone - Task.Factory.StartNew(() => { SetForegroundWindow(windowHandle); }); – JsAndDotNet Aug 31 '16 at 16:13

4 Answers4

13

In fact this is a pure Win32 issue rather than a .net specific issue. The .net framework stands on top of Win32 and here the rules of Win32 are being reflected on to you.

The documentation for SetForegroundWindow gives a comprehensive explanation of the issue you face. Essentially the issue facing the design of SetForegroundWindow is that it can be used for focus stealing. Focus is something that users should control. Applications that change the focus can be troublesome. And so SetForegroundWindow attempts to defend against focus stealers.

The documentation says:

The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:

  • The process is the foreground process.
  • The process was started by the foreground process.
  • The process received the last input event.
  • There is no foreground process.
  • The process is being debugged.
  • The foreground process is not a Modern Application or the Start Screen.
  • The foreground is not locked (see LockSetForegroundWindow).
  • The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • No menus are active.

An application cannot force a window to the foreground while the user is working with another window. Instead, Windows flashes the taskbar button of the window to notify the user.

You are almost surely falling foul of these criteria. Note that a process that is being debugged is always granted permission to set foreground window. That explains why you see no problems whilst debugging. But outside a debugger, if your process is not the foreground process, then calls to SetForegroundWindow fail.

This is all by design. Your reaction to this should be to try to come up with a design that doesn't require you to attempt to call SetForegroundWindow when your process is not the foreground process.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Getlasterror returns 0. But with the help of logs I found out that SetForegroundWindow is failing. So what can be done? I tried SwitchToThisWindow API as well and din't find success. The link I posted was performing AttachThreadInput but I saw an issue there. The issue is that the system can slow down which is reported on that link – Aster Veigas Dec 07 '13 at 19:10
  • 2
    I'm not sure I can explain it any more clearly. If your process is not the foreground process, then it cannot expect to be able to influence the foreground window. The solution is to either be the foreground process, or to give up attempting to modify the foreground process. And no, don't call `AttachThreadInput`. That leads to pain. – David Heffernan Dec 07 '13 at 19:12
5

The trick is to 'fool' windows (not trying to talk in pleonasms) and attach the input to the new thread to which the window-to-focus belongs, I took most of this from the pinvoke website but added a test to restore minimized windows:

private const uint WS_MINIMIZE = 0x20000000;

private const uint SW_SHOW     = 0x05;
private const uint SW_MINIMIZE = 0x06;
private const uint SW_RESTORE  = 0x09;

public static void FocusWindow(IntPtr focusOnWindowHandle)
{
    int style = GetWindowLong(focusOnWindowHandle, GWL_STYLE);

    // Minimize and restore to be able to make it active.
    if ((style & WS_MINIMIZE) == WS_MINIMIZE)
    {
        ShowWindow(focusOnWindowHandle, SW_RESTORE);
    }

    uint currentlyFocusedWindowProcessId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
    uint appThread = GetCurrentThreadId();

    if (currentlyFocusedWindowProcessId != appThread)
    {
        AttachThreadInput(currentlyFocusedWindowProcessId, appThread, true);
        BringWindowToTop(focusOnWindowHandle);
        ShowWindow(focusOnWindowHandle, SW_SHOW);
        AttachThreadInput(currentlyFocusedWindowProcessId, appThread, false);
    }

    else
    {
        BringWindowToTop(focusOnWindowHandle);
        ShowWindow(focusOnWindowHandle, SW_SHOW);
    }
}
Erlend Robaye
  • 181
  • 2
  • 3
3

Register a Hot Key with RegisterHotKey. Choose carefully the Hot Key, as you must not interfere with existing (or future) application.

When you need to steal the focus (but remember it's BAD), simulate the Hot Key with SendInput.

Then, you will receive a WM_HOTKEY message, and during the processing of that message, you will be allowed to use SetForegroundWindow (I mean, it will success).

You will have to store/remenber somewhere the HWND of the window to activate, between the call to SendInput and your processing of WM_HOTKEY, which is posted.

References: Pressing a registered hotkey gives you the foreground activation love

manuell
  • 7,528
  • 5
  • 31
  • 58
-2

David was right and led me to the right direction . Followed the code project article which says "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"

How to bring window to top with SetForegroundWindow()

Aster Veigas
  • 866
  • 3
  • 13
  • 34
  • Are you sure your application is the foreground process when you call `SetForegroundWindow`? What makes you think some other app is calling `LockSetForegroundWindow`? – David Heffernan Dec 07 '13 at 21:31
  • The other app on the foreground was IE in my case,could also see this case in notepad. I had kept logs and was checking the return value of setforegroundwindow and in some cases it was returning false and also getlasterror was returning 0. It is definitely a focus issue – Aster Veigas Dec 07 '13 at 21:43
  • 2
    I still don't think you quite understand. If IE is the foreground process, you can't expect `SetForegroundWindow` to have any effect. IE certainly does not need to call `LockSetForegroundWindow` and I'd be surprised if it did. All it needs to do is **be** the foreground process, and other processes cannot change the foreground process. – David Heffernan Dec 07 '13 at 21:46
  • 1
    When IE is on top and there is no input to IE at all.Setforegroundwindow works fine its only when an IE receives an input it doesn't work always. But the alt key simulation solves this problem – Aster Veigas Dec 07 '13 at 22:02
  • The accepted solution obviously doesn't work. I know it is too late now, but for whoever might face the same issue and come to this page, on the link below, an actual working solution (with a disclaimer at the top of the article) can be found. It works perfectly for me (again, have in mind the disclaimer at the top of the article). https://shlomio.wordpress.com/2012/09/04/solved-setforegroundwindow-win32-api-not-always-works/ – aleksandaril Feb 13 '22 at 11:29
  • Well it did work for me and still does. You might be facing another issue – Aster Veigas Feb 14 '22 at 03:40