首先,对不起我的英语,因为它不是我的母语。
问题发生在我的 .NET Windows Forms 应用程序中,并且由于某些原因仅在 Virtaul PC Windows 7 (x64) 上重现。
当调整包含许多自定义控件的主应用程序窗体的大小时,我在应用程序的一个地方遇到了 Win32Exception,包括两个相互堆叠的 tabcontrols 等。异常的消息是“创建窗口句柄时出错”。我花了一些时间在 Microsoft 支持网站上找到了该问题的解决方案。这与我的情况非常相似。来自网站的引用:
在 .NET 应用程序中,停靠控件有时在它们的父级嵌套时不会调整大小。在 64 位和 32 位平台上都会出现此问题,但在 32 位系统上需要更深的嵌套级别。
发生的情况是,当顶层控件布局时,SetBoundsCore 调用 SetWindowPos 来调整子控件的大小。每个子控件都会收到一个 WM_WINDOWPOSCHANGED 通知,该通知会触发一个布局事件,该事件调用 SetBoundsCore,该事件调用 SetWindowPos。对 SetWindowPos 的每次调用都会进入内核模式,然后退出以传递 WM_WINDOWPOSCHANGED 通知。最终线程耗尽内核堆栈空间,SetWindowPos 静默失败。
建议的解决方案是覆盖容器控件的 OnSizeChanged 方法(如 Panels 或 TabControl(在我的情况下)):
protected override void OnSizeChanged(EventArgs e)
{
if (this.Handle != null)
{
BeginInvoke((MethodInvoker)(() => base.OnSizeChanged(e);));
}
}
我成功地将这个解决方案应用于我的案例:创建了自定义 TabControl(从普通的 winforms TabControl 类继承)并使用我的自定义控件实例更改了 TabControl 实例。问题消失了!但...
...当我在 CCnet 构建机器上启动 Build 时,我在不同的单元测试中遇到了很多 Win32Exception-s“创建窗口句柄时出错”,但最有趣的不是我有问题的控件(包含自定义 TabControl 对象)单元测试!错误情况不同,但它们与我的自定义控件无关。当我恢复更改时,一切正常,创建了构建(单元测试成功执行)。
应用更改修复了用户应用程序的可操作性,但在创建构建时导致单元测试失败,这让我完全感到困惑。
顺便说一句,在本地机器上,所有单元测试在任何情况下都可以正常执行(有或没有修复)。
我花了很多时间来调查这个问题,现在我只有一个假设:ccnet build machine 在一个进程中执行所有单元测试,并且测试没有正确处理测试数据(gdi 对象)(在拆卸时),因为错误“错误创建窗口句柄”通常发生在达到允许的 gdi 对象句柄 (10000) 的限制时。
能否请您分享您的专业意见?提前非常感谢。