Я подключаю диалоговые окна (CommonDialog и MessageBox), чтобы центрировать их в родительском Form после их отображения. Все работает как шарм в том, что касается MessageBox, но когда диалог наследуется от CommonDialog (OpenFileDialog, SaveFileDialog и т. д.), прямоугольник, который я получаю, всегда неправильный, и центрирование сбивается. Это код, который я использую для получения прямоугольника диалогового окна:
[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;
}
В моей рабочей среде (Win7 с VS2013 и Framework 4.6.2), как я уже говорил ранее, метод GetRectangle возвращает неправильный прямоугольник Width и Height, когда диалоговое окно, которое я должен центрировать, наследуется от CommonDialog. Во время моих тестов я обнаружил, что и GetWindowRect, и DwmGetWindowAttribute возвращают одинаковые значения, поэтому основной обходной путь, который я реализовал, совершенно бесполезен. Я также обнаружил, что полученный прямоугольник всегда на 40 пикселей или около того шире реального (я измерил его, сделав снимок экрана).
Теперь, это серьезно сводит меня с ума. Единственные решения, которые я могу понять, это:
Определите, принадлежит ли обработчик окна
CommonDialog, и в этом случае вручную исправьте размер прямоугольника. Я не знаю как, так какGetClassNameвозвращает#32770как дляMessageBox, так и дляCommonDialog. Я также сомневаюсь, чтоGetWindowLongможет предоставить полезную информацию, которая позволит мне распознать тип диалогового окна.Вручную измените размер
CommonDialog, как только он появится, чтобы я мог узнать его реальный размер.
Любое другое предложение более чем приветствуется.
OpenFileDialogиSaveFileDialog. Это связано с тем, что классCommonDialogвыполняет метод с именемMoveToScreenCenterпри обработкеWM_INITDIALOG. Таким образом, если вы добавите флагSWP_SHOWWINDOWкSetWindowPos, вы сможете ясно увидеть идеально отцентрированное диалоговое окно, которое внезапно перемещается в центр экрана. - person Tommaso Belluzzo   schedule 02.12.2016