繁体   English   中英

Win32:将窗口置于顶部

[英]Win32: Bring a window to top

我有一个 Windows 程序,其中有两个 2 个窗口:

hwnd (main interface)

hwnd2 (toplevel window, no parent, created by hwnd)

当我双击hwnd时,我需要hwnd2弹出并显示一些数据,所以我使用这个函数将hwnd2带到顶部:

BringWindowToTop(hwnd2);

hwnd2 被带到了顶部,但有一点很奇怪。 当我再次点击 hwnd2 时,hwnd(主界面)再次自动弹出。 我尝试使用以下函数来解决这个问题,但它们都不起作用。

SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                                                  //doesn't work

BringWindowToTop(hwnd2);    //This is the function brings hwnd2 to top

SetForegroundWindow(hwnd2); //doesn't work

SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 
                                                                  //doesn't work

SetWindowPos(hwnd2, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
                                       // hwnd2 "always" on top, not what I want

SetActiveWindow(hwnd2); // doesn't work too (for replying to Magnus Skog, thanks)

SwitchToThisWindow(hwnd2, TRUE);// got the same problem with BringWindowToTop function
SwitchToThisWindow(hwnd2, FALSE);

我怎么能解决这个问题? 提前致谢。

(为了回复aJ,hwnd2没有父级,因为它需要是一个顶层窗口,所以它可以在其他窗口的前面/后面)

(hwnd2 是一个媒体播放器,由多个窗口组成,其中一个窗口用于视频显示,另外两个轨迹栏控件用于进度条和音量条,一个工具栏控件用于控制面板。)

(有一个这可能会有所帮助,无论我单击 hwnd2 的哪个窗口,hwnd 都会自动弹出“鼠标在 Z 顺序中位于 hwnd 的顶部”,包括菜单栏和非客户区等)

(这个媒体播放器是用Direct Show写的。我使用IVideoWindow::put_Owner把视频窗口作为视频所有者,Direct Show内部创建了一个子视频窗口作为视频窗口的子窗口。除了这个子视频窗口是我看不到源代码,我在 hwnd2 中没有看到任何可疑的东西。)

我找到了原因,这是因为Direct Show。 我使用多线程执行它,然后问题解决了。 但为什么??

这个问题可以通过使用 PostMessage(而不是 SendMessage)来解决。

试试这个,据说来自M$

    HWND hCurWnd = ::GetForegroundWindow();
    DWORD dwMyID = ::GetCurrentThreadId();
    DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
    ::AttachThreadInput(dwCurID, dwMyID, TRUE);
    ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    ::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
    ::SetForegroundWindow(m_hWnd);
    ::SetFocus(m_hWnd);
    ::SetActiveWindow(m_hWnd);
    ::AttachThreadInput(dwCurID, dwMyID, FALSE);

为了把一个窗口带到顶部,你应该得到你的窗口句柄,线程句柄,在前台的窗口线程句柄

然后我们将我们的线程附加到前台窗口线程并通过 AttachThreadInput 获取输入,然后我们将我们的窗口 z 顺序设置为最顶层,然后将其 z 顺序恢复为正常,调用 SetForegroundWindow,SetFocus,SetActiveWindow 以确保我们的窗口被带到顶部并且是活跃且专注

然后从旧的前台窗口线程中分离输入队列,使我们的线程成为唯一捕获输入事件的线程

那么我们为什么要调用AttachThreadInput,那是因为

SetFocus 将键盘焦点设置到指定的窗口。 该窗口必须附加到调用线程的消息队列。

AttachThreadInput 有什么作用?

AttachThreadInput 函数可用于允许一组线程共享相同的输入状态。 通过共享输入状态,线程共享其活动窗口的概念。 通过这样做,一个线程总是可以激活另一个线程的窗口。 此函数对于在共享输入状态的不同线程创建的窗口之间共享焦点状态、鼠标捕获状态、键盘状态和窗口 Z 顺序状态也很有用。

我们使用 SetWindowPos 将窗口带到最顶层,如果窗口隐藏,则使用 SWP_HIDEWINDOW 显示窗口

SetWindowPos 函数更改子窗口、弹出窗口或顶级窗口的大小、位置和 Z 顺序。 这些窗口根据它们在屏幕上的外观进行排序。 最顶层的窗口获得最高等级,并且是 Z 顺序中的第一个窗口

如果你的问题是你的窗口也被最小化了,你应该在最后添加一行代码

ShowWindow(m_hWnd, SW_RESTORE);

两者都很好用:

::SetForegroundWindow(wnd)

要么

::SetWindowPos(m_hWnd,       // handle to window
            HWND_TOPMOST,  // placement-order handle
            0,     // horizontal position
            0,      // vertical position
            0,  // width
            0, // height
            SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE// window-positioning options
            );

但请记住,最后一个将窗口始终设置在顶部。

经过多次尝试和错误,我找到了以下解决此问题的方法:

SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // restore the minimize window
SetForegroundWindow(hwnd); 
SetActiveWindow(hwnd); 
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE  | SWP_NOSIZE);
//redraw to prevent the window blank.
RedrawWindow(hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN );

hwnd 是您的 windows HWND 。 请不要只是复制和粘贴。 您还需要使用GetLastError在每次 api 调用后检查 api 错误。

我在我的 win7 上确认了以下结果:

  • 可以恢复最小化窗口并且没有错误返回。
  • 如果窗口已经置顶,则窗口标题会闪烁并且不会返回错误。
  • 如果窗口已关闭,它将返回错误“0x578 无效的窗口句柄”。
  • 它可以将窗口带到所有不是最顶层的窗口的顶部并且没有错误返回。(例如它会在最顶层的任务管理器后面)
  • 它不会使窗口位于最顶部。 用户可以在它上面制作其他窗口。

SwitchToThisWindow最适合我。

SwitchToThisWindow()根本不被弃用。
我在生产环境中使用了14年。
查看Windows源代码,您将看到它在任何地方都被称为...

你试过SetActiveWindow()吗?

如果最小化,这将恢复应用程序并将其置于最前面:

ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);

//效果很好!

Var
 WndHandle:HWND;

begin
 WndHandle :=FindWindowEx(0,0,nil,'Calculator');
 PostMessage(WndHandle,WM_SHOWWINDOW,SW_RESTORE,0);
 SetForegroundWindow(WndHandle);
end; 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM