0

I'm hooking dialog boxes (CommonDialog and MessageBox) so that I can center them into the parent Form once they are displayed. Everything works like a charm for what concerns MessageBox, but when the dialog inherits from CommonDialog (OpenFileDialog, SaveFileDialog, etc...) the rectangle I retrieve is always wrong and the centering gets messed up. This is the code I use to get the dialog box rectangle:

[DllImport("User32.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, ExactSpelling=true, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern Boolean GetWindowRect([In] IntPtr handle, [Out] out RECT rectangle);

[DllImport("Dwmapi.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, ExactSpelling=true, SetLastError=true)]
private static extern UInt32 DwmGetWindowAttribute([In] IntPtr handle, [In] DWMWINDOW_ATTRIBUTE attribute, [In, Out] IntPtr attributeValue, [In] UInt32 attributeSize);

[DllImport("Dwmapi.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Unicode, ExactSpelling=true, SetLastError=true)]
private static extern UInt32 DwmIsCompositionEnabled([Out, MarshalAs(UnmanagedType.Bool)] out Boolean enabled);

internal static Boolean AeroThemeEnabled
{
    get
    {
        Boolean result = false;

        if (Environment.OSVersion.Version.Major >= 6)
            DwmIsCompositionEnabled(out result);

        return result;
    }
}

internal static Boolean GetRectangle(IntPtr windowHandle, out Rectangle rectangle)
{
    RECT nativeRectangle;

    if (AeroThemeEnabled)
    {
        IntPtr attributeValue = IntPtr.Zero;
        UInt32 size = GetSize(typeof(RECT));

        try
        {
            attributeValue = Marshal.AllocCoTaskMem((Int32)size);

            UInt32 result = DwmGetWindowAttribute(windowHandle, DWMWINDOW_ATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, attributeValue, size);

            if (result == 0)
                nativeRectangle = Marshal.PtrToStructure<RECT>(attributeValue);
            else if (!GetWindowRect(windowHandle, out nativeRectangle))
            {
                rectangle = Rectangle.Empty;
                return false;
            }
        }
        finally
        {
            if (attributeValue != IntPtr.Zero)
                Marshal.FreeCoTaskMem(attributeValue);
        }
    }
    else if (!GetWindowRect(windowHandle, out nativeRectangle))
    {
        rectangle = Rectangle.Empty;
        return false;
    }

    Int32 x = nativeRectangle.Left;
    Int32 y = nativeRectangle.Top;
    Int32 width = nativeRectangle.Right - x;
    Int32 height = nativeRectangle.Bottom - y;

    rectangle = new Rectangle(x, y, width, height);

    return true;
}

In my working environment (Win7 with VS2013 and Framework 4.6.2), as I previously said, the method GetRectangle returns wrong rectangle Width and Height when the dialog box I have to center inherits from CommonDialog. During my tests, I found out that both GetWindowRect and DwmGetWindowAttribute return the same values, so the main workaround I implemented is totally useless. I also discovered that the retrieved rectangle is always 40 pixels or so wider than the real one (I measured it taking a screenshot).

Now, this is seriously driving me to madness. The only solutions I can figure out are:

  1. Detect if the window handler belongs to a CommonDialog and, in that case, manually fix the rectangle size. I don't know how, since GetClassName returns #32770 for both MessageBox and CommonDialog. I also doubt that GetWindowLong can provide useful information that can let me recognize the dialog box type.

  2. Manually resize the CommonDialog as soon as it is shown so I can know its real size.

Any other suggestion is more than welcome.

Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
  • 1
    Have a look at [GetClientRect](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633503(v=vs.85).aspx) – RamblinRose Dec 01 '16 at 19:48
  • GetClientRect also is returning a wrong value when the time comes to measure a CommonDialog. For example... GetWindowRect width is 664, GetClientRect width is 648... but the true values should be respectively 625 and 609. – Tommaso Belluzzo Dec 01 '16 at 19:50
  • 1
    this is a duplicate question. http://stackoverflow.com/questions/2576156/winforms-how-can-i-make-messagebox-appear-centered-on-mainform http://stackoverflow.com/questions/1732443/center-messagebox-in-parent-form – McNets Dec 01 '16 at 20:56
  • A small update: my approach (which is basically this one: http://stackoverflow.com/a/3498791/796085) works for every dialog box except `OpenFileDialog` and `SaveFileDialog`. This is because the `CommonDialog` class executes a method called `MoveToScreenCenter` when the `WM_INITDIALOG` is processed. So if you add `SWP_SHOWWINDOW` flag to `SetWindowPos` you can clearly see a perfectly centered dialog moving all of a sudden to the center of the screen. – Tommaso Belluzzo Dec 02 '16 at 01:32

0 Answers0