Winforms问题 - 创建窗口句柄时出错

73

我们在一个Winform应用程序中看到了这个错误。有人能帮忙解释一下为什么会出现这个错误,更重要的是如何修复它或避免它发生。

System.ComponentModel.Win32Exception: 创建窗口句柄时出错。
   at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
   at System.Windows.Forms.Control.CreateHandle()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.OnVisibleChanged(EventArgs e)
   at System.Windows.Forms.ButtonBase.OnVisibleChanged(EventArgs e)
10个回答

54

你是否运行过Process Explorer或Windows任务管理器来查看GDI对象、句柄、线程和用户对象?如果没有,请选择这些列进行查看(任务管理器选择“查看”->“选择列”…),然后运行你的应用程序,查看该应用程序的这些列,看看其中一个是否在不断增长。

可能是因为你有一些UI组件认为已经被清理了,但实际上并没有被Disposed。

这里提供了一些相关帮助。

祝你好运!


2
我遇到了这个问题,发现我的应用程序报告了9600多个用户对象和1800多个GDI对象。我的问题是我没有做错任何事情,只是向FlowLayoutPanel添加了很多项。我想我必须“分页”显示的数据... - Gerardo Contijoch
我正在研究我的应用程序中的这个错误,然而在异常被抛出的时候,我的进程只有987个句柄,22个线程,98个用户对象和70个GDI对象。另外,那个链接现在已经失效了 :( - kwill
我正在研究我的应用程序中的这个错误,然而在异常被抛出的时候,我的进程只有987个句柄,22个线程,98个用户对象和70个GDI对象。另外,那个链接现在已经失效了 :( - undefined

32

你的应用程序的Windows句柄限制为10,000个句柄。由于你的程序创建了太多的句柄,所以出现了错误。你需要找到内存泄漏的原因。正如其他用户建议的那样,使用内存分析器。我也使用.NET内存分析器。此外,在从窗体中移除控件之前,确保调用控件上的Dispose方法(否则控件将不会被处理)。你还需要确保没有事件与该控件注册。我自己也有同样的问题,尽管我已经知道一些解决方法,但仍然有一些内存泄漏问题无法解决...


11

不再可用:“指定的CGI应用程序遇到错误,服务器终止了进程。” - ErocM
对我来说有效。 - Fabrice

7

这个问题几乎总是与GDI对象计数、用户对象计数或句柄计数有关,通常不是由于您的机器上出现了内存不足的情况。

当我跟踪这些错误时,我会打开ProcessExplorer并观察这些列:句柄、线程、GDI对象、用户对象、私有字节、虚拟大小和工作集。

(根据我的经验,问题通常是由于事件处理程序持有对象并防止其被处理导致对象泄漏。)


是的。我们该如何解决它? - Munavvar
1
在测试程序时,您可以通过观察句柄计数、线程计数、GDI 对象、用户对象等来解决问题。如果您发现任何一个计数在执行特定操作时上升而不下降,请检查实现该操作的代码。您应该寻找一些问题,比如长时间保留不需要的对象,或者在循环中重复创建对象而不释放它,或者在可以创建并引用对象一次的情况下无谓地重新创建对象,或者挂钩事件处理程序并在先取消事件处理程序后丢弃对象。 - AlfredBr
这对我很有帮助:“或者不必要地重新创建一个对象,而可以只创建一次并引用它。” - programingfrik

2

嗯,在我的情况下,肯定是用户对象失控了。我查看了Windows任务管理器,果然,用户对象计数正好为10,000。

我通过将属性或列表表格的容器面板的父级属性设置为选项卡页面的父级属性,动态地嵌入属性和列表表格。我根据正在列出的集合类型或正在检查的对象的类类型有条件地回收或重新创建属性和列表表格表单。

注意:在Delphi中,所有控件都有Owner和Parent属性。即使更改了控件的Parent属性,当拥有控件被销毁时,它仍将被其所有者处置。

在C#中,如果一个控件(例如Panel)通过更改Panel.Parent属性从Form编程重新分配到TabPage,则调用Dispose()方法不会处置Panel,调用TabPage上的Controls.Clear()方法也不会。即使直接调用Panel.Dispose()方法也不会实际处置它,除非先手动将其Parent属性设置为null。


2

我的应用程序出现了相同的错误。我在单个页面中加载了许多控件。在按钮点击事件中,我清除了这些控件。但是清除这些控件并没有释放它们占用的内存。因此,需要将这些控件从内存中释放。我注释掉了controls.clear()方法,并加入了一些代码来释放这些控件。

类似于以下内容:

For Each ctl As Control In controlCollection

ctl.Dispose()

Next


2

我认为这通常与计算机内存耗尽有关,因此无法创建更多的窗口句柄。在这一点上,通常Windows也会显示一些奇怪的行为。


1

我添加了一个检查,使它工作...

if (_form.Handle.ToInt32() > 0)
{
   _form.Invoke(method, args);
}

它总是正确的,但没有它,表格会抛出错误。 顺便说一下,我的句柄大约是490万


2
请注意,Handle属性的实现会检查句柄是否已创建,如果未创建,则会创建它。在.NET源代码中查看:public IntPtr Handle { get { ...if (!this.IsHandleCreated) { this.CreateHandle(); } ...}} IsHandleCreated属性将返回true/false而不创建句柄。 - Paul Williams

0

-1

内存不足的建议似乎不是一个坏的线索。

你的程序在做什么导致出现这个错误?

它创建了很多窗口或控件吗? 它是以编程方式创建它们而不是在设计时创建它们吗? 如果是这样,你是在一个循环中这样做吗?那个循环是无限的吗? 你是否以某种其他方式消耗了大量的内存?

当你观察任务管理器中应用程序使用的内存时会发生什么?它会飙升到天上吗?或者最好像上面建议的那样使用进程监视器来深入了解详情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接