9

我正在开发一个消息传递工具。消息窗口是整个应用程序的一部分。当有一些消息到来时,我需要窗口转到前面。我正在使用这段代码:

    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;

我什至试图做一个TOPMOST,但在某些情况下它仍然不起作用。我还尝试了 ::BringToFront()。

任何人都可以帮助或解释为什么它不起作用?这是一个已知的微软限制。

4

2 回答 2

11

系统限制哪些进程可以设置前台窗口。只有当下列条件之一为真时,进程才能设置前台窗口:

  • 该进程是前台进程。
  • 该进程由前台进程启动。
  • 进程收到最后一个输入事件。
  • 没有前台进程。
  • 正在调试前台进程。
  • 前景未锁定(请参阅 LockSetForegroundWindow)。
  • 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有菜单处于活动状态。

有关更多详细信息,请参阅SetForegroundWindow()文档

于 2013-10-02T12:04:33.640 回答
8

在Win32 API的官方文档中,有备注:

备注 系统限制哪些进程可以设置前台窗口。只有当下列条件之一为真时,进程才能设置前台窗口:

  • 该进程是前台进程。
  • 该进程由前台进程启动。
  • 进程收到最后一个输入事件。
  • 没有前台进程。
  • 正在调试进程。
  • 前台进程不是现代应用程序或开始屏幕。
  • 前景未锁定(请参阅 LockSetForegroundWindow)。
  • 前台锁定超时已过期(请参阅 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有菜单处于活动状态。

但是有一个技巧可以将窗口强制为前台:

诀窍是通过附加线程(使用 AttachThreadInput API)和使用替代 API:BringWindowToTop,让窗口“认为”我们的进程和目标窗口(hwnd)相关。

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);
}

原来的答案在这里

PS:如果出现某些消息,我也不认为您应该将消息应用程序置于顶部,但仍然......这是适用于我在 Windows 10 上的 Qt 应用程序的解决方案

于 2020-01-09T07:55:30.723 回答