如何:给定HWND,确定窗口是否是模态窗口

12

对于我处理的任何给定窗口,我需要一种方法来查找给定窗口是否是模态的。

据我所知,没有确切可以做到这一点的方法,这就是为什么我需要一些巧妙的解决方法来解决这个问题!

感谢您的帮助!

编辑:为什么我的GetWindow(,GW_OWNER)失败了? :(

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    internal static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
    [DllImport("user32.dll", ExactSpelling = true)]
    internal static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestor_Flags gaFlags);
    [DllImport("user32.dll", SetLastError = false)]
    internal static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll", SetLastError = true)]
    internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    const UInt32 WS_DISABLED = 0x8000000;


    internal enum GetAncestor_Flags
    {
        GetParent = 1,
        GetRoot = 2,
        GetRootOwner = 3
    }

    internal enum GetWindow_Cmd : uint
    {
        GW_HWNDFIRST = 0,
        GW_HWNDLAST = 1,
        GW_HWNDNEXT = 2,
        GW_HWNDPREV = 3,
        GW_OWNER = 4,
        GW_CHILD = 5,
        GW_ENABLEDPOPUP = 6
    }



IntPtr _inspHwnd = FindWindow("rctrl_renwnd32", inspector.Caption); // searching for a window with this name
        if (_inspHwnd.ToInt32() != 0) // found window with this name
        {
            IntPtr _ownerHwnd = GetWindow(_inspHwnd, GetWindow_Cmd.GW_OWNER);
            if (_ownerHwnd.ToInt32() != 0)
            {
                IntPtr _ancestorHwnd = GetAncestor(_ownerHwnd, GetAncestor_Flags.GetParent);
                if (_ancestorHwnd == GetDesktopWindow())
                {
                    if (GetWindowLong(_ancestorHwnd, -16) == WS_DISABLED) 
                    { 
                        // inspector is probably modal if you got all the way here
                        MessageBox.Show("modal flag tripped");
                    }
                }
            }
        }

只是在这里想想:1)寻找它的父级 2)查看父窗口是否可以被激活 - BoltClock
你好,BoltClock。我对窗口属性的了解有限,所以想问一下,在这个上下文中,“activated”是什么意思?是指窗口可见,还是检查它是否存在? - CodeMinion
基本上意味着检查您是否可以将窗口置于焦点(通常通过单击或使用Alt + Tab切换到它)。 - BoltClock
在非模态检查器上,似乎“parent”不等于Outlook的主体,所以我不确定这种方法是否有效。 - CodeMinion
错误的方法。如果您找到了特定的窗口,那么它是否是模态的并不重要。 - Hans Passant
目标是发现模态窗口并将其替换为非模态窗口,以解决此处详细说明的空白窗格错误:http://stackoverflow.com/questions/5723444/need-help-with-very-specific-issue-with-vsto-outlook-2007-addin-running-on-window - CodeMinion
3个回答

10

模态窗口通常通过禁用其所有者来工作,其中所有者是顶级窗口。因此,如果您测试此情况,您应该捕获对话框是否为模态的情况。

  • 检查HWND实际上是顶级对话框,而不是子窗口
  • 获取所有者(GetWindow(GW_OWNER))
  • 检查所有者本身是否是顶级窗口(例如,GetAncestor(GA_PARENT)== GetDesktopWindow())
  • 检查所有者是否已禁用(GetWindowLong(GWL_STYLE)&WS_DISABLED)

这应该可以捕获所有标准的Win32样式模态对话框。

请注意,父母和所有者是微妙不同的概念;在这里要检查的是所有者。这可能会让人感到困惑,因为GetParent可能会返回所有者... - Raymond Chen here提供更多详细信息。


我会将此标记为答案,但我不太了解win API如何实际执行您的建议:(有没有好的页面可以让我学习呢? - CodeMinion
好的,多亏了pinvoke.net,我现在几乎所有的东西都能正常工作了,但是GWL_STYLE位让我感到困惑,它应该是一个常量UInt32吗? - CodeMinion
这是一个普通的 int(或 Int32),值为-16 - 更多细节请参阅 MSDN http://msdn.microsoft.com/en-us/library/ms633584(v=vs.85).aspx。在这种情况下,也可以使用 IsWindowEnabled(http://msdn.microsoft.com/en-us/library/ms646303(v=vs.85).aspx) - BrendanMcK
谢谢,Brandon!只剩下一个问题需要解决了!我的 GetWindow 函数似乎返回了 0!我会在我的问题中添加一些代码,以防我做错了什么。 - CodeMinion
你使用过Spy++来检查这是否是在这种特定情况下模态工作的方式吗?上面的答案是win32应用程序中通常完成模态的方式;但Outlook可能正在做自己的事情。在编写代码之前,Spy++是一个很好的工具,可以帮助你弄清楚发生了什么。另一件要注意的事情是-不要直接将GetWindowLong的输出与WS_DISABLED进行比较;GetWindowLong返回一个位字段,因此可能设置了其他位。 - BrendanMcK
显示剩余4条评论

3
我不确定BrendanMck的解决方案是否总是正确的。假设窗口W首先显示一个非模态对话框A,然后显示一个模态对话框B。A和B都有W作为它们的父窗口。在B被显示时,W变为禁用状态,因此将算法应用于A和B将报告它们都是模态对话框。

-2

我刚在我的代码中写了这么一行:

GetWindowLong(GetWindow(Hwnd, GW_OWNER), GWL_STYLE) & WS_DISABLED & WS_POPUP

2
你需要解释,而不是仅仅复制一些你甚至不知道来源的代码。 - quantum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接