.net &引用;创建窗口句柄时出错";

.net &引用;创建窗口句柄时出错";,.net,winforms,handles,.net,Winforms,Handles,我们正在开发一个非常大的.NET WinForms复合应用程序——不是CAB,而是一个类似的自行开发的框架。我们在Windows Server 2003上运行的Citrix和RDP环境中运行 我们开始遇到随机且难以再现的“创建窗口句柄时出错”错误,这似乎是应用程序中的一个老式句柄泄漏。我们大量使用第三方控件(Janus GridEX、Inflution VirtualTree和.NET Magic docking),并根据数据库中的元数据动态加载和呈现大量内容 谷歌上有很多关于这个错误的信息,但

我们正在开发一个非常大的.NET WinForms复合应用程序——不是CAB,而是一个类似的自行开发的框架。我们在Windows Server 2003上运行的Citrix和RDP环境中运行

我们开始遇到随机且难以再现的“创建窗口句柄时出错”错误,这似乎是应用程序中的一个老式句柄泄漏。我们大量使用第三方控件(Janus GridEX、Inflution VirtualTree和.NET Magic docking),并根据数据库中的元数据动态加载和呈现大量内容

谷歌上有很多关于这个错误的信息,但没有很多关于如何避免这个领域问题的可靠指导


stackoverflow社区对我构建易处理的winforms应用程序有什么好的指导吗?

我发现了很多UI在winforms中无法按预期卸载的问题

以下是一些一般提示:

  • 很多时候,控件将保持使用状态,因为控件事件没有被正确删除(工具提示提供程序在这里给我们造成了很大的问题),或者控件没有被正确处理
  • 在所有模式对话框周围使用“使用”块,以确保它们已被释放
  • 有些控件属性会在必要时强制创建窗口句柄(例如,设置TextBox控件的ReadOnly属性会强制实现该控件)
  • 使用类似的工具获取所创建类的计数。此工具的较新版本还将跟踪GDI和用户对象
  • 尽量减少Win API调用(或其他DllImport调用)的使用。如果确实需要使用互操作,请尝试以这样的方式包装这些调用,以使using/Dispose模式能够正常工作

我在工作时使用Janus控件。就处置本身而言,它们是极其危险的。我建议您确保正确处理它们。此外,与它们的绑定有时不会释放,因此您必须手动解除对象绑定以处置控件。

我遇到此异常,因为无休止的循环创建新的UI控件并设置其属性。 循环多次后,在更改控件visible属性时抛出此EXCTION。 我发现用户对象和GDI对象(来自任务管理器)都非常大


我猜您的问题与这些UI控件耗尽系统资源的原因类似。

在将控件添加到面板中时,我遇到了此异常,因为面板中的子控件未清除。如果在面板中处理子控件,则错误已修复

For k = 1 To Panel.Controls.Count
    Panel.Controls.Item(0).Dispose()
Next

我遇到了相同的.Net运行时错误,但我的解决方案不同

我的场景: 从返回DialogResult的弹出对话框中,用户将单击按钮发送电子邮件消息。我添加了一个线程,以便在后台生成报告时UI不会锁定。这个场景最终得到了那个不寻常的错误消息

导致问题的代码: 这段代码的问题是线程立即启动并返回,这导致返回DialogResult,在线程能够从字段中正确获取值之前,DialogResult会处理对话框

private void Dialog_SendEmailSummary_Button_Click(object sender, EventArgs e)
{
    SendSummaryEmail();
    DialogResult = DialogResult.OK;
}

private void SendSummaryEmail()
{
    var t = new Thread(() => SendSummaryThread(Textbox_Subject.Text, Textbox_Body.Text, Checkbox_IncludeDetails.Checked));
    t.Start();
}

private void SendSummaryThread(string subject, string comment, bool includeTestNames)
{
    // ... Create and send the email.
}
此场景的修复方法: 解决方法是在将值传递到创建线程的方法之前获取并存储这些值

private void Dialog_SendEmailSummary_Button_Click(object sender, EventArgs e)
{
    SendSummaryEmail(Textbox_Subject.Text, Textbox_Body.Text, Checkbox_IncludeDetails.Checked);
    DialogResult = DialogResult.OK;
}

private void SendSummaryEmail(string subject, string comment, bool includeTestNames)
{
    var t = new Thread(() => SendSummaryThread(subject, comment, includeTestNames));
    t.Start();
}

private void SendSummaryThread(string subject, string comment, bool includeTestNames)
{
    // ... Create and send the email.
}
理解这个错误 推动Windows的极限:用户和GDI对象——Mark Russinovich的第1部分:

故障排除此错误 你需要能够重现这个问题。这里有一种方法可以记录执行此操作的步骤

确定是什么创建了这么多句柄的最简单方法是打开TaskMgr.exe。在TaskMgr.exe中,您需要让用户对象、GDI对象和句柄列如图所示可见,为此,请选择“视图菜单”>“选择列”:

完成导致问题的步骤,并观察用户对象数量增加到大约10000个或GDI对象或句柄达到其极限

当看到对象或句柄增加(通常是急剧增加)时,可以通过单击“暂停”按钮在Visual Studio中停止代码执行

然后按住F10或F11键,浏览代码,观察对象/句柄计数急剧增加的情况

到目前为止,我找到的最好的工具是来自NirSoft的GDIView,它分解了GDI句柄字段:

我在设置DataGridViews列宽时使用了以下代码:

If Me.Controls.ContainsKey(comboName) Then
    cbo = CType(Me.Controls(comboName), ComboBox)
    With cbo
        .Location = New System.Drawing.Point(cumulativeWidth, 0)
        .Width = Me.Columns(i).Width
    End With
    'Explicitly cleaning up fixed the issue of releasing USER objects.
    cbo.Dispose()
    cbo = Nothing  
End If
这是堆栈跟踪:

位于System.Windows.Forms.Control.CreateHandle()的 位于的System.Windows.Forms.ComboBox.CreateHandle() System.Windows.Forms.Control.get_Handle()位于 System.Windows.Forms.ComboBox.InvalidateEverything()位于 System.Windows.Forms.ComboBox.OnResize(EventArgs e)位于 System.Windows.Forms.Control.OnSizeChanged(EventArgs e)位于 System.Windows.Forms.Control.UpdateBounds(Int32 x,Int32 y,Int32 宽度、Int32高度、Int32客户端宽度、Int32客户端高度) System.Windows.Forms.Control.UpdateBounds(Int32 x,Int32 y,Int32 宽度,Int32(高度) System.Windows.Forms.Control.SetBoundsCore(Int32 x,Int32 y,Int32 宽度,Int32高度,指定的边界)在 System.Windows.Forms.ComboBox.SetBoundsCore(Int32 x,Int32 y,Int32 宽度,Int32高度,指定的边界)在 System.Windows.Forms.Control.SetBounds(Int32 x,Int32 y,Int32 width, Int32高度,指定边界)在 System.Windows.Forms.Control.set_Width(Int32值)

以下是帮助我找出极限的关键:

“创建窗口句柄时出错”
当我为客户机开发的大型Windows窗体应用程序被积极使用时,用户经常会遇到“错误创建窗口句柄”异常

除了应用程序消耗太多资源之外
 this.Invoke((MethodInvoker)delegate
{
    //call your method here
});
private void ultraButton1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() => myMethod1());
}

void myMethod1()
{
    //my logic

    this.Invoke((MethodInvoker)delegate
    {
        ultraDesktopAlert1.Show($"my message header", "my message");
    });

    //my logic
}
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems