C++ Win32:将窗口置于顶部

C++ Win32:将窗口置于顶部,c++,winapi,visual-c++,C++,Winapi,Visual C++,我有一个Windows程序,其中有两个窗口: hwnd (main interface) hwnd2 (toplevel window, no parent, created by hwnd) 当我双击hwnd时,我需要hwnd2弹出并显示一些数据,因此我使用此功能将hwnd2置于顶部: BringWindowToTop(hwnd2); hwnd2排名靠前,但有一件事很奇怪。当我再次单击hwnd2时,hwnd(主界面)会自动再次弹出。 我尝试使用下面的函数来解决这个问题,但没有一个有效 S

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

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将video window作为视频所有者,Direct Show在内部创建了一个子视频窗口作为视频窗口的子窗口。除了这个子视频窗口,我看不到源代码,我在hwnd2中没有看到任何可疑的东西。)

我找到了原因,这是因为直接表演。我使用多线程执行它,然后问题就解决了。但是…为什么


使用PostMessage(而不是SendMessage)可以解决此问题。

您是否尝试过SetActiveWindow()

最适合我。

两者都很有效:

::SetForegroundWindow(wnd)

但请记住,最后一个选项将窗口设置为始终位于顶部。

//非常好

Var
 WndHandle:HWND;

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

试试这个,据说来自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);

经过多次尝试和错误,我找到了以下解决方案:

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。请不要只是复制和粘贴。您还需要在每次api调用后使用
GetLastError
检查api错误

我已在win7上确认以下结果:

  • 可以还原最小化窗口且无错误返回
  • 如果窗口已位于顶部,则窗口标题将闪烁且不会返回错误
  • 如果窗口已关闭,它将返回错误“0x578无效窗口句柄”
  • 它可以将窗口置于所有非最顶端窗口的顶端,并且不会返回错误。(例如,它将位于最顶端taskmanager的后面)
  • 它不会使窗户最顶部。用户可以在上面创建其他窗口

这将在最小化的情况下还原应用程序,并将其置于最前端:

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

hwnd2没有父项的具体原因是什么?创建时可以将hwnd2设置为父级。您在hwnd2的鼠标按钮处理代码中执行什么操作?有什么可疑的地方吗?那你是如何用PostMessage解决的呢?MSDN:这个函数不推荐使用,不适合一般用途。建议您不要在新程序中使用它,因为它可能会在后续版本的Windows中被更改或不可用。我一直在寻找这首神奇的歌舞已经有一段时间了。它对我来说非常有效.我仍然不明白它的作用,但我希望我能说同样的话。不适合我。对话框获得焦点,但另一个对话框仍在它前面。当我想在win7中将最小化窗口置于顶部时,这对我不起作用。它只是没有将最小化窗口带到顶部。如果不最小化窗口,它可以将窗口置于顶部。SetFocus api返回错误代码0x57“参数不正确”。在我的win7上。我不知道为什么这段代码会忽略所有windows api错误。如果没有windows api的源代码,很难说我可能有点晚了,但在显示窗口之前,您必须调用
::SetForegroundWindow
(确保同时更新窗口)。
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);