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:
Detect if the window handler belongs to a
CommonDialog
and, in that case, manually fix the rectangle size. I don't know how, sinceGetClassName
returns#32770
for bothMessageBox
andCommonDialog
. I also doubt thatGetWindowLong
can provide useful information that can let me recognize the dialog box type.Manually resize the
CommonDialog
as soon as it is shown so I can know its real size.
Any other suggestion is more than welcome.