3

我收到运行时错误“创建窗口句柄时出错”。根据我的研究,我知道此错误通常表明应用程序已超过 Windows 的 10,000 个句柄限制,我应该通过确保没有不必要地创建句柄并正确处理来解决该错误。

但是,我找不到任何有关导致创建窗口句柄的原因的文档。每次我实例化一个窗体时都会创建一个窗口句柄吗?每次我实例化一个控件?每次我实例化一个类?要不然是啥?

是不是说对于light-UI的应用,使用的句柄数量不需要特别在意,但是对于图形元素较多的应用,程序员就必须采取措施限制窗口句柄的数量?这就是“无窗口控件”和“轻量级控件”的全部意义吗?还有其他我应该了解的相关概念吗?

到目前为止,我还没有认为我的应用程序是 UI 密集型的。但是,它确实显示了一个图表网格,其中每个图表都是由几个组件控件组成的用户控件。对于大型分析,控制的总数可能达到数千。假设我想保留这个网格,有没有我可以应用的特定技术来保持句柄倒计时?例如,有没有办法“渲染”一个控件,使其仍然可见,但不再需要窗口句柄?

-TC

4

2 回答 2

4

但是,我找不到任何有关导致创建窗口句柄的原因的文档。

这可能是因为 .net 是一种抽象。

在 Win32 的“真实”世界中,窗口句柄由类型表示,HWND并赋予几乎所有东西。每个按钮、菜单等都可以有一个HWND.

实际上,这并不完全正确。您可以创建的每个对象(在 C Windows API 中)都有一个句柄。每个类通常只绘制整个控件 - 但是,某些控件可能会绘制更复杂的控件,例如额外的按钮。他们要么可以创建另一个窗口(控件),要么可以使用 GDI 来绘制它。

因此,并非您看到的所有内容都会生成 HWND - 但大多数情况都会生成。

有趣的是,您可能想知道要在 C/Win32 中创建控件,您使用CreateWindow(). 一切都是一个窗口

所以现在回到你的.net APP。如果您依赖的控件通过其底层CreateWindow调用创建大量对象,您将发出大量HWND变量并最终用完唯一标识符。

Mark Russinovich 在他推动 Windows 的限制时涵盖了实际限制,他故意尝试耗尽他的应用程序的分配。

那么是什么编程习惯导致了这种情况呢?创建太多 Window 对象。这可能与应用程序窗口意义上的实际 Windows 不对应,而是对应于控件的数量。避免这种情况的唯一方法是减少使用,或者如果第三方导致问题,请根据您一次可以显示的实际限制来设计您的应用程序。

另一种方法是生成您自己的控件,而不是使用子控件,而是绘制它们。然而,这可能是很多工作。

于 2012-04-25T20:36:57.983 回答
1

简而言之,窗口句柄被赋予每个交互的 UI 元素。每个真实的窗口、每个文本框、网格单元、按钮、菜单等等。尽管非交互式控件不需要窗口句柄,但如果编写不当,它们仍可能使用它们。

通常很难达到窗口句柄限制。如果发生这种情况并且您的应用程序不是特别密集的 UI,这通常意味着您正在泄漏句柄。如果您使用编写不当的可视化组件库而没有在应该释放资源时发生这种情况。窗口句柄是非托管资源,在不再需要时必须小心释放它。如果您碰巧使用库并观察到句柄泄漏,最好是更改库。它通常比听起来更难,因此作为一个糟糕的解决方法,您可以尝试强制垃圾收集器收集对象并希望在终结器/析构函数中释放所有非托管资源。

GC.Collect();

不能保证这会有所帮助,因为如果您使用的控件写得不好,即使在它们的终结器中,它们也可能不会释放句柄。同样,这是不好的做法,但如果您别无选择,可能会有所帮助。

如果您只使用标准的 .NET 控件,请确保您Close()在使用后的每个表单,而不仅仅是隐藏它。这将处理一个非对话框窗体及其所有控件,如果它们是标准控件,则不会泄漏。对话框表单需要在代码中处理。详细的文档在这里

于 2012-04-25T20:57:29.607 回答