【问题标题】:Can I get the behavior of setting my WinForms form's owner using an hwnd / NativeWindow?我可以使用 hwnd / NativeWindow 设置我的 WinForms 表单所有者的行为吗?
【发布时间】:2010-09-17 20:07:59
【问题描述】:

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

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


2008 年 10 月 20 日 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。如果您有任何其他建议,请回复。再次感谢。


2008 年 11 月 10 日 16:25 更新

一个后续评论 - 如果您将其分解为 try/finally 中的方法调用,如 Scott 的第二篇文章中所述,finally 块中的调用应该是:

parentWindow.ReleaseHandle();

【问题讨论】:

  • Scott - 抱歉耽搁了这么久,被拖到了其他事情上。您提交的原始答案效果很好。我只需要通过 ShowDialog 传入 NativeWindow,而不是设置 Form.Owner。我的另一个问题是调用代码首先没有传递正确的 hWnd。谢谢
  • 仅供参考,以上两个问题都是可以解决的——对于居中性,确保设置:“form.StartPosition = FormStartPosition.CenterParent”——对于顶部性,确保设置:form.TopMost =真的; -- 顺便说一句,感谢有关 ReleaseHandle() 的信息! :-)

标签: c# winforms hwnd


【解决方案1】:

所以您正在从 VB6 调用 C# Windows 窗体类,这意味着您可能正在使用 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;
   }
}

【讨论】:

    【解决方案2】:

    这太长了,不能作为评论发布...

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

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

    我认为是这个 finally 块给你带来了问题。在我的代码中,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();
    }
    

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

    【讨论】:

      猜你喜欢
      • 2017-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      • 1970-01-01
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      相关资源
      最近更新 更多