Can I get the behavior of setting my WinForms form's owner using an hwnd / NativeWindow?

落爺英雄遲暮 提交于 2019-11-30 09:42:33

So you are calling a C# Windows Form class from VB6, which means you are probably using either Show() or ShowDialog(), correct? Both of those methods also take an IWin32Window parameter, which simply defines an object that returns an IntPtr property named Handle.

So...you need to add an overloaded constructor (or ShowDialog method) for your Windows Forms classes which take a long as a parameter so you can pass the VB6 hwnd to the form. Once inside the C# code, you need to create an IntPtr from the hwnd and assign it to a NativeWindow object and then pass that as the owner.

Something like this should work, although it's untested:

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;
   }
}

This is too long to post as a comment...

I think the problem you are running in to is the way you wrapped the code I presented in the ShowDialog overload. If you follow what your GetWindowFromHost code is doing it goes through the following steps:

  1. Creates a new IntPtr from the hwnd given.
  2. Creates a new NativeWindow object and assigns it's handle to be the IntPtr.
  3. Sets the IntPtr (in the finally block) to be IntPtr.Zero.

I think it's this finally block that is causing you problems. In my code, the finally block would run after the call to this.ShowDialog(nativeWindow) finished. At that point the handle (IntPtr) was no longer being used. In your code, you are returning an IWin32Window that should still be holding a reference to that IntPtr, which at the time you call launchTarget.ShowDialog(parentWindow) is IntPtr.Zero.

Try changing your code to look like this:

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

And then change your calling code to look like this:

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();
}

These changes should work, but again this is untested.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!