.net - DisplaySettingsChanging 上的 WPF 互操作死锁

标签 .net wpf winforms winforms-interop

我有一个托管无模式 Win32 表单的 WPF 应用程序。一切都运行顺利,直到我将 VNC 连接到机器或从机器上分离。然后应用程序陷入死锁:它不再重绘任何内容,也不对用户交互使用react。我使用 WinDbg 查看了堆栈跟踪:

0012f03c 792b6865 System.Threading.WaitHandle.WaitOne(Int32, Boolean)
0012f050 7b6f1a4f System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)
0012f064 7ba2d68b System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
0012f104 7b6f33ac System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
0012f138 7b920bd7 System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback, System.Object)
0012f150 7a92ed62 Microsoft.Win32.SystemEvents+SystemEventInvokeInfo.Invoke(Boolean, System.Object[])
0012f184 7a92dc8f Microsoft.Win32.SystemEvents.RaiseEvent(Boolean, System.Object, System.Object[])
0012f1d0 7a92daec Microsoft.Win32.SystemEvents.OnDisplaySettingsChanging()
0012f1e0 7a574c9f Microsoft.Win32.SystemEvents.WindowProc(IntPtr, Int32, IntPtr, IntPtr)
0012f1e4 003c20dc [InlinedCallFrame: 0012f1e4] 
0012f3a8 57843a57 System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
0012f3f8 57843129 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
0012f404 578430cc System.Windows.Threading.Dispatcher.Run()
0012f410 55bed46e System.Windows.Application.RunDispatcher(System.Object)
0012f41c 55bec76f System.Windows.Application.RunInternal(System.Windows.Window)
0012f440 55bd3aa6 System.Windows.Application.Run(System.Windows.Window)
0012f450 55bd3a69 System.Windows.Application.Run()

显然,VNC 连接/分离会引发一个 OnDisplaySettingsChanging 事件,该事件又尝试使用 System.Windows.Forms.Control.Invoke 调用某个事件,该事件发送向主线程发送消息,然后等待响应。但由于这一切都发生在主线程中,因此消息循环永远不会获取消息,并且等待永远不会返回。

我找到了使用 EnableSystemEventsThreadAffinityCompatibility 的解决方法(它本质上绕过了 Control.Invoke 调用),但感觉像是一个肮脏的黑客行为。

有人见过这样的事情发生吗?

有人知道为什么当消息到达主(STA)线程时SystemEvents类会使用Control.Invoke(确实如此,我检查过)?

编辑:评论中问题的答案:

  • 在没有 VNC 的情况下更改显示设置(例如分辨率)时是否会发生同样的情况? -> 不会。
  • VNC 上的几个不同版本(包括最新版本)是否会发生同样的情况? -> 我只尝试过最新版本 1.0.9.5。
  • 有关 WPF 应用、控件或 Win32 控件的任何其他详细信息吗? -> 有一个 WPF 主窗口和一个无模式 WinForms 窗体。

最佳答案

这是一个程序初始化问题。注意自定义启动画面。如果第一个事件订阅没有发生在主线程上,那么它将在错误的线程上触发通知。这可能会导致各种令人讨厌的问题,从奇怪的绘画伪影到彻底的僵局。请注意,当 Windows 主题或系统颜色更改时,一些标准 Winforms 控件将使用 SystemEvents 来了解何时应重新绘制自己。

一种解决方法是在完成其他操作之前在 Main() 方法中显式订阅虚拟事件处理程序。

关于.net - DisplaySettingsChanging 上的 WPF 互操作死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6600526/

相关文章:

c# - 在 C# 中,为什么 dictionary[0]++ 有效?

c# - CloudTableClient.CreateCloudTableClient 抛出 System.IO.FileNotFoundException 类型的异常

wpf - WPF 验证中的 ValidatesOnNotifyDataErrors 与 ValidatesOnDataErrors 和 NotifyOnValidationError 之间有什么区别?

.net - 如何使用ConcurrentDictionary,INotifyCollectionChanged,INotifyPropertyChanged创建自定义可观察集合

使用 ApplicationSettingsBase 的 C# 设置 - 漫游和通用

c# - 如何将 List<> 绑定(bind)到 dataGridview C#

c# - Windows 服务上的本地 Http 服务器

c# - 如何使用 Entity Framework `ValueComparer<T>` ?

c# - 是否可以在变量名的名称中使用变量号?

c# - 在 Winforms 中绘制心电图