为啥单击子窗口并不总是将应用程序带到前台?
Posted
技术标签:
【中文标题】为啥单击子窗口并不总是将应用程序带到前台?【英文标题】:Why does clicking a child window not always bring the application to the foreground?为什么单击子窗口并不总是将应用程序带到前台? 【发布时间】:2008-09-09 02:58:15 【问题描述】:当一个应用程序落后于另一个应用程序并且 我点击我的应用程序的任务栏图标,我希望整个应用程序 来到 z-order 的顶部,即使是一个 app-modal,WS_POPUP 对话框 打开。
但是,有些时候,对于我(和其他人)的一些对话框,只有对话框出现在前面;应用程序的其余部分留在后面。
我查看了 Spy++,对于那些正常工作的,我可以看到 WM_WINDOWPOSCHANGING 被发送到对话框的父级。对于那些 留下应用程序的其余部分,WM_WINDOWPOSCHANGING 不是 发送到对话框的父级。
我有一个示例,其中一个对话框通常会带来整个应用程序,而另一个不会。工作对话框和非工作对话框都具有相同的窗口样式、子样式、父窗口、所有者、个体。
简而言之,两者都是使用 DialogBoxParam() 创建的 WS_POPUPWINDOW 窗口, 已将相同的 HWND 作为第三个参数传入。
有没有其他人注意到 Windows 程序中的这种行为异常?当我单击它的按钮时,任务栏会向应用程序发送什么消息?谁负责确保所有应用程序的窗口都出现在前台?
在我的情况下,基本父系是一个 MDI 框架......这是否以某种方式影响?
【问题讨论】:
【参考方案1】:我知道这已经很老了,但我只是偶然发现它,我知道答案。
在您看到(和编写)的应用程序中,将对话框置于前台并没有将主窗口随之打开,开发人员只是忽略了指定对话框。
这适用于模态窗口,如对话框和消息框,以及非模态窗口。设置无模式弹出窗口的所有者也会使弹出窗口始终高于其所有者。
在Win32 API中,弹出对话框或消息框的函数以所有者窗口为参数:
INT_PTR DialogBox(
HINSTANCE hInstance,
LPCTSTR lpTemplate,
HWND hWndParent, /* this is the owner */
DLGPROC lpDialogFunc
);
int MessageBox(
HWND hWnd, /* this is the owner */
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
类似,在.NET WinForms中,可以指定所有者:
public DialogResult ShowDialog(
IWin32Window owner
)
public static DialogResult Show(
IWin32Window owner,
string text
) /* ...and other overloads that include this first parameter */
此外,在 WinForms 中,设置无模式窗口的所有者很容易:
public void Show(
IWin32Window owner,
)
或者,等效地:
form.Owner = this;
form.Show();
在直接的 WinAPI 代码中,可以在创建窗口时设置无模式窗口的所有者:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent, /* this is the owner if dwStyle does not contain WS_CHILD */
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
或之后:
SetWindowLong(hWndPopup, GWL_HWNDPARENT, (LONG)hWndOwner);
或(64 位兼容)
SetWindowLongPtr(hWndPopup, GWLP_HWNDPARENT, (LONG_PTR)hWndOwner);
请注意,MSDN 对SetWindowLong[Ptr] 有以下说法:
不要使用 GWLP_HWNDPARENT 索引调用 SetWindowLongPtr 来更改子窗口的父级。相反,请使用 SetParent 函数。
这有点误导,因为它似乎暗示上面的最后两个 sn-ps 是错误的。这不是这样的。调用SetParent
会将预期的弹出窗口变成父窗口的子(设置其WS_CHILD
位),而不是使其成为拥有的窗口。上面的代码是使现有弹出窗口成为拥有窗口的正确方法。
【讨论】:
感谢您的回答!但是,这不是我的应用程序出现问题的原因。正如我在问题中所说,我在所有情况下都通过了所有者。还有其他想法吗? 您是否有一个可重复的样本,偶然?【参考方案2】:当您单击任务栏图标时,Windows 会向您的应用程序发送 WM_ACTIVATE 消息。
您确定您的代码正在将 WM_ACTIVATE 消息传递给 DefWindowProc 窗口过程进行处理吗?
【讨论】:
【参考方案3】:对话框的父窗口设置是否正确?
发布此内容后,我启动了自己的 Windows 窗体应用程序并重现了您描述的问题。我有两个对话框,一个可以正常工作,另一个不能正常工作,我看不出任何直接原因是为什么它们的行为不同。如果我知道了,我会更新这篇文章。
Raymond Chen 你在哪里!
【讨论】:
以上是关于为啥单击子窗口并不总是将应用程序带到前台?的主要内容,如果未能解决你的问题,请参考以下文章