none
UI thread blocked on NotifyIcon.ShowContextMenu RRS feed

  • Question

  • Hi Windows Forms experts,

     

    We've developed a simple application that uses a tray icon with a simple context menu. For the first time today, we noticed the UI froze - the other threads of the application were running just fine. It all happened right around the time we right clicked on the tray icon in order to display its menu.


    We attached a debugger to the application and found the Main thread stuck indefinitely trying to show the tray icon's context menu. This is the stack the thread was stuck on:

     

    Code Snippet

     mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext)
      mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext)
      System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle)
      System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous)
      System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args)
      System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state)
      System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization = true, object[] args)
      System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization = true, object key = {object}, object[] args)
      System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanging(int msg, System.IntPtr wParam, System.IntPtr lParam)
      System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd = 1317942, int msg = 8218, System.IntPtr wParam = 47, System.IntPtr lParam = 122396224)
      [Native to Managed Transition]
      [Managed to Native Transition]
      System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.ShowContextMenu()
      System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.WndProc(ref System.Windows.Forms.Message msg)
      System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.NotifyIconNativeWindow.WndProc(ref System.Windows.Forms.Message m)
      System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg = 2048, System.IntPtr wparam, System.IntPtr lparam)
      [Native to Managed Transition]
      [Managed to Native Transition]
      mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext)
      mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext)
      System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle = {System.Threading.ManualResetEvent})
      System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous)
      System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args)
      System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state)
      System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization = true, object[] args = {object[2]})
      System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization = true, object key = {object}, object[] args = {object[2]})
      System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanging(int msg, System.IntPtr wParam, System.IntPtr lParam)
      System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd = 1317942, int msg = 8218, System.IntPtr wParam = 24, System.IntPtr lParam = 67704096)
      [Native to Managed Transition]
      [Managed to Native Transition]
      System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = -1, int pvLoopData = 0)
      System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = -1, System.Windows.Forms.ApplicationContext context = {ad})
      System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context)
      System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.ApplicationContext context)
      Program.exe!TestApplication.Main()

     

    What are we missing? Any ideas what could be wrong?

     

    Thanks,

     

    Don

    Wednesday, June 25, 2008 2:03 AM

Answers

  • Yup, your deadlocked solid.  There was a notification picked up by SystemEvents, just as the user clicked on the NotifyIcon.  Problem is, SystemEvents thinks it needs to Control.Invoke to another thread to deliver the notification.  That deadlocks because your app isn't pumping any messages, it's trying to display the context menu.

    It's risky to point fingers but your stack trace is pointing squarely at code that is playing fast and loose with threads.  Works for quite a while, maybe the odd painting problem here or there.  But the wrong combination of events and wham!  Three finger salute.

    Only access forms, controls and NI from the main UI thread.  Always Control.Invoke from a background thread to the main thread before touching any UI element.  Use .NET 2.0 so you're likely to get an exception in the debugger when you do it wrong.  Don't mess with CheckForIllegalCrossThreadCalls.
    Wednesday, June 25, 2008 2:51 AM
    Moderator

All replies

  • Yup, your deadlocked solid.  There was a notification picked up by SystemEvents, just as the user clicked on the NotifyIcon.  Problem is, SystemEvents thinks it needs to Control.Invoke to another thread to deliver the notification.  That deadlocks because your app isn't pumping any messages, it's trying to display the context menu.

    It's risky to point fingers but your stack trace is pointing squarely at code that is playing fast and loose with threads.  Works for quite a while, maybe the odd painting problem here or there.  But the wrong combination of events and wham!  Three finger salute.

    Only access forms, controls and NI from the main UI thread.  Always Control.Invoke from a background thread to the main thread before touching any UI element.  Use .NET 2.0 so you're likely to get an exception in the debugger when you do it wrong.  Don't mess with CheckForIllegalCrossThreadCalls.
    Wednesday, June 25, 2008 2:51 AM
    Moderator
  • I have exactly the same problem in our multi-threaded application, here is the GUI thread:

    Code Snippet

         [Managed to Native Transition]   
         System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.ShowContextMenu() + 0x113 bytes   
         System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.WndProc(ref System.Windows.Forms.Message msg = {System.Windows.Forms.Message}) + 0x166 bytes   
         System.Windows.Forms.dll!System.Windows.Forms.NotifyIcon.NotifyIconNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0xc bytes   
         System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 2048, System.IntPtr wparam, System.IntPtr lparam) + 0x57 bytes   
         [Native to Managed Transition]   
         [Managed to Native Transition]   
         System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = -1, int pvLoopData = 0) + 0x1c3 bytes   
         System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = -1, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) + 0x17d bytes   
         System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x53 bytes   
         System.Windows.Forms.dll!System.Windows.Forms.Application.Run() + 0x2b bytes   
    >    Dac.Core.dll!Dac.Core.Threading.InvokableThread.RunThread() Line 233 + 0x5 bytes    C#
         mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x3b bytes   
         mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 bytes   
         mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x40 bytes   


    Any ideas why this is deadlocking? I get no exceptions or MDA warnings - it just locks when I click on a context menu item.
    Tuesday, July 29, 2008 3:11 PM