How to deal with this C# hang invloving SystemEven

2020-06-28 00:56发布

问题:

My WinForm application having a hang problem. What happen is that client sometime leave the application running overnight and when they comeback in morning application is typically in a hang state. This is what I see in dump file on the main thread. What I don't understand is what could make SystemEvents.OnUserPreferenceChanged event to be invoked, although I don't think I am doing anything that is invoking this event.

0024e480 770496f4 System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean)  
0024e52c 702c68af System.Threading.WaitHandle.WaitOne(Int64, Boolean)  
0024e548 702c6865 System.Threading.WaitHandle.WaitOne(Int32, Boolean)  
0024e55c 6e891a6f System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)  
0024e570 6ebcd6eb System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)  
0024e610 6e8933cc System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])  
0024e644 6eac0c83 System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback, System.Object)  
0024e65c 6fe1eed2 Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke(Boolean, System.Object[])  
0024e690 6fe1d07f Microsoft.Win32.SystemEvents.RaiseEvent(Boolean, System.Object, System.Object[])  
0024e6dc 6fe1e38f Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(Int32, IntPtr, IntPtr)  
0024e6fc 6fa64c29 Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, IntPtr)  
0024e700 000a1104 [InlinedCallFrame: 0024e700]   
0024e8d8 6e378d5e System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)  
0024e974 6e3789c7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)  
0024e9c8 6e378811 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)  
0024e9f8 6e88de47 System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form)  
0024ea0c 6e8c25cb System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)  
0024ea98 6e8c27e3 System.Windows.Forms.Form.ShowDialog()  
0024ea9c 56c26e76 MyNameSpace.MyForm.MyMethod2(Object, Boolean, Boolean, System.Guid, Boolean)  
0024eba0 56c26c47 MyNameSpace.MyForm.MyMethod1(System.Guid, System.Guid, System.Guid, Boolean)  
0024ecf8 56c91f4c MyNameSpace.MyForm.MyButton_Click(System.Object, System.EventArgs)  
0024ee88 6e334180 System.Windows.Forms.Control.OnClick(System.EventArgs)  

回答1:

Controls subscribe this event so that they will redraw themselves when the user changed the theme or system colors. This event also gets fired when you're not close to the machine and Windows automatically locks the workstation. Which explains the morning-after hangover.

The deadlock is caused by a threading problem, the SystemEvents class fires the event on the wrong thread. Which is caused by an initialization problem in your program. The typical trigger is not creating the first window on the main thread, that confuzzles SystemEvents. It tries to fire an event on that same thread again but it isn't around anymore. Or it copied SynchronizationContext.Current before it got initialized by Winforms. Either way, the event will fire on a threadpool thread instead of the main UI thread. That's lethal.

Common when you implement your own splash screen for example. Use the built-in support instead.