Kos L.A.
Kos L.A.

Reputation: 13

Win32Exception: Error Creating Window Handle (big number of nested controls)

First of all, sorry for my english since it's not my native language.

Problem was happened in my .NET Windows Forms Application and reproduced only on Virtaul PC Windows 7 (x64) for some reasons.

I faced with Win32Exception in one place of my application when resizing main application form containing a lot of custom controls, including two stacked to each other tabcontrols etc... Exception's message was "Error creating window handle". Spending some time I found solution for that problem on Microsoft Support site. It was very similar to my case. Qoute from the site:

In .NET applications, docked controls sometimes do not resize when their parents are resized if they are deeply nested. This problem occurs on both 64-bit and on 32-bit platforms, but requires a deeper nesting level on 32-bit systems.

What happens is that when the top level control lays out, SetBoundsCore calls SetWindowPos to resize the child controls. Each child control receives a WM_WINDOWPOSCHANGED notification, which triggers a layout event, which calls SetBoundsCore, which calls SetWindowPos. Each call to SetWindowPos goes into kernel mode and then back out to deliver the WM_WINDOWPOSCHANGED notification. Eventually the thread runs out of kernel stack space and SetWindowPos fails silently.

Proposed solution is to override OnSizeChanged method for container controls (like Panels or TabControl (in my case)):

    protected override void OnSizeChanged(EventArgs e)
    {
        if (this.Handle != null)
        {
            BeginInvoke((MethodInvoker)(() => base.OnSizeChanged(e);));
        }
    }

I successfully applied this solution to my case: created custom TabControl (inherited from plain winforms TabControl class) and changed TabControl instance with my custom control instance. And problem was gone away! But...

...When I launched Build on CCnet build machine I've got a lot of Win32Exception-s "Error creating window handle" in different unit tests but what is most interesting not in place of my problematic control (containing custom TabControl object) unit test! Error cases were different but they wasn't related to my custom control. When i reverted changes back everything was ok, build was created (unit tests performed successfully).

It totally confused me that applied change fixes user application workability but lead to unit tests fails when creating a build.

By the way, on local machine all unit tests are performed ok in any cases (with or without fix).

I spent a lot time on investigation of this problem and now I have only one assumption: ccnet build machine performs all unit tests in one process and tests don't dispose test data (gdi objects) correctly (on teardown) since the error "Error creating window handle" usually happens when limit of allowed gdi object handles (10000) is reached.

Could you please share you professional opinion? Thanks a lot in advance.

Upvotes: 1

Views: 1555

Answers (3)

Markus Stoll
Markus Stoll

Reputation: 1

I had the same problem with deeply nested Controls. However for a proper solution, I had to overwrite and delay SetBoundsCore

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        if (this.IsHandleCreated)
        {
            this.BeginInvoke(
                             (MethodInvoker)delegate
                             {
                                 base.SetBoundsCore(x, y, width, height, specified);
                             });
        }
    }

Upvotes: 0

jlew
jlew

Reputation: 10601

If running as a unit test on the CCNET machine, it is probably running in a non-interactive service context, which may prevent windows from being created because there is no one to view them.

Upvotes: 0

roken
roken

Reputation: 4014

Not directly related to your error, but accessing the Handle property will force the creation the window handle, which sometimes is not possible. Handle checks should not be performed like this:

if (this.Handle != null)

instead, check the IsHandleCreated property:

if (this.IsHandleCreated)

I had mentioned this on the blog post about this issue a while back but it doesn't seem to have been noted.

Upvotes: 0

Related Questions