windows - 为什么单击子窗口并不总是将应用程序带到前台?

标签 windows winapi

当一个应用程序落后于另一个应用程序并且 我单击我的应用程序的任务栏图标,我希望整个应用程序 来到 z-order 的顶部,即使是 app-modal,WS_POPUP 对话框 打开。

然而,有些时候,对于我(和其他人)的一些对话框,只有对话框出现在前面;应用程序的其余部分留在后面。

我查看了 Spy++,对于那些可以正常工作的,我可以看到 WM_WINDOWPOSCHANGING 被发送到对话框的父级。对于那些 留下应用程序的其余部分,WM_WINDOWPOSCHANGING 没有被 发送给对话框的父级。

我有一个例子,其中一个对话框通常会带来整个应用程序,而另一个则不会。工作对话框和非工作对话框具有相同的窗口样式、子样式、父级、所有者、个体生成。

简单来说,都是用DialogBoxParam()创建的WS_POPUPWINDOW窗口, 作为第三个参数传入相同的 HWND。

有没有其他人注意到 Windows 程序中的这种行为异常?当我单击它的按钮时,TaskBar 会向应用程序发送什么消息?谁负责确保应用程序的所有窗口都出现在前台?

在我的例子中,基本父子关系是一个 MDI 框架……这会以某种方式影响吗?

最佳答案

我知道这现在已经很老了,但我只是偶然发现了它,而且我知道答案。

在您看到(和编写)的应用程序中,将对话框置于前台并没有将主窗口一起调出,开发人员只是忽略了指定对话框的所有者对话框。

这既适用于模态窗口,如对话框和消息框,也适用于非模态窗口。设置无模式弹出窗口的所有者也会使弹出窗口始终保持在其所有者之上。

在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] 有以下说明:

Do not call SetWindowLongPtr with the GWLP_HWNDPARENT index to change the parent of a child window. Instead, use the SetParent function.

这有点误导,因为它似乎暗示上面的最后两个片段是错误的。不是这样的。调用 SetParent 会将预期的弹出窗口变成父窗口的 child(设置其 WS_CHILD 位),而不是使其成为拥有的窗口。上面的代码是使现有弹出窗口成为拥有窗口的正确方法。

关于windows - 为什么单击子窗口并不总是将应用程序带到前台?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51150/

相关文章:

linux - 从 Linux 备份到 Windows Server

windows - 如何使用性能计数器监视 WCF 服务的正常运行时间?

c++ Windows API递归搜索未返回预期目录

c++ - 如何获取 Windows 7 中“开始”按钮的句柄?

c++ - 我应该使用 GetProcAddress 还是只包含各种 win32 库?

c++ - 为什么尽管有 SW_HIDE 和 CREATE_NO_WINDOW,通过 CreateProcess 调用的程序的窗口仍会显示?

java - 在 Windows 中更改 Java 安全文件

javascript - tfjs-node-gpu Windows 上的 ELF header 无效

windows - Powershell 相当于 Linux 超时

c - 启动应用程序并等待其完成,而不会阻止重绘