Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenceExceptions

N

Niall

A colleague of mine previously made the following post in this newsgroup,
but it hasn't received any MS attention. We were reminded that we should
register our nospam alias with the .Net Passport that is linked to our MSDN
licenses, and it was reposted with that nospam alias, but it still hasn't
been answered. This is an important issue for us, some Microsoft insight
would be very useful.

Regards,

Niall

----------------

(Trying again, this time with the email address registered with our MSDN
subscription! Thanks Chris for pointing this out...)

We are receiving error reports with NullReferenceExceptions from our users
with stacks like the following:

at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,
IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WmUpdateUIState(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.ParkingWindow.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)

---------

Our error reporter also takes a stacktrace at the time the exception was
handled, and the common element in all of them is Control.CreateHandle() and
the dreaded ParkingWindow.

I don't believe this is a threading issue, our app is mostly
single-threaded. The OnThreadException method is manually called in code by
the NativeWindow.Callback method.

An example of the callstack to the handler:

at System.Windows.Forms.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,
IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.ParkingWindow.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,
IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,
IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WmCreate(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.IntCreateWindowEx(Int32
dwExStyle, String lpszClassName, String lpszWindowName, Int32 style, Int32
x, Int32 y, Int32 width, Int32 height, HandleRef hWndParent, HandleRef
hMenu, HandleRef hInst, Object pvParam)
at System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(Int32 dwExStyle,
String lpszClassName, String lpszWindowName, Int32 style, Int32 x, Int32 y,
Int32 width, Int32 height, HandleRef hWndParent, HandleRef hMenu, HandleRef
hInst, Object pvParam)
at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.AccessibilityNotifyClients(AccessibleEvents
accEvent, Int32 childID)
at System.Windows.Forms.RadioButton.OnCheckedChanged(EventArgs e)
at Application.Namespace.Control.InitializeComponent() ... which is from
InitializeComponent() in one of our usercontrols for example.

I have seen several posts in this newsgroup describing similar problems, has
anyone had any resolution on them?

Regards,
Matt
 
P

Paul F. Williams

Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you create the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
G

Guest

Hi Paul,

We are seeing similar intermittent crashing in our application. Your post is
helpful, but it is the only place on the net that I have found such a claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the .net
framework for Control.Dispose(disposing=false) is not correct in some manner.
Do you have more information on why and / or sample code to illustrate the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come
 
G

Guest

Paul,

I am unable to create a small example to reproduce the problem. However, in
our enterprise application, I can uncomment the cached controls I Disposed,
and the exception reappears. I'm reasonably convinced that Disposing of our
cached controls avoids the problem. I can't explain why.

The error message that led me to my solution was "Cannot call Dispose while
doing CreateHandle()." Using the .NET Reflector to look at the Control
class, I found this exception occurs only when Dispose(true) is called, and
only when the control believes it is currently being created. The GC thread
must have called Dispose(true). I'm not sure how. CreateHandle() calls
SetState(262144, true) when it begins. Dispose(true) checks for this flag
and, if set, throws an InvalidOperationException with the error message
above. How can the same control be created and disposed at the same time?

I only saw this particular exception once. I usually get some kind of null
pointer exception. The pattern always looks something like the stack trace I
included at the bottom.

Here, a form is being instantiated. The form's constructor constructs
MyControl. The MyControl constructor starts the Windows form designer code.
At the point of the exception, the form designer is setting a label's text.
As you can see, changing the text triggers the label to measure its text.
Measuring the text requires a Graphics object. Creating a graphics object
requires a valid window handle, so the control creates itself. Note that the
label has not yet been added to any parent.

(I find it odd that the Framework would create a control before it's even
been added to a parent, much less become visible. A better solution to me
would be to measure the text in CreateControl. This behavior may be related
to the crash.)

To create itself, the control calls CreateWindowEx. CreateWindowEx fires
the WM_CREATE message back to the control, which its WndProc forwards to the
WmCreate() method.

WmCreate forwards the message to its DefWndProc. Then, it immediately fires
the WM_CHANGEUISTATE message with a parameter of UIS_INITIALIZE (3). Windows
bounces the message to a callback, which trickles it back up to some
control's WmUpdateUIState method. WmUpdateUIState forwards it back to
DefWndProc, which sends it to the control's NativeWindow, where it crashes.
I wish I could determine which windows got the messages, and what the state
was, but the debugger doesn't let me inspect managed variables when debugging
a native crash.

Looking at a decompiled version of NativeWindow.DefWndProc, it looks like
the control is trying to call the win32 DefWndProc function. I'm not sure
why that crashes. It may be a simple check for null would fix the problem.
This is the decompiled version:

public void DefWndProc(ref Message m)
{
if (this.previousWindow == null)
{
if (this.defWindowProc == IntPtr.Zero)
{
m.Result = System.Windows.Forms.UnsafeNativeMethods.DefWindowProc(m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result =
System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(this.defWindowProc,
m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result = this.previousWindow.Callback(m.HWnd, m.Msg, m.WParam,
m.LParam);
}

If you look at the implementation of NativeWindow, you will see each
NativeWindow has a pointer to a previous window and a pointer to a next
window. The .NET Framework maintains a doubly linked list of windows. Every
NativeWindow has two variables, previousWindow and nextWindow, that point to
other NativeWindows. I don't fully understand this list, but I think it
tracks window handles. Creating a handle adds it and its window to the list,
and destroying one removes them. Furthermore, NativeWindows forward
unhandled messages to their previous windows. In this case, I don't think
there is a previous window. Maybe that indicates the topmost window, or
maybe it's because a parent has not been created. I'm not sure.

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being initialized. The
garbage collector thread would have to reclaim the window handles, because
they did not get properly Disposed. If the NativeWindow list maintenance
were not synchonized, there might be a race condition between the UI thead
and the GC thread. However, the Framework code looks safe, because it
synchronizes on the NativeWindow type. If Dispose and CreateHandle ran at
the same time, they shouldn't corrupt each other. It may be that a Dispose
in between CreateHandle calls somehow corrupted memory.

I think I have a solution, but I'm clueless as to why it works. What would
really help: if someone at Microsoft would analyze a dump. I can produce
them on demand.

(Is there a way to generate a dump from inside Visual Studio? I can do so
from windbg.exe, but that tool doesn't show me the managed methods, so I
can't tell if it's the same stack trace.)

BEGIN Typical Stack Trace
=====================================================

00000000()

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message m) + 0xde bytes

system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System.Windows.Forms.Message m) + 0x3b bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m) + 0x718 bytes

system.windows.forms.dll!System.Windows.Forms.GroupBox.WndProc(System.Windows.Forms.Message m) + 0x45 bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message m) + 0xde bytes

system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System.Windows.Forms.Message m) + 0x3b bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m) + 0x718 bytes

