Issue with SetForegroundWindow in .NET
Asked Answered
X

4

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:

Xeres answered 7/12, 2013 at 18:9 Comment(1)
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); });Chew
X
-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()

Xeres answered 7/12, 2013 at 21:13 Comment(6)
Are you sure your application is the foreground process when you call SetForegroundWindow? What makes you think some other app is calling LockSetForegroundWindow?Ideatum
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 issueXeres
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.Ideatum
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 problemXeres
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). shlomio.wordpress.com/2012/09/04/…Ketty
Well it did work for me and still does. You might be facing another issueXeres
I
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.

Ideatum answered 7/12, 2013 at 18:59 Comment(2)
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 linkXeres
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.Ideatum
R
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);
    }
}
Review answered 30/3, 2017 at 13:47 Comment(0)
C
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

Contorted answered 7/12, 2013 at 20:35 Comment(2)
I love this answer. It's been the most robust solution of everything else I've tried.Rowney
@JohnMeschke Thanks. I just fixed the dead link to The Old New Thing.Contorted
X
-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()

Xeres answered 7/12, 2013 at 21:13 Comment(6)
Are you sure your application is the foreground process when you call SetForegroundWindow? What makes you think some other app is calling LockSetForegroundWindow?Ideatum
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 issueXeres
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.Ideatum
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 problemXeres
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). shlomio.wordpress.com/2012/09/04/…Ketty
Well it did work for me and still does. You might be facing another issueXeres

© 2022 - 2024 — McMap. All rights reserved.