我是否可以使用 hwnd / NativeWindow 获取设置 WinForms 表单所有者的行为

本文关键字:表单 WinForms 所有者 设置 获取 可以使 是否 hwnd NativeWindow | 更新日期: 2023-09-27 17:47:20

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

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


更新 Oct 20 '08 在 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。 如果您有任何其他建议,请回复。 再次感谢。


更新 11月 10 '08 在 16:25

一个后续评论 - 如果你把它分解到一个 try/finally 的方法调用中,就像 Scott 的第二篇文章一样,finally 块中的调用应该是:

parentWindow.ReleaseHandle();

我是否可以使用 hwnd / NativeWindow 获取设置 WinForms 表单所有者的行为

所以你从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
  4. (在 finally 块中)设置为 IntPtr.Zero。

我认为是这个最终的障碍给你带来了问题。在我的代码中,最后一个块将在调用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();
}

这些更改应该有效,但这同样未经测试。