WinForms关闭时WM_SETTINGCHANGE引发OnUserPreferenceChanging挂起的非延迟解决方案咨询
Windows Forms应用关闭时因
WM_SETTINGCHANGE消息导致挂起的解决方案 在一款关闭时会修改桌面布局的Windows Forms应用中,Windows Forms处理WM_SETTINGCHANGE消息时出现挂起,该问题会在应用关闭流程期间收到任何WM_SETTINGCHANGE消息时触发。除了添加任意延迟外,是否存在其他方法可以避免此挂起?
事件时间线
- 主线程关闭唯一窗体时,触发桌面布局修改(具体通过
SHAppBarMessage(ABM_REMOVE, ...)移除AppBar) - 主线程开始关闭流程,释放控件、窗体等资源
- ".NET System Events"线程收到
WM_SETTINGCHANGE消息,尝试调用主线程执行处理逻辑 - 由于主线程尚未完全关闭,
WindowsFormsSynchronizationContext.Send:82处的检测通过,允许跨线程调用 - ".NET System Events"线程进入
WaitHandle等待状态,等待主线程执行完成 - 主线程在主窗体关闭后退出消息循环,
Main方法返回 - 应用陷入挂起状态
挂起时调用栈
主线程(仅原生栈,无.NET栈)
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 * pdwindex) 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线程
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)
关键注意事项
- 未在后台线程创建控件,因此常规的跨线程控件创建挂起排查方案不适用
- 该问题属于已知的WinForms系统事件挂起场景,已有相关讨论案例
- 已向.NET WinForms官方提交Issue:关闭期间收到
WM_SETTINGCHANGE时出现挂起 - 复现条件:窗体上至少包含一个控件(通过
VisualStyleRenderer..cctor触发SystemEvents.UserPreferenceChanging事件注册) - 复现代码分为两类:基于
SHAppBarMessage的真实场景复现,以及基于SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, ...)的极简复现,同时提供了内存转储文件用于分析
内容的提问来源于stack exchange,提问作者Mitch
相关产品推荐
相关产品推荐

