title: Find Target Thread of Invocation in Memory Dump Using Windbg
body: <p><strong>Background</strong></p>
  
  <p>A customer reported a hang in a C# application.  I have a memory dump at the point the application was hung.  The memory dump shows the main UI thread displaying a progress form and multiple background threads running.  One of the background threads is trying to Control.Invoke back to the main thread to update the form.  The CLR stack looks like this:</p>
  
  <pre><code>System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean) 
  System.Threading.WaitHandle.WaitOne(Int64, Boolean) 
  System.Threading.WaitHandle.WaitOne(Int32, Boolean) 
  System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle) 
  System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean) 
  System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[]) 
  profdata.com.Library.frmAsyncExec.SetMessageText(System.String) 
  profdata.com.Library.frmAsyncExec.SetMessage(System.String, System.String) 
  profdata.com.Library.frmAsyncExec.DoAsyncProcess(System.Object) 
  System.Threading.ThreadHelper.ThreadStart_Context(System.Object) 
  System.Threading.ExecutionContext.runTryCode(System.Object) 
  System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 
  System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
  System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
  System.Threading.ThreadHelper.ThreadStart(System.Object) 
  </code></pre>
  
  <p>The UI thread is in a modal loop and awaiting a message:</p>
  
  <pre><code>System.Windows.Forms.UnsafeNativeMethods.WaitMessage() 
  System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32) 
  System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext) 
  System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext) 
  System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form) 
  System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window) 
  profdata.com.Library.frmAppletBaseForm.ShowDialog(System.Windows.Forms.IWin32Window) 
  profdata.com.Library.frmAsyncExec.ExecuteProcess(System.Windows.Forms.IWin32Window) 
  </code></pre>
  
  <p>I verified that the only message in the message queue (that I can see) is a paint message.  Message 15 corresponds to WM_PAINT:</p>
  
  <pre><code>0:000&gt; !dso
  OS Thread Id: 0x126c (0)
  ESP/REG  Object   Name
  ebx      01a688d0 System.Windows.Forms.Application+ThreadContext
  esi      01a6eb9c System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry
  edi      1b0c05e0 System.Collections.Hashtable+HashtableEnumerator
  0036e244 1b08430c System.Windows.Forms.NativeMethods+MSG[]
  
  0:000&gt; !da 1b08430c 
  Name: System.Windows.Forms.NativeMethods+MSG[]
  MethodTable: 67e0592c
  EEClass: 67be89b8
  Size: 40(0x28) bytes
  Array: Rank 1, Number of elements 1, Type VALUETYPE
  Element Methodtable: 67e059dc
  
  0:000&gt; !dumpvc 67e059dc 1b084314
  Name: System.Windows.Forms.NativeMethods+MSG
  MethodTable 67e059dc
  EEClass: 67bbd880
  Size: 36(0x24) bytes
   (C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)
  Fields:
        MT    Field   Offset                 Type VT     Attr    Value Name
  691b35f0  4002ba0        0        System.IntPtr  1 instance    b02ee hwnd
  691b2f74  4002ba1        4         System.Int32  1 instance       15 message
  691b35f0  4002ba2        8        System.IntPtr  1 instance        0 wParam
  691b35f0  4002ba3        c        System.IntPtr  1 instance        0 lParam
  691b2f74  4002ba4       10         System.Int32  1 instance 264314085 time
  691b2f74  4002ba5       14         System.Int32  1 instance      188 pt_x
  691b2f74  4002ba6       18         System.Int32  1 instance      386 pt_y
  </code></pre>
  
  <p>I know that Control.MarshaledInvoke is implemented as a PostMessage of a known message:</p>
  
  <pre><code>private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
  {
      ...
      System.Windows.Forms.UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
      ...
  }
  </code></pre>
  
  <p>MSDN says this about <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944%28v=vs.85%29.aspx" rel="nofollow">PostMessage</a>:</p>
  
  <blockquote>
    <p>Places (posts) a message in the message queue associated with the
    thread that created the specified window and returns without waiting
    for the thread to process the message.</p>
  </blockquote>
  
  <p>I suspect that this is a classic case of a background thread accessing a UI object which is known to cause application hangs.  I am well aware this is a bad thing.</p>
  
  <p>Since there are multiple background threads, I would like to determine which background thread messed up.</p>
  
  <p><strong>Question</strong></p>
  
  <p>Is it possible to determine the destination thread for the call to Control.Invoke using information in the memory dump?</p>
  
  <p><strong>Work So Far</strong></p>
  
  <p>I've gotten a dump of the stack objects of the background thread:</p>
  
  <pre><code>0:000&gt; ~20s
  0:020&gt; !dso
  OS Thread Id: 0x5d8 (20)
  ESP/REG  Object   Name
  ecx      01a2b2d0 System.Runtime.Remoting.Contexts.Context
  0c42e49c 1b083e20 System.Threading.ManualResetEvent
  0c42e524 01a2006c System.Collections.Hashtable
  0c42e560 1b083e38 Microsoft.Win32.SafeHandles.SafeWaitHandle
  0c42e5fc 1b044128 System.Windows.Forms.PropertyStore
  0c42e608 1b060b68 System.Collections.Queue
  0c42e610 1b083de0 System.Windows.Forms.Control+ThreadMethodEntry
  0c42e65c 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec
  0c42e66c 1b083cb0 System.Object[]    (System.Object[])
  0c42e670 1b083c90 profdata.com.Library.frmAsyncExec+SetMessageDelegate
  0c42e674 1b083cc4 System.Windows.Forms.Control+MultithreadSafeCallScope
  0c42e694 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec
  </code></pre>
  
  <p>I've tried looing at the ThreadMethodEntry and the Context object, but I'm not sure what I'm looking for:</p>
  
  <pre><code>0:020&gt; !do 1b083de0 
  Name: System.Windows.Forms.Control+ThreadMethodEntry
  MethodTable: 67e05380
  EEClass: 67be8454
  Size: 52(0x34) bytes
   (C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)
  Fields:
        MT    Field   Offset                 Type VT     Attr    Value Name
  67dff750  40011b9        4 ...ows.Forms.Control  0 instance 1b043b30 caller
  67dff750  40011ba        8 ...ows.Forms.Control  0 instance 1b043b30 marshaler
  691b118c  40011bb        c      System.Delegate  0 instance 1b083c90 method
  691844f8  40011bc       10      System.Object[]  0 instance 1b083cb0 args
  691b0944  40011bd       14        System.Object  0 instance 00000000 retVal
  691b0ebc  40011be       18     System.Exception  0 instance 00000000 exception
  691847f4  40011bf       2c       System.Boolean  1 instance        1 synchronous
  691847f4  40011c0       2d       System.Boolean  1 instance        0 isCompleted
  69197b54  40011c1       1c ....ManualResetEvent  0 instance 1b083e20 resetEvent
  691b0944  40011c2       20        System.Object  0 instance 1b083e14 invokeSyncObject
  691ada1c  40011c3       24 ....ExecutionContext  0 instance 1b083cd0 executionContext
  691aa00c  40011c4       28 ...ronizationContext  0 instance 00000000 syncContext
  
  0:020&gt; !do 01a2b2d0 
  Name: System.Runtime.Remoting.Contexts.Context
  MethodTable: 691a210c
  EEClass: 68fcf620
  Size: 60(0x3c) bytes
   (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
  Fields:
        MT    Field   Offset                 Type VT     Attr    Value Name
  691844f8  4001f60        4      System.Object[]  0 instance 01a2b3a0 _ctxProps
  691a219c  4001f61        8 ...micPropertyHolder  0 instance 00000000 _dphCtx
  691a75b4  4001f62        c ...em.LocalDataStore  0 instance 00000000 _localDataStore
  69196f18  4001f63       10 ...ging.IMessageSink  0 instance 00000000 _serverContextChain
  69196f18  4001f64       14 ...ging.IMessageSink  0 instance 00000000 _clientContextChain
  691b1508  4001f65       18     System.AppDomain  0 instance 01a01298 _appDomain
  691844f8  4001f66       1c      System.Object[]  0 instance 00000000 _ctxStatics
  691b35f0  4001f67       20        System.IntPtr  1 instance   551520 _internalContext
  691b2f74  4001f68       24         System.Int32  1 instance        0 _ctxID
  691b2f74  4001f69       28         System.Int32  1 instance        3 _ctxFlags
  691b2f74  4001f6a       2c         System.Int32  1 instance        1 _numCtxProps
  691b2f74  4001f6b       30         System.Int32  1 instance        0 _ctxStaticsCurrentBucket
  691b2f74  4001f6c       34         System.Int32  1 instance        0 _ctxStaticsFreeIndex
  691a219c  4001f6d      654 ...micPropertyHolder  0   shared   static _dphGlobal
      &gt;&gt; Domain:Value  00557ff8:01a2b068 &lt;&lt;
  69189944  4001f6e      658 ...LocalDataStoreMgr  0   shared   static _localDataStoreMgr
      &gt;&gt; Domain:Value  00557ff8:01a2b07c &lt;&lt;
  691b2f74  4001f6f      b40         System.Int32  1   shared   static _ctxIDCounter
      &gt;&gt; Domain:Value  00557ff8:0 &lt;&lt;
  </code></pre>
  
  <p>Or maybe there is a more native approach that involves finding the association of the window handle to a specific thread, but if so, I don't know how to do that.</p>