How to : Given HWND, discover if window is Modal or not
Asked Answered
B

3

12

For any given window I handle, I need a way to find out whether or not the given window is Modal.

Far as I can tell, there are no methods that do exactly that, which is why I need some clever workaround to work this out!

Help is appreciated!

EDIT : Why is my GetWindow(,GW_OWNER) failing? :(

    [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");
                    }
                }
            }
        }
Buhr answered 25/4, 2011 at 23:1 Comment(6)
Just thinking aloud here: 1) Look for its parent 2) See if the parent window can be activatedRhyne
hello boltclock, my understanding of window properties is limited, so I want to ask, what does being 'activated' mean within this context. is it like being visible or checking if it exists?Buhr
It basically means check if you can bring the window to focus (normally by clicking it or Alt+Tabbing to it).Rhyne
On non-modal inspectors it seems as if 'parent' is not equal to the main body of outlook, so I'm not sure if this method will work.Buhr
Wrong approach. If you find the particular window you are looking for then whether it is modal or not doesn't matter.Involuted
the goal is to discover modal windows and replace them with non-modal windows as a workaround to the blank pane bug detailed here : #5723944Buhr
P
10

Modal windows usually work by disabling their owner, where the owner is a top-level window. So if you test for this situation, you should catch whether a dialog is modal or not.

  • Check that the HWND is actually a top-level dialog, and not a child window
  • Get the owner (GetWindow(GW_OWNER))
  • Check that the owner is itself a top-level window (eg. GetAncestor(GA_PARENT)==GetDesktopWindow())
  • Check that the owner is disabled (GetWindowLong(GWL_STYLE) & WS_DISABLED)

That should catch all standard Win32-style modal dialogs.

Note that parent and owner are subtly different concepts; it's the owner you want to check here. This can get confusing, because GetParent can return the owner... - more details from Raymond Chen here.

Periotic answered 26/4, 2011 at 0:13 Comment(9)
I'm going to flag this as the answer, but I don't know win API well enough to know how to actually put your suggestions into action :( Anyone have a good page for me to learn that from?Buhr
Ok, I have almost everything working now thanks to pinvoke.net, but the GWL_STYLE bit confuses me, is that supposed to be a constant UInt32?Buhr
It's a plain int (or Int32), value -16 - more details on MSDN msdn.microsoft.com/en-us/library/ms633584(v=vs.85).aspx . In this case, can also use IsWindowEnabled ( msdn.microsoft.com/en-us/library/ms646303(v=vs.85).aspx )Periotic
thanks, brandon! just one issue left to iron out! my GetWindow function seems to be returning 0! i'll add some code to my question incase i'm doing something wrong.Buhr
Have you used Spy++ to check that this is how the modals work in this particular case? The above answer is how modals are typically done in win32 apps; but it's always possible that Outlook is doing its own thing. Spy++ is a great tool for figuring out what's going on before writing code. Another thing to watch for - don't compare the output of GetWindowLong directly with WS_DISABLED; GetWindowLong returns a bitfield, so there could be other bits set.Periotic
Believe it or not, this is my first time hearing about Spy++! It does seem as if modal windows launched from MS Word have a different owner/parent than the Outlook Explorer window. In stepping through the code I noticed that the parent was just "Outlook", not referencing any open Explorer window in particular. Maybe the background process? I can also just get the Outlook.Explorer's handle at the start of the program and store it, and then check and see if it is disabled when an inspector is created. But how do I check for WS_DISABLED if not by comparison?Buhr
Easy bit first: Checking for WS_DISABLED: the usual way for checking for one bit set in a bitfield is to use the & operator: if((GetWindowLong(hwnd,GWL_STYLE) & WS_DISABLED) != 0) { disabled case } - bitwise-& strips all the bits except for the one you're checking; so if the result is non-zero, it means WS_DISABLED must have been present on the left hand side. (In C/C++, the !=0 part is usually left out, but I think it's needed in C#.)Periotic
Parents vs Owners: Spy++ isn't exactly correct: if the window has an owner, it seems to display that as the 'parent' also. The is likely due to a quirk in the underlying API 'GetParent()' - which returns the parent window; or the owner, if the window has an owner instead. So you have to manually figure out if it's really talking about a parent vs owner. Usually the window's position in the window tree in Spy++ gives it away easily.Periotic
The parent/owner has to be an actual HWND, it can't just be a process in general; though sometimes apps will use a technique where the have a dialog that is owned by an invisible window: this prevents the dialog from showing up on the task bar. When using Spy++, take note of the handle values. In the window properties dialog, you can click through to get information about that window - check the styles for WS_VISIBLE to see if it's hidden or not; if you click the Synchronize button at bottom of dialog, it will highlight that window in the tree.Periotic
S
3

I'm not certain that BrendanMck's solution will always be correct. Let's say that window W displays first a modeless dialog A and then a modal dialog B. Both A and B have W as their parent window. At the time B was displayed, W became disabled and as such applying the algorithm to both A and B will report both of them as being modal dialogs.

Serna answered 7/11, 2012 at 16:15 Comment(0)
S
-2

I just wrote GetWindowLong(GetWindow(Hwnd, GW_OWNER), GWL_STYLE) & WS_DISABLED & WS_POPUP in my code.

Synonymize answered 20/6, 2012 at 7:57 Comment(1)
You need to explain not just copy some code off somewhere that you don't even know.Demy

© 2022 - 2024 — McMap. All rights reserved.