Проблема позиционирования окна при использовании SetParent () - PullRequest
3 голосов
/ 08 ноября 2010

Я пытаюсь установить childForm как дочерний элемент главного окна Excel, используя API SetParent через PInvoke:

Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
childForm.StartPosition = FormStartPosition.Manual;
childForm.Left = 0;
childForm.Top = 0;

Как вы можете видеть выше, я также хочу расположить ребенка в верхнем левом углу окна Excel. Однако по какой-то причине childForm всегда оказывается в каком-то странном месте.

Что я делаю не так?

Ответы [ 5 ]

7 голосов
/ 10 ноября 2010

Хотя все ответы здесь предлагают совершенно логичные подходы, ни один из них не сработал для меня.Тогда я попробовал MoveWindow.По какой-то причине я не понимаю, это сработало.

Вот код:

[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

...

Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
MoveWindow(childForm.Handle, 0, 0, childForm.Width, childForm.Height, true);
5 голосов
/ 08 ноября 2010

При использовании SetParent в форме, которая в настоящее время является дочерней по отношению к рабочему столу (другими словами, одна без родителя установить), вы должны установить стиль WS_CHILD и удалить стиль WS_POPUP. (См. Раздел «Примечания» записи MSDN .) Windows требует, чтобы все принадлежащие ей окна имели установленный стиль WS_CHILD. Это также может быть причиной того, что свойства left и top сообщают / устанавливают неправильные значения, потому что форма не знает, кто ее папа. Вы можете исправить это, позвонив SetWindowLong после SetParent, но перед тем, как попытаться установить местоположение:

//Remove WS_POPUP style and add WS_CHILD style
const UInt32 WS_POPUP = 0x80000000;
const UInt32 WS_CHILD = 0x40000000;
int style = GetWindowLong(this.Handle, GWL_STYLE);
style = (style & ~(WS_POPUP)) | WS_CHILD;
SetWindowLong(this.Handle, GWL_STYLE, style);
1 голос
/ 08 ноября 2010

Я полагаю, это зависит от вашего звонка в ShowDialog. Если вы вызываете ShowDialog без родительского параметра, родительский элемент сбрасывается.

Вы можете создать класс-оболочку, который реализует IWin32Window и возвращает HWND, чтобы преуспеть. Затем вы можете передать это в вызов ShowDialog childForm.

Вы также можете запросить позицию приложения Excel, используя GetWindowPos, а затем соответственно установить childForm.

0 голосов
/ 08 ноября 2010

Если вы знаете, как получить hwnds окон, для которых вы хотите установить z-порядок, вы можете использовать этот pInvoke:

    public stati class WindowsApi 
    {
     [DllImport("user32.dll")]
    public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
        int X, int Y, int cx, int cy, uint uFlags);
    }



    public class WindowZOrderPositioner 
    {
         public void SetZOrder(IntPtr targetHwnd, IntPtr insertAfter)
         {
             IntPtr nextHwnd = IntPtr.Zero;

             WindowsAPI.SetWindowPos(targetHwnd, insertAfter, 0, 0, 0, 0, SetWindowPosFlags.NoMove | SetWindowPosFlags.NoSize | SetWindowPosFlags.NoActivate);
     }
0 голосов
/ 08 ноября 2010

Попробуйте несколько способов диагностики проблемы:

  • Поставить точку останова после установки влево и Top, слева и сверху читается ноль?
  • Вызовите SetParent последним.
  • Создайте метод, который устанавливает Left и Top снова и BeginInvoke метод.
  • Убедитесь, что ваше дочернее окно действительно ребенок. Для этого звоните ShowDialog, и попробуйте нажать родительское окно. Убедитесь, что окна предотвращает фокус на родительском окне.
...