Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc
From: Matt Garven (ediEnterprise_at_NoSpam.com)
Date: 02/01/05
- Next message: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Previous message: Eric: "Re: ComboBox DropDown does not display list item"
- Next in thread: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Reply: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Messages sorted by: [ date ] [ thread ]
Date: Tue, 1 Feb 2005 11:33:00 +1100
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" <Paul F. Williams@discussions.microsoft.com> wrote in
message news:EB4E483A-03AC-43CD-9201-53F73F4E04FF@microsoft.com...
> 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)
>
> "Paul Haefele" wrote:
>
> > 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" wrote:
> >
> > > 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.
>
- Next message: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Previous message: Eric: "Re: ComboBox DropDown does not display list item"
- Next in thread: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Reply: Paul F. Williams: "Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|