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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/916259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:55:58  来源:igfitidea点击:

Win32: Bring a window to top

c++winapivisual-c++

提问by

I have a Windows program which has two 2 windows in it:

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

hwnd (main interface)

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

When I double click on hwnd, I need hwnd2 to pop up and show some data, so I use this function to bring hwnd2 to top:

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

BringWindowToTop(hwnd2);

hwnd2 is brought to top, but there is one thing odd. When I click on hwnd2 again, hwnd (main interface) pops itself up again automatically. I tried to use the following function to solve this problem, but non of them works.

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

How could I solve this problem? Thanks in advance.

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

(for replying to aJ, hwnd2 doesn't have parent because it needs to be a toplevel window so it can be in front/back of other windows)

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

(hwnd2 is a media player which is composed of several windows, one of the windows is for video dispaly, two other trackbar controls for progress bar and volume bar, one Toolbar control for control panel.)

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

(There is one this might help, no matter which window I click on hwnd2, hwnd pops up automatically as loong as "the mouse is on top of hwnd in Z-order", including menu bar and non-client area, etc.)

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

(This media player is writen in Direct Show. I use IVideoWindow::put_Owner to put video window as the video owner, Direct Show internally creates a sub-video window as a child of the video window. Except for this sub-video window which I can't see the source code, I don't see any thing suspicious in hwnd2.)

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

I found the reason, which is because of Direct Show. I use multithread to execute it, and then the problem's solved. But...why??

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

This problem can be resolved by using PostMessage (rather than SendMessage).

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

回答by bowman han

try this,it is said coming from M$

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

In order to bring a window to top, you should get your window handle,thread handle, the windows thread handle who is in foreground

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

then we attach our thread to foreground window thread and get input by AttachThreadInput, then we set our window z order to topmost and then restore its z order to normal, call SetForegroundWindow,SetFocus,SetActiveWindow to make sure our window is brought to top and is active and have focus

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

then deattach the input queue from the old foreground window thread, make our thread the only one who capture the input events

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

So why should We call AttachThreadInput, it is because

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

SetFocus sets the keyboard focus to the specified window. The window must be attached to the calling thread's message queue.

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

What does AttachThreadInput do?

AttachThreadInput 有什么作用?

The AttachThreadInput function can be used to allow a set of threads to share the same input state. By sharing input state, the threads share their concept of the active window. By doing this, one thread can always activate another thread's window. This function is also useful for sharing focus state, mouse capture state, keyboard state, and window Z-order state among windows created by different threads whose input state is shared.

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

We use SetWindowPos to bring the windows to topmost and show the window if the window is hidding by using SWP_HIDEWINDOW

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

SetWindowPos function changes the size, position, and Z order of a child, pop-up, or top-level window. These windows are ordered according to their appearance on the screen. The topmost window receives the highest rank and is the first window in the Z order

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

If your problem is your window is also minimized , you should add one line code to the end

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

ShowWindow(m_hWnd, SW_RESTORE);

回答by Nuno

Both work great:

两者都很好用:

::SetForegroundWindow(wnd)

or

或者

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

But remember that the last one sets the window always on top.

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

回答by scottm

SwitchToThisWindowworks best for me.

SwitchToThisWindow最适合我。

回答by bronze man

After many tries and errors.I found following solution to this problem:

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

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

The hwnd is your windows HWND . Please do not just copy and paste. You also need use GetLastErrorto check api error after every api call.

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

I have confirm following result on my win7:

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

  • Can restore minimize window and no error return.
  • If the window already top, the window title will blink and no error return.
  • If the window has closed, it will return the error "0x578 Invalid window handle."
  • It can bring the window to the top on all not top-most window and no error return.(For example it will behind the top-most taskmanager)
  • It do not make the window top-most. The user can make other window on top of it.
  • 可以恢复最小化窗口并且没有错误返回。
  • 如果窗口已经置顶,则窗口标题会闪烁并且不会返回错误。
  • 如果窗口已关闭,它将返回错误“0x578 无效的窗口句柄”。
  • 它可以将窗口带到所有不是最顶层的窗口的顶部并且没有错误返回。(例如它会在最顶层的任务管理器后面)
  • 它不会使窗口位于最顶部。用户可以在它上面制作其他窗口。

回答by bronze man

SwitchToThisWindow() is not deprecated at all.
I use it for 14 years in production environment.
See Windows source code and you will see it's called everywhere...

SwitchToThisWindow() 根本没有被弃用。
我在生产环境中使用了 14 年。
查看 Windows 源代码,你会看到它在任何地方都被调用......

回答by ralphtheninja

Have you tried SetActiveWindow()?

你试过SetActiveWindow()吗?

回答by Goran Ekstrom

This will restore an app if minimized and bring it to the front:

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

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

回答by Iryna Panasyuk

//work great!

//效果很好!

Var
 WndHandle:HWND;

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