2009-05-01 108 views
12

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

这可能吗?

+0

不幸的是,我不认为有办法做到这一点。 – Charlie 2009-05-03 03:27:19

回答

0

你可以访问窗口的Z顺序吗?

我不记得窗口的默认z顺序,但我认为这是1.您可能能够IE设置为-1和您的应用程序为0

0

试试这个:

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

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

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

+0

这是它的一次(但它做了一次没有它反正)。点击IE将它带到我的窗口前:( – Mat 2009-05-01 20:30:45

3

当您的窗口的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; 

应在Z顺序hWndB后插入hWndA任何时候hWndA的位置变化。

+0

Mat没有自己的父窗口,所以他不能改变“A”的winproc。但是,也许父母的某种类型的钩子会起作用? – Aardvark 2009-05-04 17:45:24

+0

其实,他说他拥有A并且想让它看起来像是B的孩子,这不是他的(Internet Explorer)。我认为A会收到A的z顺序在B前面移动的通知。 – 2009-05-04 20:16:02

2

在Vista之前,一种方法是使用SetWindowsHookEx,并钩住WH_CBTWH_CALLWNDPROC钩子,然后在检测到Z顺序变化时采取适当的措施。然而,这不适用于Vista(据我所知,谷歌搜索)。

唯一的其他解决方案,我能想到的是要建立一个计时器,每隔几秒钟火,然后当您收到WM_TIMER,您使用GetNextWindow找出哪个窗口是你背后询问系统。如果它不是IE,请致电SetWindowPos将您的窗口放置在IE上方(我假设您有一个关于您关心的IE窗口的HWND-记住可以有多个IE窗口)。

如果人们试图将您的窗口放在前面,这会导致问题 - 它会翻转回到IE上方。在这种情况下,在您的代码中,您可以处理WM_ACTIVATE并尝试更改IE窗口的Z顺序,使其位于窗口下方(请拨SetWindowPos移动IE窗口,使其位于窗口当前窗口之上)。出于安全原因,这种解决方案可能充满了问题,因为Windows可能会试图阻止您搞乱另一个进程的窗口。另一方面,SetWindowPos的MSDN文档不明确提到您不能操纵另一个进程的窗口。尽管可能有一些模糊的限制。

即使此计时器的黑客,你将有效地在你的应用程序一个忙等待循环(与频繁的WM_TIMER消息),这通常是一个坏的事情,尤其是对于笔记本电脑的电池寿命等等(因为你阻止CPU进入睡眠状态,等等)。

我会说没有好的方法来做到这一点,任何你可能会工作的东西都会变得脆弱并引发问题。 我强烈建议不要尝试去做。是否有可能让你的程序进入IE的某种插件或工具栏?

NB尤其要注意的是,如果沿着这条路线走下去,SetWindowsHookEx会在系统级别上造成性能损失。

12

不会产生所有权关系吗?

SetWindowLong(hwndChild, GWL_HWNDPARENT, hwndOwner) 

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

1

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

0

如果父子关系是由SetWindowPos()函数自己完成的,那么您的愿望可以实施。