system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(System.Windows.Forms.Message m) + 0x36 bytes

system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(System.Windows.Forms.Message m) + 0x17 bytes

system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndProc(System.Windows.Forms.Message m) + 0xe bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message m) + 0xde bytes

system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m) + 0x960 bytes

system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(System.Windows.Forms.Message m) + 0x36 bytes

system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(System.Windows.Forms.Message m) + 0x17 bytes

system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndProc(System.Windows.Forms.Message m) + 0xe bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message m) + 0xde bytes

system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m) + 0x960 bytes

system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.Forms.Message m) + 0xca bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetDC() + 0x154
user32.dll!GetParent() + 0x16c
user32.dll!SendMessageW() + 0x49
system.windows.forms.dll!System.Windows.Forms.Control.SendMessage(int msg,
int wparam, int lparam) + 0x42 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WmCreate(System.Windows.Forms.Message m) + 0x45 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m) + 0x387 bytes

system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.Forms.Message m) + 0xca bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m) + 0xb bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetTopWindow() + 0x128
user32.dll!DefWindowProcW() + 0x183
user32.dll!GetSystemMenu() + 0x88
ntdll.dll!KiUserCallbackDispatcher() + 0x13
user32.dll!UserClientDllInitialize() + 0x9eb
user32.dll!CreateWindowExW() + 0x33

system.windows.forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(int
dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int
y, int width, int height, System.Runtime.InteropServices.HandleRef
hWndParent, System.Runtime.InteropServices.HandleRef hMenu,
System.Runtime.InteropServices.HandleRef hInst, System.Object pvParam) + 0x36
bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams cp) + 0x247 bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateHandle() +
0xd9 bytes
system.windows.forms.dll!System.Windows.Forms.Control.get_Handle() + 0x31
bytes

system.windows.forms.dll!System.Windows.Forms.Control.CreateGraphicsInternal() + 0x8 bytes
system.windows.forms.dll!System.Windows.Forms.Label.get_PreferredWidth() +
0x57 bytes
system.windows.forms.dll!System.Windows.Forms.Label.AdjustSize() + 0x85
bytes

system.windows.forms.dll!System.Windows.Forms.Label.OnTextChanged(System.EventArgs e) + 0x1b bytes
system.windows.forms.dll!System.Windows.Forms.Control.set_Text(string
value) + 0x6d bytes
myassembly.dll!my.namespace.MyControl.InitializeComponent() Line 647 C#
myassembly.dll!my.namespace.MyControl.MyControl() Line 494 C#
(boring stuff removed)

Paul Haefele said:
Hi Paul,

We are seeing similar intermittent crashing in our application. Your post is
helpful, but it is the only place on the net that I have found such a claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the .net
framework for Control.Dispose(disposing=false) is not correct in some manner.
Do you have more information on why and / or sample code to illustrate the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come

Paul F. Williams said:
Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you create the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
G

Guest

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being initialized.

That should read "It's possible the garbage collector thread collected
*dead* forms while *others* were being initialized."
 
M

Matt Garven

Hi Paul,

Thanks for the post. If you can create dumps on command, I'm very
interested. Ours manifests itself infrequently and I have not yet determined
a pattern or a method to reproduce the problem.

If you're familiar with WinDBG, you could try using SOS to see the managed
callstacks (see http://mtaulty.com/blog/archive/2004/08/03/609.aspx as a
guide). I'd be interested to analyse the dump also.

You said you had a solution, but you didn't know why it worked - what was
the solution?

Regards,
Matt

Paul F. Williams said:
Paul,

I am unable to create a small example to reproduce the problem. However, in
our enterprise application, I can uncomment the cached controls I Disposed,
and the exception reappears. I'm reasonably convinced that Disposing of our
cached controls avoids the problem. I can't explain why.

The error message that led me to my solution was "Cannot call Dispose while
doing CreateHandle()." Using the .NET Reflector to look at the Control
class, I found this exception occurs only when Dispose(true) is called, and
only when the control believes it is currently being created. The GC thread
must have called Dispose(true). I'm not sure how. CreateHandle() calls
SetState(262144, true) when it begins. Dispose(true) checks for this flag
and, if set, throws an InvalidOperationException with the error message
above. How can the same control be created and disposed at the same time?

I only saw this particular exception once. I usually get some kind of null
pointer exception. The pattern always looks something like the stack trace I
included at the bottom.

Here, a form is being instantiated. The form's constructor constructs
MyControl. The MyControl constructor starts the Windows form designer code.
At the point of the exception, the form designer is setting a label's text.
As you can see, changing the text triggers the label to measure its text.
Measuring the text requires a Graphics object. Creating a graphics object
requires a valid window handle, so the control creates itself. Note that the
label has not yet been added to any parent.

(I find it odd that the Framework would create a control before it's even
been added to a parent, much less become visible. A better solution to me
would be to measure the text in CreateControl. This behavior may be related
to the crash.)

To create itself, the control calls CreateWindowEx. CreateWindowEx fires
the WM_CREATE message back to the control, which its WndProc forwards to the
WmCreate() method.

WmCreate forwards the message to its DefWndProc. Then, it immediately fires
the WM_CHANGEUISTATE message with a parameter of UIS_INITIALIZE (3). Windows
bounces the message to a callback, which trickles it back up to some
control's WmUpdateUIState method. WmUpdateUIState forwards it back to
DefWndProc, which sends it to the control's NativeWindow, where it crashes.
I wish I could determine which windows got the messages, and what the state
was, but the debugger doesn't let me inspect managed variables when debugging
a native crash.

