In a windows form application which changes the desktop layout as it closes, Windows Forms seems to hang while processing a WM_SETTINGCHANGE
message. This seems to happen for any WM_SETTINGSCHANGE
message received between the start and end of application shutdown.
Apart from adding an arbitrary delay, is there a way to avoid this hang?
Apparent timeline of events:
- On main thread, in closing the only Form, a change to the desktop layout is triggered (specifically due to removing an AppBar with
SHAppBarMessage(ABM_REMOVE, ...)
) - The main thread begins shutting down (disposing controls, form, etc...)
- The ".NET System Events" thread receives
WM_SETTINGCHANGE
and Invokes to the main thread - Since the main thread has not shutdown, the test at
WindowsFormsSynchronizationContext.Send:82
succeeds - The ".Net System Events" thread enters a
WaitHandle
- The main thread, having had its main form closed, exits the message loop and
Main
returns - Hang
Call stacks at hang:
Main Thread (no .Net stack, only native)
win32u.dll!NtUserMsgWaitForMultipleObjectsEx()
combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long cEvents, unsigned long * lpdwSignaled) Line 2108
combase.dll!ClassicSTAThreadWaitForHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * pdwIndex) Line 54
combase.dll!CoWaitForMultipleHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * lpdwindex) Line 126
[Inline Frame] hostpolicy.dll!coreclr_t::shutdown(int *) Line 152
hostpolicy.dll!run_app_for_context(const hostpolicy_context_t & context, int argc, const wchar_t * * argv) Line 264
...snip...
.NET System Events thread
System.Private.CoreLib.dll!System.Threading.WaitHandle.WaitOneNoCheck(int millisecondsTimeout) Line 139
at /_/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs(139)
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) Line 3967
at /_/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs(3967)
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) Line 7141
at /_/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs(7141)
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) Line 6587
at /_/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs(6587)
System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) Line 88
at /_/src/System.Windows.Forms/src/System/Windows/Forms/WindowsFormsSynchronizationContext.cs(88)
Microsoft.Win32.SystemEvents.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization, object[] args) Line 35
at Microsoft.Win32\SystemEvents.cs(35)
Microsoft.Win32.SystemEvents.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization, object key, object[] args) Line 850
at Microsoft.Win32\SystemEvents.cs(850)
locals:
array[0]
._delegate = System.Windows.Forms.VisualStyles.VisualStyleRenderer.OnUserPreferenceChanging
._syncCtx = System.Windows.Forms.WindowsFormsSynchronizationContext
Microsoft.Win32.SystemEvents.dll!Microsoft.Win32.SystemEvents.WindowProc(nint hWnd, int msg, nint wParam, nint lParam) Line 961
at Microsoft.Win32\SystemEvents.cs(961)
locals:
msg = 8218
wParam = 0x2f
lParam = 0
[Native to Managed Transition]
[Managed to Native Transition]
Microsoft.Win32.SystemEvents.dll!Interop.User32.DispatchMessageW.____PInvoke|210_0(Interop.User32.MSG* msg)
Microsoft.Win32.SystemEvents.dll!Microsoft.Win32.SystemEvents.WindowThreadProc() Line 1038
at Microsoft.Win32\SystemEvents.cs(1038)
Notes:
- There are no controls being created on background threads (Debugging Windows Forms Application Hangs During SystemEvents.UserPreferenceChanged does not apply)
- Related: WinForms application hang due to SystemEvents.OnUserPreferenceChanged event
- Issue opened: Hang during exit if WM_SETTINGCHANGE is received
- At least one control is required on the form (to cause
SystemEvents.UserPreferenceChanging
to be created viaVisualStyleRenderer..cctor
) - Repro with
SHAppBarMessage
and memory dump - Minimal repro with
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, ...)