首先,我的英語很抱歉,因爲它不是我的母語。Win32Exception:創建窗口句柄時出錯(大量嵌套控件)
問題發生在我的.NET Windows窗體應用程序中,出於某些原因僅在Virtaul PC Windows 7(x64)上覆制。
我在應用程序的一個地方遇到了Win32Exception,當調整包含大量自定義控件的主要應用程序表單時,包括兩個彼此堆疊的tabcontrols等等......異常的消息是「創建窗口句柄時出錯」。花一些時間,我在微軟支持網站上發現了這個問題的解決方案。這與我的情況非常相似。來自網站的Qoute:
在.NET應用程序中,如果父對象嵌套深度較大時,它們的父對象的調整大小有時不會調整。在64位和32位平臺上都會發生此問題,但在32位系統上需要更深的嵌套級別。
會發生什麼情況是,當頂層控件佈局時,SetBoundsCore調用SetWindowPos來調整子控件的大小。每個子控件都會收到一個WM_WINDOWPOSCHANGED通知,該通知觸發一個佈局事件,該事件調用SetBoundsCore,該事件調用SetWindowPos。每次調用SetWindowPos進入內核模式,然後退出以傳遞WM_WINDOWPOSCHANGED通知。最終線程將耗盡內核堆棧空間,並且SetWindowPos會自動失敗。
建議的解決方案是重寫爲容器控件OnSizeChanged方法(如面板或TabControl的(在我的情況)):
protected override void OnSizeChanged(EventArgs e)
{
if (this.Handle != null)
{
BeginInvoke((MethodInvoker)(() => base.OnSizeChanged(e);));
}
}
我成功地應用於該溶液到我的情況下:創建的自定義的TabControl(繼承自純winForms TabControl類)和改變TabControl實例與我的自定義控件實例。問題就消失了!但...
...當我在CCnet構建機器上啓動Build時,我在不同的單元測試中出現了很多Win32Exception -s「Error creation window handle」,但最有趣的不是我的問題控件(包含自定義TabControl對象)單元測試!錯誤情況有所不同,但它們與我的自定義控件無關。當我恢復更改時,一切正常,構建已創建(單元測試成功執行)。
它使我完全困惑,應用更改修復了用戶應用程序的可用性,但導致創建構建時單元測試失敗。
順便說一句,在本地機器上,所有的單元測試在任何情況下都可以正常執行(有或沒有修復)。
我花了很多時間研究這個問題,現在我只有一個假設:ccnet構建機器在一個進程中執行所有單元測試,並且測試不會正確地處理測試數據(gdi對象)(在拆卸時),因爲在達到允許的gdi對象句柄的限制(10000)時,通常會發生錯誤「創建窗口句柄錯誤」。
請您分享一下您的專業意見嗎?提前致謝。
謝謝!我會做出適當的改變。我也安裝了resharper,並且它總是標記爲「if(this.Handle!= null)」,表明它是多餘的「條件總是如此......」。老實說,我不明白是否有可能調整大小將在沒有創建句柄的控制上完成?僅僅是這種可能的處置控制? –
是的,size屬性可以在創建句柄之前更改(通常在顯示控件時)。例如當Size通過設計器設置時,它在控件的構造函數中設置。 – roken