如何:给定 HWND,发现窗口是不是是模态的

Posted

技术标签:

【中文标题】如何:给定 HWND,发现窗口是不是是模态的【英文标题】:How to : Given HWND, discover if window is Modal or not如何:给定 HWND,发现窗口是否是模态的 【发布时间】:2011-08-12 15:46:57 【问题描述】:

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

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

感谢您的帮助!

编辑:为什么我的 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,我对窗口属性的理解是有限的,所以我想问一下,在这种情况下“激活”是什么意思。是可见还是检查它是否存在? 这基本上意味着检查您是否可以使窗口聚焦(通常通过单击它或 Alt+Tabbing 到它)。 在非模态检查器上似乎'父'不等于outlook的主体,所以我不确定这种方法是否有效。 方法错误。如果您找到您正在寻找的 特定 窗口,那么它是否是模态的并不重要。 【参考方案1】:

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

【讨论】:

【参考方案2】:

我刚刚写了 GetWindowLong(GetWindow(Hwnd, GW_OWNER), GWL_STYLE) & WS_DISABLED & WS_POPUP 在我的代码中。

【讨论】:

你需要解释的不仅仅是复制一些你甚至不知道的地方的代码。【参考方案3】:

模式窗口通常通过禁用其所有者来工作,其中所有者是***窗口。因此,如果您测试这种情况,您应该了解对话框是否是模态的。

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

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

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

【讨论】:

我将把它标记为答案,但我不太了解 win API,不知道如何将您的建议付诸实践 :( 任何人都有一个很好的页面供我学习是从哪里来的? 好的,多亏了 pinvoke.net,我现在几乎所有东西都可以工作了,但是 GWL_STYLE 位让我感到困惑,这应该是一个常量 UInt32 吗? 这是一个普通的 int(或 Int32),值为 -16 - MSDN msdn.microsoft.com/en-us/library/ms633584(v=vs.85).aspx 上的更多详细信息。在这种情况下,也可以使用 IsWindowEnabled (msdn.microsoft.com/en-us/library/ms646303(v=vs.85).aspx) 谢谢,布兰登!只剩下一个问题需要解决!我的 GetWindow 函数似乎返回 0!我会在我的问题中添加一些代码,以防我做错了什么。 您是否使用过 Spy++ 来检查模态在这种特殊情况下的工作方式?上面的答案是 modals 通常在 win32 应用程序中是如何完成的;但 Outlook 总是有可能在做自己的事情。 Spy++ 是一个很好的工具,可以在编写代码之前弄清楚发生了什么。另一件需要注意的事情 - 不要将 GetWindowLong 的输出直接与 WS_DISABLED 进行比较; GetWindowLong 返回一个位域,因此可以设置其他位。

以上是关于如何:给定 HWND,发现窗口是不是是模态的的主要内容,如果未能解决你的问题,请参考以下文章

关于PeekMessage中hwnd参数

模态窗口无法刷新

MFC 如何向子窗口发送消息,子窗口是在tab control下的模态窗口?

如何将模态位置设置到屏幕的左下角?

WPF 解决弹出模态窗口关闭后,主窗口不在最前

如何使 QDialog 仅针对其非模态父窗口而不是所有祖父窗口成为模态?