Looking at a decompiled version of NativeWindow.DefWndProc, it looks like
the control is trying to call the win32 DefWndProc function. I'm not sure
why that crashes. It may be a simple check for null would fix the problem.
This is the decompiled version:

public void DefWndProc(ref Message m)
{
if (this.previousWindow == null)
{
if (this.defWindowProc == IntPtr.Zero)
{
System.Windows.Forms.UnsafeNativeMethods.DefWindowProc(m.HWnd, m.Msg,
m.WParam, m.LParam);
return;
}
m.Result =
System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(this.defWindowProc,
m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result = this.previousWindow.Callback(m.HWnd, m.Msg, m.WParam,
m.LParam);
}

If you look at the implementation of NativeWindow, you will see each
NativeWindow has a pointer to a previous window and a pointer to a next
window. The .NET Framework maintains a doubly linked list of windows. Every
NativeWindow has two variables, previousWindow and nextWindow, that point to
other NativeWindows. I don't fully understand this list, but I think it
tracks window handles. Creating a handle adds it and its window to the list,
and destroying one removes them. Furthermore, NativeWindows forward
unhandled messages to their previous windows. In this case, I don't think
there is a previous window. Maybe that indicates the topmost window, or
maybe it's because a parent has not been created. I'm not sure.

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being initialized. The
garbage collector thread would have to reclaim the window handles, because
they did not get properly Disposed. If the NativeWindow list maintenance
were not synchonized, there might be a race condition between the UI thead
and the GC thread. However, the Framework code looks safe, because it
synchronizes on the NativeWindow type. If Dispose and CreateHandle ran at
the same time, they shouldn't corrupt each other. It may be that a Dispose
in between CreateHandle calls somehow corrupted memory.

I think I have a solution, but I'm clueless as to why it works. What would
really help: if someone at Microsoft would analyze a dump. I can produce
them on demand.

(Is there a way to generate a dump from inside Visual Studio? I can do so
from windbg.exe, but that tool doesn't show me the managed methods, so I
can't tell if it's the same stack trace.)

BEGIN Typical Stack Trace
=====================================================

00000000()
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytessystem.windows.forms.dll!System.Windows.Forms.GroupBox.WndProc(System.Window
s.Forms.Message m) + 0x45 bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytessystem.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytessystem.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytessystem.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytessystem.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytessystem.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytessystem.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytessystem.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetDC() + 0x154
user32.dll!GetParent() + 0x16c
user32.dll!SendMessageW() + 0x49
system.windows.forms.dll!System.Windows.Forms.Control.SendMessage(int msg,
int wparam, int lparam) + 0x42 bytes
system.windows.forms.dll!System.Windows.Forms.Control.WmCreate(System.Window
s.Forms.Message m) + 0x45 bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x387 bytessystem.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetTopWindow() + 0x128
user32.dll!DefWindowProcW() + 0x183
user32.dll!GetSystemMenu() + 0x88
ntdll.dll!KiUserCallbackDispatcher() + 0x13
user32.dll!UserClientDllInitialize() + 0x9eb
user32.dll!CreateWindowExW() + 0x33

system.windows.forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWind
owEx(int
dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int
y, int width, int height, System.Runtime.InteropServices.HandleRef
hWndParent, System.Runtime.InteropServices.HandleRef hMenu,
System.Runtime.InteropServices.HandleRef hInst, System.Object pvParam) + 0x36
bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(Syst
em.Windows.Forms.CreateParams cp) + 0x247 bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateHandle() +
0xd9 bytes
system.windows.forms.dll!System.Windows.Forms.Control.get_Handle() + 0x31
bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateGraphicsInternal
() + 0x8 bytes
system.windows.forms.dll!System.Windows.Forms.Label.get_PreferredWidth() +
0x57 bytes
system.windows.forms.dll!System.Windows.Forms.Label.AdjustSize() + 0x85
bytes
system.windows.forms.dll!System.Windows.Forms.Label.OnTextChanged(System.Eve
ntArgs e) + 0x1b bytes
system.windows.forms.dll!System.Windows.Forms.Control.set_Text(string
value) + 0x6d bytes
myassembly.dll!my.namespace.MyControl.InitializeComponent() Line 647 C#
myassembly.dll!my.namespace.MyControl.MyControl() Line 494 C#
(boring stuff removed)

Paul Haefele said:
Hi Paul,

We are seeing similar intermittent crashing in our application. Your post is
helpful, but it is the only place on the net that I have found such a claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the .net
framework for Control.Dispose(disposing=false) is not correct in some manner.
Do you have more information on why and / or sample code to illustrate the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come

Paul F. Williams said:
Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you create the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
G

Guest

Matt,

Our particular problem seems to have been some controls that were created,
not added to any form, and never Disposed. The control itself does not yet
have a handle, but some of the Labels do, for reasons I explained below. I'm
guessing that the garbage collector is collecting the control and doing work
that is supposed to be done in the UI thread.

For example, we have a UserControl that is very slow to initialize. We
decided to create it once, store it in a local variable, and cache it until
used. However, we forgot to Dispose of this control. Because it's not a
child of some Form, it doesn't get Disposed automatically. Without Disposing
of the control, our app crashes after opening and closing a particular MDI
child several times. With the Dispose coded, it doesn't crash.

There may be more to it-- some combination of things our control was doing,
maybe, or something funny about our implementation-- but Disposing of the
cached controls fixed our problem. More details are in previous messages.

Matt Garven said:
Hi Paul,

Thanks for the post. If you can create dumps on command, I'm very
interested. Ours manifests itself infrequently and I have not yet determined
a pattern or a method to reproduce the problem.

If you're familiar with WinDBG, you could try using SOS to see the managed
callstacks (see http://mtaulty.com/blog/archive/2004/08/03/609.aspx as a
guide). I'd be interested to analyse the dump also.

You said you had a solution, but you didn't know why it worked - what was
the solution?

Regards,
Matt

Paul F. Williams said:
Paul,

I am unable to create a small example to reproduce the problem. However, in
our enterprise application, I can uncomment the cached controls I Disposed,
and the exception reappears. I'm reasonably convinced that Disposing of our
cached controls avoids the problem. I can't explain why.

The error message that led me to my solution was "Cannot call Dispose while
doing CreateHandle()." Using the .NET Reflector to look at the Control
class, I found this exception occurs only when Dispose(true) is called, and
only when the control believes it is currently being created. The GC thread
must have called Dispose(true). I'm not sure how. CreateHandle() calls
SetState(262144, true) when it begins. Dispose(true) checks for this flag
and, if set, throws an InvalidOperationException with the error message
above. How can the same control be created and disposed at the same time?

I only saw this particular exception once. I usually get some kind of null
pointer exception. The pattern always looks something like the stack trace I
included at the bottom.

Here, a form is being instantiated. The form's constructor constructs
MyControl. The MyControl constructor starts the Windows form designer code.
At the point of the exception, the form designer is setting a label's text.
As you can see, changing the text triggers the label to measure its text.
Measuring the text requires a Graphics object. Creating a graphics object
requires a valid window handle, so the control creates itself. Note that the
label has not yet been added to any parent.

(I find it odd that the Framework would create a control before it's even
been added to a parent, much less become visible. A better solution to me
would be to measure the text in CreateControl. This behavior may be related
to the crash.)

To create itself, the control calls CreateWindowEx. CreateWindowEx fires
the WM_CREATE message back to the control, which its WndProc forwards to the
WmCreate() method.

WmCreate forwards the message to its DefWndProc. Then, it immediately fires
the WM_CHANGEUISTATE message with a parameter of UIS_INITIALIZE (3). Windows
bounces the message to a callback, which trickles it back up to some
control's WmUpdateUIState method. WmUpdateUIState forwards it back to
DefWndProc, which sends it to the control's NativeWindow, where it crashes.
I wish I could determine which windows got the messages, and what the state
was, but the debugger doesn't let me inspect managed variables when debugging
a native crash.

Looking at a decompiled version of NativeWindow.DefWndProc, it looks like
the control is trying to call the win32 DefWndProc function. I'm not sure
why that crashes. It may be a simple check for null would fix the problem.
This is the decompiled version:

public void DefWndProc(ref Message m)
{
if (this.previousWindow == null)
{
if (this.defWindowProc == IntPtr.Zero)
{
System.Windows.Forms.UnsafeNativeMethods.DefWindowProc(m.HWnd, m.Msg,
m.WParam, m.LParam);
return;
}
m.Result =
System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(this.defWindowProc,
m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result = this.previousWindow.Callback(m.HWnd, m.Msg, m.WParam,
m.LParam);
}

If you look at the implementation of NativeWindow, you will see each
NativeWindow has a pointer to a previous window and a pointer to a next
window. The .NET Framework maintains a doubly linked list of windows. Every
NativeWindow has two variables, previousWindow and nextWindow, that point to
other NativeWindows. I don't fully understand this list, but I think it
tracks window handles. Creating a handle adds it and its window to the list,
and destroying one removes them. Furthermore, NativeWindows forward
unhandled messages to their previous windows. In this case, I don't think
there is a previous window. Maybe that indicates the topmost window, or
maybe it's because a parent has not been created. I'm not sure.

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being initialized. The
garbage collector thread would have to reclaim the window handles, because
they did not get properly Disposed. If the NativeWindow list maintenance
were not synchonized, there might be a race condition between the UI thead
and the GC thread. However, the Framework code looks safe, because it
synchronizes on the NativeWindow type. If Dispose and CreateHandle ran at
the same time, they shouldn't corrupt each other. It may be that a Dispose
in between CreateHandle calls somehow corrupted memory.

I think I have a solution, but I'm clueless as to why it works. What would
really help: if someone at Microsoft would analyze a dump. I can produce
them on demand.

(Is there a way to generate a dump from inside Visual Studio? I can do so
from windbg.exe, but that tool doesn't show me the managed methods, so I
can't tell if it's the same stack trace.)

BEGIN Typical Stack Trace
=====================================================

00000000()
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytessystem.windows.forms.dll!System.Windows.Forms.GroupBox.WndProc(System.Window
s.Forms.Message m) + 0x45 bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytessystem.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytessystem.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytessystem.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytessystem.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytessystem.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytessystem.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytessystem.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytessystem.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetDC() + 0x154
user32.dll!GetParent() + 0x16c
user32.dll!SendMessageW() + 0x49
system.windows.forms.dll!System.Windows.Forms.Control.SendMessage(int msg,
int wparam, int lparam) + 0x42 bytes
system.windows.forms.dll!System.Windows.Forms.Control.WmCreate(System.Window
s.Forms.Message m) + 0x45 bytessystem.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x387 bytessystem.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytessystem.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytessystem.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetTopWindow() + 0x128
user32.dll!DefWindowProcW() + 0x183
user32.dll!GetSystemMenu() + 0x88
ntdll.dll!KiUserCallbackDispatcher() + 0x13
user32.dll!UserClientDllInitialize() + 0x9eb
user32.dll!CreateWindowExW() + 0x33

system.windows.forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWind
owEx(int
dwExStyle, string lpszClassName, string lpszWindowName, int style, int x, int
y, int width, int height, System.Runtime.InteropServices.HandleRef
hWndParent, System.Runtime.InteropServices.HandleRef hMenu,
System.Runtime.InteropServices.HandleRef hInst, System.Object pvParam) + 0x36
bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(Syst
em.Windows.Forms.CreateParams cp) + 0x247 bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateHandle() +
0xd9 bytes
system.windows.forms.dll!System.Windows.Forms.Control.get_Handle() + 0x31
bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateGraphicsInternal
() + 0x8 bytes
system.windows.forms.dll!System.Windows.Forms.Label.get_PreferredWidth() +
0x57 bytes
system.windows.forms.dll!System.Windows.Forms.Label.AdjustSize() + 0x85
bytes
system.windows.forms.dll!System.Windows.Forms.Label.OnTextChanged(System.Eve
ntArgs e) + 0x1b bytes
system.windows.forms.dll!System.Windows.Forms.Control.set_Text(string
value) + 0x6d bytes
myassembly.dll!my.namespace.MyControl.InitializeComponent() Line 647 C#
myassembly.dll!my.namespace.MyControl.MyControl() Line 494 C#
(boring stuff removed)

Paul Haefele said:
Hi Paul,

We are seeing similar intermittent crashing in our application. Your post is
helpful, but it is the only place on the net that I have found such a claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the .net
framework for Control.Dispose(disposing=false) is not correct in some manner.
Do you have more information on why and / or sample code to illustrate the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come

:

Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you create the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
M

Matt Garven

Hi Paul,

It's highly likely that we're doing this also - it's just a matter of
finding out where.

I'm sceptical regarding the Finalizer doing work on the UI thread, that
would truly be a horrendous oversight. It could happen if Dispose was
overriden and the wrong value was passed to the base method (ie true when
"disposing" was false), but I doubt this could be the case in any of the
framework classes.

The bug looks very similar to another we've experienced regarding a race
condition in the dispose of the .NET ToolTip class, so it certainly is
possible that other race conditions exist in the framework regarding
disposing without it necessarily being the Finalizer doing work on the UI
thread. It's just a matter of tracking them down.

Regards,
Matt

Paul F. Williams said:
Matt,

Our particular problem seems to have been some controls that were created,
not added to any form, and never Disposed. The control itself does not yet
have a handle, but some of the Labels do, for reasons I explained below. I'm
guessing that the garbage collector is collecting the control and doing work
that is supposed to be done in the UI thread.

For example, we have a UserControl that is very slow to initialize. We
decided to create it once, store it in a local variable, and cache it until
used. However, we forgot to Dispose of this control. Because it's not a
child of some Form, it doesn't get Disposed automatically. Without Disposing
of the control, our app crashes after opening and closing a particular MDI
child several times. With the Dispose coded, it doesn't crash.

There may be more to it-- some combination of things our control was doing,
maybe, or something funny about our implementation-- but Disposing of the
cached controls fixed our problem. More details are in previous messages.

Matt Garven said:
Hi Paul,

Thanks for the post. If you can create dumps on command, I'm very
interested. Ours manifests itself infrequently and I have not yet determined
a pattern or a method to reproduce the problem.

If you're familiar with WinDBG, you could try using SOS to see the managed
callstacks (see http://mtaulty.com/blog/archive/2004/08/03/609.aspx as a
guide). I'd be interested to analyse the dump also.

You said you had a solution, but you didn't know why it worked - what was
the solution?

Regards,
Matt

Paul F. Williams said:
Paul,

I am unable to create a small example to reproduce the problem.
However,
in
our enterprise application, I can uncomment the cached controls I Disposed,
and the exception reappears. I'm reasonably convinced that Disposing
of
our
cached controls avoids the problem. I can't explain why.

The error message that led me to my solution was "Cannot call Dispose while
doing CreateHandle()." Using the .NET Reflector to look at the Control
class, I found this exception occurs only when Dispose(true) is
called,
and
only when the control believes it is currently being created. The GC thread
must have called Dispose(true). I'm not sure how. CreateHandle() calls
SetState(262144, true) when it begins. Dispose(true) checks for this flag
and, if set, throws an InvalidOperationException with the error message
above. How can the same control be created and disposed at the same time?

I only saw this particular exception once. I usually get some kind of null
pointer exception. The pattern always looks something like the stack trace I
included at the bottom.

Here, a form is being instantiated. The form's constructor constructs
MyControl. The MyControl constructor starts the Windows form designer code.
At the point of the exception, the form designer is setting a label's text.
As you can see, changing the text triggers the label to measure its text.
Measuring the text requires a Graphics object. Creating a graphics object
requires a valid window handle, so the control creates itself. Note
that
the
label has not yet been added to any parent.

(I find it odd that the Framework would create a control before it's even
been added to a parent, much less become visible. A better solution to me
would be to measure the text in CreateControl. This behavior may be related
to the crash.)

To create itself, the control calls CreateWindowEx. CreateWindowEx fires
the WM_CREATE message back to the control, which its WndProc forwards
to
the
WmCreate() method.

WmCreate forwards the message to its DefWndProc. Then, it immediately fires
the WM_CHANGEUISTATE message with a parameter of UIS_INITIALIZE (3). Windows
bounces the message to a callback, which trickles it back up to some
control's WmUpdateUIState method. WmUpdateUIState forwards it back to
DefWndProc, which sends it to the control's NativeWindow, where it crashes.
I wish I could determine which windows got the messages, and what the state
was, but the debugger doesn't let me inspect managed variables when debugging
a native crash.

Looking at a decompiled version of NativeWindow.DefWndProc, it looks like
the control is trying to call the win32 DefWndProc function. I'm not sure
why that crashes. It may be a simple check for null would fix the problem.
This is the decompiled version:

public void DefWndProc(ref Message m)
{
if (this.previousWindow == null)
{
if (this.defWindowProc == IntPtr.Zero)
{
m.Result =
System.Windows.Forms.UnsafeNativeMethods.DefWindowProc(m.HWnd, m.Msg,
m.WParam, m.LParam);
return;
}
m.Result =
System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(this.defWindowProc,
m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result = this.previousWindow.Callback(m.HWnd, m.Msg, m.WParam,
m.LParam);
}

If you look at the implementation of NativeWindow, you will see each
NativeWindow has a pointer to a previous window and a pointer to a next
window. The .NET Framework maintains a doubly linked list of windows. Every
NativeWindow has two variables, previousWindow and nextWindow, that
point
to
other NativeWindows. I don't fully understand this list, but I think it
tracks window handles. Creating a handle adds it and its window to
the
list,
and destroying one removes them. Furthermore, NativeWindows forward
unhandled messages to their previous windows. In this case, I don't think
there is a previous window. Maybe that indicates the topmost window, or
maybe it's because a parent has not been created. I'm not sure.

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being
initialized.
The
garbage collector thread would have to reclaim the window handles, because
they did not get properly Disposed. If the NativeWindow list maintenance
were not synchonized, there might be a race condition between the UI thead
and the GC thread. However, the Framework code looks safe, because it
synchronizes on the NativeWindow type. If Dispose and CreateHandle ran at
the same time, they shouldn't corrupt each other. It may be that a Dispose
in between CreateHandle calls somehow corrupted memory.

I think I have a solution, but I'm clueless as to why it works. What would
really help: if someone at Microsoft would analyze a dump. I can produce
them on demand.

(Is there a way to generate a dump from inside Visual Studio? I can do so
from windbg.exe, but that tool doesn't show me the managed methods, so I
can't tell if it's the same stack trace.)

BEGIN Typical Stack Trace
=====================================================

00000000()
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytes system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytes system.windows.forms.dll!System.Windows.Forms.GroupBox.WndProc(System.Window
s.Forms.Message m) + 0x45 bytes system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytes system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytes system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytes system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytes system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytes system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytes system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytes system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytes system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytes system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytes system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytes system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetDC() + 0x154
user32.dll!GetParent() + 0x16c
user32.dll!SendMessageW() + 0x49
system.windows.forms.dll!System.Windows.Forms.Control.SendMessage(int
msg,
int wparam, int lparam) + 0x42 bytes
system.windows.forms.dll!System.Windows.Forms.Control.WmCreate(System.Window
s.Forms.Message m) + 0x45 bytes system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x387 bytes system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytes system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetTopWindow() + 0x128
user32.dll!DefWindowProcW() + 0x183
user32.dll!GetSystemMenu() + 0x88
ntdll.dll!KiUserCallbackDispatcher() + 0x13
user32.dll!UserClientDllInitialize() + 0x9eb
user32.dll!CreateWindowExW() + 0x33
system.windows.forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWind
owEx(int
dwExStyle, string lpszClassName, string lpszWindowName, int style, int
x,
int
y, int width, int height, System.Runtime.InteropServices.HandleRef
hWndParent, System.Runtime.InteropServices.HandleRef hMenu,
System.Runtime.InteropServices.HandleRef hInst, System.Object pvParam)
+
0x36
system.windows.forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(Syst
em.Windows.Forms.CreateParams cp) + 0x247 bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateHandle() +
0xd9 bytes
system.windows.forms.dll!System.Windows.Forms.Control.get_Handle() + 0x31
bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateGraphicsInternal
() + 0x8 bytes system.windows.forms.dll!System.Windows.Forms.Label.get_PreferredWidth()
+
0x57 bytes
system.windows.forms.dll!System.Windows.Forms.Label.AdjustSize() + 0x85
bytes
system.windows.forms.dll!System.Windows.Forms.Label.OnTextChanged(System.Eve
ntArgs e) + 0x1b bytes
system.windows.forms.dll!System.Windows.Forms.Control.set_Text(string
value) + 0x6d bytes
myassembly.dll!my.namespace.MyControl.InitializeComponent() Line 647 C#
myassembly.dll!my.namespace.MyControl.MyControl() Line 494 C#
(boring stuff removed)

:

Hi Paul,

We are seeing similar intermittent crashing in our application. Your post is
helpful, but it is the only place on the net that I have found such
a
claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the ..net
framework for Control.Dispose(disposing=false) is not correct in
some
manner.
Do you have more information on why and / or sample code to
illustrate
the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come

:

Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you
create
the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
G

Guest

These cached controls did not get Disposed. Some of the controls still have
handles, especially labels, which create their handles when you set their
Text property. The garbage collector tries to destroy these controls from
the GC thread-- probably at the same time the UI thread is initializing some
other opened Form.

Take the .NET Reflector and look at the implementation of Control.Dispose.
The control was not Disposed properly, so it still has a handle. The garbage
collector will call Dispose(false). Dispose(false) does all sorts of
interesting things if the control has a handle, including posting a WM_CLOSE
message, SetWindowLong, GetWindowLong, GC.SupressFinalize, etc. (through
NativeWindow.ReleaseHandle). From what I recall from my Win32 days, it's a
very bad thing to be doing UI stuff in a non-UI thread.

Once, I did get a Dispose(true) in the GC thread. In fact, it appeared that
the same control was being created on the UI thread and Disposed on the GC
thread at the same time! The error message I got was "Cannot call Dispose
while doing CreateHandle()." This message led me down the path of Disposing
of these cached controls in the UI thread. I've not been able to reproduce
this particular condition.

Matt Garven said:
Hi Paul,

It's highly likely that we're doing this also - it's just a matter of
finding out where.

I'm sceptical regarding the Finalizer doing work on the UI thread, that
would truly be a horrendous oversight. It could happen if Dispose was
overriden and the wrong value was passed to the base method (ie true when
"disposing" was false), but I doubt this could be the case in any of the
framework classes.

The bug looks very similar to another we've experienced regarding a race
condition in the dispose of the .NET ToolTip class, so it certainly is
possible that other race conditions exist in the framework regarding
disposing without it necessarily being the Finalizer doing work on the UI
thread. It's just a matter of tracking them down.

Regards,
Matt

Paul F. Williams said:
Matt,

Our particular problem seems to have been some controls that were created,
not added to any form, and never Disposed. The control itself does not yet
have a handle, but some of the Labels do, for reasons I explained below. I'm
guessing that the garbage collector is collecting the control and doing work
that is supposed to be done in the UI thread.

For example, we have a UserControl that is very slow to initialize. We
decided to create it once, store it in a local variable, and cache it until
used. However, we forgot to Dispose of this control. Because it's not a
child of some Form, it doesn't get Disposed automatically. Without Disposing
of the control, our app crashes after opening and closing a particular MDI
child several times. With the Dispose coded, it doesn't crash.

There may be more to it-- some combination of things our control was doing,
maybe, or something funny about our implementation-- but Disposing of the
cached controls fixed our problem. More details are in previous messages.

Matt Garven said:
Hi Paul,

Thanks for the post. If you can create dumps on command, I'm very
interested. Ours manifests itself infrequently and I have not yet determined
a pattern or a method to reproduce the problem.

If you're familiar with WinDBG, you could try using SOS to see the managed
callstacks (see http://mtaulty.com/blog/archive/2004/08/03/609.aspx as a
guide). I'd be interested to analyse the dump also.

You said you had a solution, but you didn't know why it worked - what was
the solution?

Regards,
Matt

message Paul,

I am unable to create a small example to reproduce the problem. However,
in
our enterprise application, I can uncomment the cached controls I
Disposed,
and the exception reappears. I'm reasonably convinced that Disposing of
our
cached controls avoids the problem. I can't explain why.

The error message that led me to my solution was "Cannot call Dispose
while
doing CreateHandle()." Using the .NET Reflector to look at the Control
class, I found this exception occurs only when Dispose(true) is called,
and
only when the control believes it is currently being created. The GC
thread
must have called Dispose(true). I'm not sure how. CreateHandle() calls
SetState(262144, true) when it begins. Dispose(true) checks for this flag
and, if set, throws an InvalidOperationException with the error message
above. How can the same control be created and disposed at the same time?

I only saw this particular exception once. I usually get some kind of
null
pointer exception. The pattern always looks something like the stack
trace I
included at the bottom.

Here, a form is being instantiated. The form's constructor constructs
MyControl. The MyControl constructor starts the Windows form designer
code.
At the point of the exception, the form designer is setting a label's
text.
As you can see, changing the text triggers the label to measure its text.
Measuring the text requires a Graphics object. Creating a graphics object
requires a valid window handle, so the control creates itself. Note that
the
label has not yet been added to any parent.

(I find it odd that the Framework would create a control before it's even
been added to a parent, much less become visible. A better solution to me
would be to measure the text in CreateControl. This behavior may be
related
to the crash.)

To create itself, the control calls CreateWindowEx. CreateWindowEx fires
the WM_CREATE message back to the control, which its WndProc forwards to
the
WmCreate() method.

WmCreate forwards the message to its DefWndProc. Then, it immediately
fires
the WM_CHANGEUISTATE message with a parameter of UIS_INITIALIZE (3).
Windows
bounces the message to a callback, which trickles it back up to some
control's WmUpdateUIState method. WmUpdateUIState forwards it back to
DefWndProc, which sends it to the control's NativeWindow, where it
crashes.
I wish I could determine which windows got the messages, and what the
state
was, but the debugger doesn't let me inspect managed variables when
debugging
a native crash.

Looking at a decompiled version of NativeWindow.DefWndProc, it looks like
the control is trying to call the win32 DefWndProc function. I'm not sure
why that crashes. It may be a simple check for null would fix the
problem.
This is the decompiled version:

public void DefWndProc(ref Message m)
{
if (this.previousWindow == null)
{
if (this.defWindowProc == IntPtr.Zero)
{
m.Result =
System.Windows.Forms.UnsafeNativeMethods.DefWindowProc(m.HWnd, m.Msg,
m.WParam, m.LParam);
return;
}
m.Result =

System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(this.defWindowProc,
m.HWnd, m.Msg, m.WParam, m.LParam);
return;
}
m.Result = this.previousWindow.Callback(m.HWnd, m.Msg,
m.WParam,
m.LParam);
}

If you look at the implementation of NativeWindow, you will see each
NativeWindow has a pointer to a previous window and a pointer to a next
window. The .NET Framework maintains a doubly linked list of windows.
Every
NativeWindow has two variables, previousWindow and nextWindow, that point
to
other NativeWindows. I don't fully understand this list, but I think it
tracks window handles. Creating a handle adds it and its window to the
list,
and destroying one removes them. Furthermore, NativeWindows forward
unhandled messages to their previous windows. In this case, I don't think
there is a previous window. Maybe that indicates the topmost window, or
maybe it's because a parent has not been created. I'm not sure.

Our Window initialization takes a while. It's possible the garbage
collector thread collected some forms while they were being initialized.
The
garbage collector thread would have to reclaim the window handles, because
they did not get properly Disposed. If the NativeWindow list maintenance
were not synchonized, there might be a race condition between the UI thead
and the GC thread. However, the Framework code looks safe, because it
synchronizes on the NativeWindow type. If Dispose and CreateHandle ran at
the same time, they shouldn't corrupt each other. It may be that a
Dispose
in between CreateHandle calls somehow corrupted memory.

I think I have a solution, but I'm clueless as to why it works. What
would
really help: if someone at Microsoft would analyze a dump. I can produce
them on demand.

(Is there a way to generate a dump from inside Visual Studio? I can do so
from windbg.exe, but that tool doesn't show me the managed methods, so I
can't tell if it's the same stack trace.)

BEGIN Typical Stack Trace
=====================================================

00000000()


system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes


system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes


system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytes


system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytes


system.windows.forms.dll!System.Windows.Forms.GroupBox.WndProc(System.Window
s.Forms.Message m) + 0x45 bytes


system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes


system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes


system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes


system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes


system.windows.forms.dll!System.Windows.Forms.Control.WmUpdateUIState(System
..Windows.Forms.Message m) + 0x3b bytes


system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x718 bytes


system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytes


system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytes


system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytes


system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes


system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes


system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes


system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes


system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytes


system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(Syst
em.Windows.Forms.Message m) + 0x36 bytes


system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(Syste
m.Windows.Forms.Message m) + 0x17 bytes


system.windows.forms.dll!System.Windows.Forms.Application.ParkingWindow.WndP
roc(System.Windows.Forms.Message m) + 0xe bytes


system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes


system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes


system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System
..Windows.Forms.Message m) + 0xde bytes


system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Wind
ows.Forms.Message m) + 0xb bytes


system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x960 bytes


system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytes


system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes


system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetDC() + 0x154
user32.dll!GetParent() + 0x16c
user32.dll!SendMessageW() + 0x49
system.windows.forms.dll!System.Windows.Forms.Control.SendMessage(int
msg,
int wparam, int lparam) + 0x42 bytes


system.windows.forms.dll!System.Windows.Forms.Control.WmCreate(System.Window
s.Forms.Message m) + 0x45 bytes


system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows
..Forms.Message m) + 0x387 bytes


system.windows.forms.dll!System.Windows.Forms.Label.WndProc(System.Windows.F
orms.Message m) + 0xca bytes


system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.
Message m) + 0xb bytes


system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Me
ssage m) + 0xbc bytes
system.windows.forms.dll!System.Windows.Forms.NativeWindow.Callback(int
hWnd, int msg, int wparam, int lparam) + 0x30 bytes
008d8f32()
user32.dll!GetDC() + 0x72
user32.dll!GetTopWindow() + 0x128
user32.dll!DefWindowProcW() + 0x183
user32.dll!GetSystemMenu() + 0x88
ntdll.dll!KiUserCallbackDispatcher() + 0x13
user32.dll!UserClientDllInitialize() + 0x9eb
user32.dll!CreateWindowExW() + 0x33


system.windows.forms.dll!System.Windows.Forms.UnsafeNativeMethods.CreateWind
owEx(int
dwExStyle, string lpszClassName, string lpszWindowName, int style, int x,
int
y, int width, int height, System.Runtime.InteropServices.HandleRef
hWndParent, System.Runtime.InteropServices.HandleRef hMenu,
System.Runtime.InteropServices.HandleRef hInst, System.Object pvParam) +
0x36
bytes


system.windows.forms.dll!System.Windows.Forms.NativeWindow.CreateHandle(Syst
em.Windows.Forms.CreateParams cp) + 0x247 bytes
system.windows.forms.dll!System.Windows.Forms.Control.CreateHandle() +
0xd9 bytes
system.windows.forms.dll!System.Windows.Forms.Control.get_Handle() +
0x31
bytes


system.windows.forms.dll!System.Windows.Forms.Control.CreateGraphicsInternal
() + 0x8 bytes
system.windows.forms.dll!System.Windows.Forms.Label.get_PreferredWidth()
+
0x57 bytes
system.windows.forms.dll!System.Windows.Forms.Label.AdjustSize() + 0x85
bytes


system.windows.forms.dll!System.Windows.Forms.Label.OnTextChanged(System.Eve
ntArgs e) + 0x1b bytes
system.windows.forms.dll!System.Windows.Forms.Control.set_Text(string
value) + 0x6d bytes
myassembly.dll!my.namespace.MyControl.InitializeComponent() Line 647 C#
myassembly.dll!my.namespace.MyControl.MyControl() Line 494 C#
(boring stuff removed)

:

Hi Paul,

We are seeing similar intermittent crashing in our application. Your
post is
helpful, but it is the only place on the net that I have found such a
claim
is made. I wrote a simple test application to see the GC / UI threading
behavior when a Control is not explicitly disposed, and
Control.Dispose(disposing=false) is invoked on the UI thread from the GC
thread. This leads me to believe that there will be no threading issues
between the GC and the UI thread.

The only other explaination for what you state is that code in the ..net
framework for Control.Dispose(disposing=false) is not correct in some
manner.
Do you have more information on why and / or sample code to illustrate
the
point.

Thanks
Paul Haefele, Summit Systems
paul_haefele[at]summithq[dot]come

:

Matt,

We had very similar problems. Our app would crash intermittently.
Attaching with Visual Studio (managed and native), I saw the same
stack
traces.

Eventually, I got a trace that made sense. The error message was
something like "Cannot call Dispose when the handle is being created".
I saw there were two threads running. The UI thread was creating a
control, as shown in your stack trace. The second thread was the
garbage collector calling Dispose as part of destroying a control from
a previously opened form. This control had not been Disposed.

It seems there is a potential for a race condition inside the .NET
Framework. If you create a control without adding it to a form, it
does not automatically get Disposed. You have to Dispose of it
manually. If you don't, the garbage collector will attempt to Dispose
of the control. Doing so requires the GC thread to make changes to
global UI data being altered simultaneously on the UI thread.

One example of a control like this is a child form. Say you create
the
child form in your parent form's constructor and store it in a local
variable. You must Dispose of this Form yourself. The .NET Framework
does not and cannot do it for you.

For me, disposing of the cached controls in my form's Dispose method
fixed the problem. Hopefully, it will help you, too.
 
M

Matt Garven

Posting a message is ok though - that's not strictly a UI thing, as the
posted message will be handled by the message loop of the UI thread, not the
Finalizer thread.

The next call in Dispose, window.ReleaseHandle() eventually makes its way
into NativeWindow.UnSubclass, which makes the GetWindowLong and
SetWindowLong as you have correctly pointed out. The nIndex parameter is
passed in as -4, which is GWL_WNDPROC. When ReleaseHandle is called by the
control, it will either call SetWindowLong with the value of
previousWindow.windowProc or if there is no previous window (ie
previousWindow is null) it sets it to defWindowProc which is the
DefWindowProc function from user32.dll.

I don't know if this strictly counts as changing the UI from a non-UI
thread, however it does make me slightly suspicious when the errors we're
receiving look like this:

at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,
IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
at System.Windows.Forms.Control.DefWndProc(Message& m)

A NullReferenceException would be what you expect from a bad delegate being
passed into unmanaged code at some time in the past, I suppose.

Also, the errors seem to have the ParkingWindow in the callstack, which
would confirm what you've said regarding controls with no parent, like
labels auto-sizing before the parent has been assigned. The exceptions seem
to often occur during the InitializeComponent method of forms that have
controls that create their handle before the parent has been assigned. I'm
not sure what the implications of this are - does it mean the
ParkingWindow's NativeWindow has at some point been corrupted?

The GC.SuppressFinalize is valid because it is the NativeWindow instance
that is having it's finalization suppressed - this is valid because the
control has explicitly cleaned up the NativeWindow in the controls
finalizer, so there is no need for the finalizer to clean up the
NativeWindow instance.

Another NullReferenceException we've had has a callstack like this:

at System.Windows.Forms.UnsafeNativeMethods.IntDestroyWindow(HandleRef hWnd)
at System.Windows.Forms.UnsafeNativeMethods.DestroyWindow(HandleRef hWnd)
at System.Windows.Forms.NativeWindow.DestroyHandle()
at System.Windows.Forms.Control.DestroyHandle()
at System.Windows.Forms.Control.Dispose(Boolean disposing)
at System.Windows.Forms.ContainerControl.Dispose(Boolean disposing)
at System.Windows.Forms.Form.Dispose(Boolean disposing)
at System.ComponentModel.Component.Dispose()
at System.Windows.Forms.Form.WmClose(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr
wparam, IntPtr lparam)

And I've got another few slightly different ones. I'm reasonably sure
they're related.

Again Paul, thanks for your thoughts on this matter (and excuse my thinking
aloud) - I'll spend more effort looking for places where controls are not
being disposed properly, and see if we're using a cache anywhere in our
application. Other than that, I don't know where to look or how to debug the
situation further (especially as it only appears at client sites).

Regards,
Matt
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top