代码之家  ›  专栏  ›  技术社区  ›  David Citron

为什么单击子窗口并不总是将应用程序置于前台?

  •  5
  • David Citron  · 技术社区  · 16 年前

    当一个应用程序位于另一个应用程序之后并且 我单击我的应用程序的任务栏图标,我希望整个应用程序 进入z顺序的顶部,即使是应用程序模式,WS_弹出对话框也是 打开。

    但是,在某些时候,对于我的(和其他人的)对话框,只有对话框显示在前面;而应用程序的其余部分则显示在后面。

    我已经看过Spy++了,对于那些工作正常的,我可以看到 正在将WM_WINDOWPOSCHANGING发送到对话框的父级。对于那些 留下应用程序的其余部分,WM_WINDOWPOSCHANGING不是 发送到对话框的父级。

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

    简而言之,这两个窗口都是用DialogBoxParam()创建的WS_popupWindows窗口, 作为第三个参数传入相同的hwnd。

    有没有人注意到Windows程序中的这种行为怪癖?当我单击任务栏的按钮时,它会向应用程序发送什么消息?谁有责任确保 全部的 应用程序的窗口出现在前台?

    在我的例子中,基本的父代是MDI框架…这会有什么影响吗?

    3 回复  |  直到 16 年前
        1
  •  4
  •   P Daddy    15 年前

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

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

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

    在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] :

    不要打电话 设置窗口长度 使用GWLPYHWNDHORD索引更改子窗口的父级。相反,使用 SetParent 功能。

    这有点误导人,因为这似乎意味着上面最后两个片段是错误的。事实并非如此。打电话 SetParent 将要弹出的内容转换为 小孩 父窗口(设置 WS_CHILD 而不是让它成为自己的窗口。上面的代码是使现有弹出窗口拥有窗口的正确方法。

        2
  •  1
  •   jussij    16 年前

    单击任务栏图标时,Windows将发送 WM U激活 向应用程序发送消息。

    你确定你的代码通过了 WM U激活 窗口过程 窗口处理程序?

        3
  •  0
  •   jmatthias    16 年前

    对话框的父窗口设置是否正确?

    在我发布这篇文章之后,我启动了自己的Windows窗体应用程序,并复制了您描述的问题。我有两个对话框,一个工作正常,另一个不正常,我看不出任何直接的原因是为什么他们的行为不同。如果我知道的话,我会更新这篇文章的。

    陈雷蒙,你在哪!