我可以使用hwnd / NativeWindow设置我的WinForms表单所有者的行为吗?

我的应用程序是一个vb6可执行文件,但系统中的一些较新的表单是用C#编写的。 我希望能够使用主应用程序窗口的句柄设置C#表单的Owner属性,以便在我的应用程序和其他应用程序之间来回切换时,对话框保持在顶部。

我可以获得主应用程序窗口的hwnd。 我不确定我能从那里做些什么?


更新08年10月20日17:06:

斯科特,

谢谢你的回复。 我忽略了Show / ShowDialog方法参数不是Form类型 – 我只查看Owner属性。

我稍微修改了我正在使用的代码 – 我们有一个组件通常加载我们的Forms并调用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窗口列表中)。 那对我来说表明我可能没有合适的人选。 如果您有任何其他建议,请回复。 再次感谢。


更新于2008年11月10日16:25

一个跟进注释 – 如果你将它分解为try / finally中的方法调用,就像在Scott的第二篇文章中那样,finally块中的调用应该是:

 parentWindow.ReleaseHandle(); 

所以你从VB6调用一个C#Windows Form类,这意味着你可能正在使用Show()ShowDialog() ,对吗? 这两个方法都采用IWin32Window参数,该参数只定义一个返回名为Handle的IntPtr属性的对象。

所以…你需要为你的Windows窗体类添加一个重载的构造函数(或ShowDialog方法),它需要一个long参数,这样你就可以将VB6 hwnd传递给窗体了。 进入C#代码后,您需要从hwnd创建一个IntPtr并将其分配给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; } } 

这太长了,不能发表评论……

我认为你遇到的问题是你包装我在ShowDialog重载中呈现的代码的方式。 如果您按照GetWindowFromHost代码执行的操作,则执行以下步骤:

  1. 从给定的hwnd创建一个新的IntPtr。
  2. 创建一个新的NativeWindow对象并将其句柄指定为IntPtr。
  3. 将IntPtr(在finally块中)设置为IntPtr.Zero。

我认为这是最终阻碍你的问题。 在我的代码中,finally块将在调用this.ShowDialog(nativeWindow)完成后运行。 此时,不再使用句柄(IntPtr)。 在你的代码中,你将返回一个IWin32Window ,该IWin32Window仍然应该持有对该IntPtr的引用,当你调用launchTarget.ShowDialog(parentWindow)时,它引用了一个引用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(); } 

这些更改应该有效,但这是未经测试的。