Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc

From: Matt Garven (ediEnterprise_at_NoSpam.com)
Date: 02/01/05


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.
>



Relevant Pages

  • Re: Repost for MS: UnsafeNativeMethods.CallWindowProc NullReferenc
    ... The control itself does not yet ... we forgot to Dispose of this control. ... >> requires a valid window handle, ... >> If you look at the implementation of NativeWindow, ...
    (microsoft.public.dotnet.framework.windowsforms)
  • Re: Entwicklung von Unix-Anwendung mit C++ (m/w)/ NRW : Ref.-Nr.: 37302/1
    ... I am responsible for design and implementation of the persistent data server working with mySQL. ... Developed within very short time the product was successfully installed ... Reengineering and implementing a display tool for Experimental Physics Industrial Control System ... Developed an operator interface under X Window for High Energy Physics Accelerator Control System. ...
    (de.markt.arbeit.d)
  • Re: loosing messages leakes my app...
    ... It posts messages to a window, ... why don't you always use PostMessage? ... threads rely on the control, then you should not destroy the control before the ... POSSIBLY know the unique target window for which this is intended. ...
    (microsoft.public.vc.mfc)
  • Re: Owner Draw STATIC Window with XP Themes
    ... >> You should open a theme once per window... ... Each OpenThemeData has a matching CloseThemeData. ... say, "Well, CloseThemeData doesn't take an HWND, it takes only an HTHEME, so ... The following code sample demonstrates how to draw a button control. ...
    (microsoft.public.vc.mfc)
  • Re: Owner Draw STATIC Window with XP Themes
    ... >> You should open a theme once per window... ... Each OpenThemeData has a matching CloseThemeData. ... say, "Well, CloseThemeData doesn't take an HWND, it takes only an HTHEME, so ... The following code sample demonstrates how to draw a button control. ...
    (microsoft.public.win32.programmer.kernel)