一个窗口可以始终位于另一个窗口的顶部吗?

时间:2009-05-01 18:46:40

标签: windows winapi

在Windows中,是否可以设置窗口A,使其始终位于窗口B的顶部,但允许其他窗口正常工作,并在活动时显示在两者之上。

换句话说,我想在两个窗口之间建立父子关系。这可以在不使窗口A成为窗口B,MDI风格的子窗口的情况下完成吗?窗口B不是我的(Internet Explorer),并且当我尝试使用SetParent实现此操作时,将我的对话框A的图形搞定。

我以为我是用MSDN forum post的这个想法来解决它的,但是唉,窗户A仍然总是在一切之上,而不仅仅是窗口B.

// Place window A on top
SetWindowPos(hWndWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
// Place window B underneath it
SetWindowPos(hWndParent, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);

有可能吗?

7 个答案:

答案 0 :(得分:13)

不会创建所有权关系吗?

SetWindowLong(hwndChild, GWL_HWNDPARENT, hwndOwner)

窗口可以在不同的进程中,您可以从任何进程调用它。这将确保子窗口始终位于所有者窗口之上。这与实际创建父/子关系的SetParent不同。 Read through this article(从1993年开始,但仍然大部分是正确的)看到所有权和养育子女之间的区别。

答案 1 :(得分:4)

当您的窗口的Z顺序(或大小或位置)发生变化时,它应该会收到WM_WINDOWPOSCHANGING消息。如果您处理该消息,您有机会修改窗口移动到的最终Z顺序(​​或大小或位置)。

为了说明,在hWndA的窗口过程中:

case WM_WINDOWPOSCHANGING:
    DefWindowProc(hWnd, msg, wParam, lParam);
    WINDOWPOS *p = (WINDOWPOS*)lParam;
    p->hwndInsertAfter = hWndB;
    p->flags &= ~SWP_NOZORDER;
    return 0;
每当hWndA的位置改变时,

应该在h-order之后插入hWndA。

答案 2 :(得分:2)

在Vista之前,一种方法是使用SetWindowsHookEx,并挂钩WH_CBTWH_CALLWNDPROC挂钩,然后在检测到Z顺序更改时采取适当的操作。然而,这不适用于Vista(据我可以通过谷歌搜索来判断)。

我能想到的唯一其他解决方案是设置计时器每隔几秒钟启动一次,然后当你收到WM_TIMER时,使用GetNextWindow查询系统以找出哪个窗口落后于你。如果它不是IE,那么调用SetWindowPos将你的窗口放在IE上面(我假设你有一个HWND用于你关心的IE窗口 - 记住可以有多个IE窗口。)

如果人们试图将您的窗口置于前面,这将导致问题 - 它将回到IE正上方。在这种情况下,在您的代码中,您可以处理WM_ACTIVATE并尝试更改IE窗口的Z顺序,使其位于窗口下方(调用SetWindowPos移动IE的窗口,使其位于当前窗口的上方在你的窗口下面)。出于安全原因,Windows可能会试图阻止您弄乱另一个进程的窗口,因此这个解决方案可能会遇到问题。另一方面,SetWindowPos的MSDN文档没有明确提及您无法操纵另一个进程的窗口。但是可能存在模糊的限制。

即使使用此计时器黑客攻击,您也会在应用程序中有效地进行忙碌等待循环(使用频繁的WM_TIMER消息),这通常是糟糕要做的事情,特别是对于笔记本电脑等的电池寿命(因为你可以防止CPU进入睡眠状态,等等)。

我会说没有好办法做到这一点,任何你可能会工作的东西都会变脆并导致问题。 我强烈建议您不要尝试这样做。是否可以将您的程序转换为IE的某种插件或工具栏?

NB 要特别注意SetWindowsHookEx如果沿着这条路走下去,会在系统范围内造成性能损失。

答案 3 :(得分:1)

莫里斯的答案是最好的,但却缺少重要的一步。当您在窗口上调用show作为叠加层时,需要调用具有该参数的show方法。您需要定义一个实现IWin32Window接口的类,并创建一个新的实例。接口唯一关心的是Handle,所以只需将其设置为IE窗口的句柄,它应该可以正常工作

答案 4 :(得分:1)

如果亲子关系是由您自己使用SetWindowPos()函数创建的,那么您的愿望就可以实现。

答案 5 :(得分:0)

您可以访问Windows的Z顺序吗?

我无法回想起Windows的默认z顺序,但我认为它是1.您可以将IE设置为-1,将应用程序设置为0.

答案 6 :(得分:0)

试试这个:

// Place window A on top of window B
SetWindowPos(hWndA, hWndB, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);

第二个窗口句柄参数指定Z顺序中的下一个窗口。

请注意,这实际上并不会改变窗口的父子关系 - 但您可以模拟它。