Win32:带一个窗口到顶部

时间:2009-05-27 15:01:45

标签: c++ winapi visual-c++

我有一个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)可以解决此问题。

8 个答案:

答案 0 :(得分:18)

试试这个,据说来自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_NOSIZE | SWP_NOMOVE);
    ::SetForegroundWindow(m_hWnd);
    ::AttachThreadInput(dwCurID, dwMyID, FALSE);
    ::SetFocus(m_hWnd);
    ::SetActiveWindow(m_hWnd);

答案 1 :(得分:13)

两者都很棒:

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

但请记住,最后一个窗口始终位于顶部。

答案 2 :(得分:7)

SwitchToThisWindow最适合我。

答案 3 :(得分:5)

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

答案 4 :(得分:4)

您是否尝试过 SetActiveWindow()

答案 5 :(得分:4)

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

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窗口句柄无效。"
  • 它可以将窗口置于所有非最顶层窗口的顶部,并且没有错误返回。(例如,它将在最顶层的任务管理器后面)
  • 它不会使窗户最顶层。用户可以在其上面建立其他窗口。

答案 6 :(得分:0)

这将还原一个最小化的应用程序并将其置于最前面:

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

答案 7 :(得分:-4)

//工作得很好!

Var
 WndHandle:HWND;

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