Issue with SetForegroundWindow in .NET

后端 未结 4 677
伪装坚强ぢ
伪装坚强ぢ 2021-01-02 07:17

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

相关标签:
4条回答
  • 2021-01-02 07:30

    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

    0 讨论(0)
  • 2021-01-02 07:31

    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);
        }
    }
    
    0 讨论(0)
  • 2021-01-02 07:37

    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()

    0 讨论(0)
  • 2021-01-02 07:49

    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.

    0 讨论(0)
提交回复
热议问题