Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Win32 ::SetForegroundWindow() not working all the time

I'm working on a messenging tool. The messaging window is part of a whole application. I need the window to go to the front when there are some messages coming. I'am using this code :

    if( m_hwnd == NULL || !::IsWindow(m_hwnd) )
        return E_UNEXPECTED;

    if(::IsIconic(m_hwnd))
    {
        ::ShowWindowAsync( m_hwnd, SW_RESTORE );
    }
    ::SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
    ::SetForegroundWindow(m_hwnd);
    if( pvbProcessed != NULL )
        *pvbProcessed = VARIANT_TRUE;

    return S_OK;

I even tried to do a TOPMOST but still in some cases it does not work. I also Tried a ::BringToFront().

Anyone can help or give an explanation on why it doen not work ? Is it a known microsoft limitation.

like image 989
samitriani Avatar asked Oct 02 '13 11:10

samitriani


2 Answers

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 foreground process is being debugged.
  • The foreground is not locked (see LockSetForegroundWindow).
  • The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • No menus are active.

See the SetForegroundWindow() docs for more details.

like image 123
Jonathan Potter Avatar answered Nov 15 '22 16:11

Jonathan Potter


In the official document of Win32 API, there are remarks:

Remarks 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.

But there is a trick to force a window to foreground:

The trick is to make windows ‘think’ that our process and the target window (hwnd) are related by attaching the threads (using AttachThreadInput API) and using an alternative API: BringWindowToTop.

void CommonHelpers::forceForegroundWindow(HWND hwnd) {
    DWORD windowThreadProcessId = GetWindowThreadProcessId(GetForegroundWindow(),LPDWORD(0));
    DWORD currentThreadId = GetCurrentThreadId();
    DWORD CONST_SW_SHOW = 5;
    AttachThreadInput(windowThreadProcessId, currentThreadId, true);
    BringWindowToTop(hwnd);
    ShowWindow(hwnd, CONST_SW_SHOW);
    AttachThreadInput(windowThreadProcessId,currentThreadId, false);
}

The original answer is here

P.S: I also dont think you should bring your message app to top if some message is coming up, but still ... this is the solution that working for my Qt App on Windows 10

like image 37
hungson175 Avatar answered Nov 15 '22 16:11

hungson175