Можно ли настроить поведение владельца формы WinForms с помощью hwnd / NativeWindow? - PullRequest
6 голосов
/ 18 октября 2008

Мое приложение - исполняемый файл vb6, но некоторые более новые формы в системе написаны на C #. Я хотел бы иметь возможность установить свойство Owner формы C # с помощью дескриптора главного окна приложения, чтобы диалоговые окна оставались сверху при переходе между моим приложением и другими приложениями.

Я могу получить hwnd главного окна приложения. Я не уверен, что я могу сделать оттуда?


ОБНОВЛЕНИЕ 20 октября 2008 года в 17: 06:

Скотт,

Спасибо за ответ. Я упустил из виду, что параметр метода Show / ShowDialog не был типа Form - я смотрел только на свойство Owner.

Я немного изменил код, который я использую из вышеприведенного - у нас есть компонент, который в общем случае загружает наши формы и вызывает ShowDialog. Мой код выглядит так:

Form launchTarget = FormFactory.GetForm(xxx);  // psuedo-code for generic form loader
launchTarget.StartPosition = FormStartPosition.CenterParent;
IWin32Window parentWindow = GetWindowFromHwnd(hwnd);

launchTarget.ShowDialog(parentWindow);

GetWindowFromHwnd - это версия вашего кода в методе:

private IWin32Window GetWindowFromHost(int hwnd)
{
    IWin32Window window = null;
    IntPtr handle = new IntPtr(hwnd);

    try
    {
        NativeWindow nativeWindow = new NativeWindow();
        nativeWindow.AssignHandle(handle);
        window = nativeWindow;
    }
    finally
    {
        handle = IntPtr.Zero;
    }

    return window;
}

К сожалению, это не делает то, на что я надеялся. Форма отображается модально, но она не отображается в правильном положении и не остается наверху, когда я перемещаюсь назад и возвращаюсь в родительское окно. Наши модалы не показывают задачу на панели задач, поэтому окно, по-видимому, «исчезает» (хотя оно все еще присутствует в списке окон alt-tab). Это для меня означает, что я не могу иметь право hwnd. Если у вас есть другие предложения, пожалуйста, ответьте. Еще раз спасибо.


ОБНОВЛЕНИЕ 10 ноября 2008 г. в 16: 25

Одно последующее замечание - если вы включите его в вызов метода в try / finally, как во втором посте Скотта, вызов в блоке finally должен быть:

parentWindow.ReleaseHandle();

Ответы [ 2 ]

9 голосов
/ 18 октября 2008

Итак, вы вызываете класс C # Windows Form из VB6, что означает, что вы, вероятно, используете либо Show(), либо ShowDialog(), верно? Оба эти метода также принимают параметр IWin32Window, который просто определяет объект, который возвращает свойство IntPtr с именем Handle.

Итак ... вам нужно добавить перегруженный конструктор (или метод ShowDialog) для ваших классов Windows Forms, которые принимают long в качестве параметра, чтобы вы могли передавать hbnd VB6 в форму. Оказавшись внутри кода C #, вам нужно создать IntPtr из hwnd и назначить его объекту NativeWindow, а затем передать его в качестве владельца.

Что-то вроде этого должно работать, хотя и не проверено:

public DialogResult ShowDialog(long hwnd)
{
   IntPtr handle = new IntPtr(hwnd);
   try
   {
      NativeWindow nativeWindow = new NativeWindow();

      nativeWindow.AssignHandle(handle);
      return this.ShowDialog(nativeWindow);
   }
   finally
   {
      handle = IntPtr.Zero;
   }
}
2 голосов
/ 20 октября 2008

Это слишком долго, чтобы оставлять комментарии ...

Я думаю, что проблема, с которой вы работаете, заключается в том, как вы упаковали код, который я представил в перегрузке ShowDialog. Если вы следите за тем, что делает ваш код GetWindowFromHost, вы пройдете следующие шаги:

  1. Создает новый IntPtr из заданного hwnd.
  2. Создает новый объект NativeWindow и назначает его дескриптор как IntPtr.
  3. Устанавливает IntPtr (в блоке finally) как IntPtr.Zero.

Я думаю, что этот последний блок вызывает у вас проблемы. В моем коде блок finally будет выполняться после завершения вызова this.ShowDialog(nativeWindow). В этот момент дескриптор (IntPtr) больше не использовался. В вашем коде вы возвращаете IWin32Window, который все еще должен содержать ссылку на этот IntPtr, который на момент вызова launchTarget.ShowDialog(parentWindow) равен IntPtr.Zero.

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

private NativeWindow GetWindowFromHost(int hwnd)
{
   IntPtr handle = new IntPtr(hwnd);
   NativeWindow nativeWindow = new NativeWindow();
   nativeWindow.AssignHandle(handle);
   return window;
}

А затем измените свой код вызова так, чтобы он выглядел следующим образом:

Form launchTarget = FormFactory.GetForm(xxx);  // psuedo-code for generic form 
loaderlaunchTarget.StartPosition = FormStartPosition.CenterParent;
NativeWindow parentWindow = GetWindowFromHwnd(hwnd);

try
{
   launchTarget.ShowDialog(parentWindow);
}
finally
{
   parentWindow.DestroyHandle();
}

Эти изменения должны работать, но опять же это не проверено.

...