DisplaySettingsChanging 上的 WPF 互操作死锁

发布于 2024-11-18 18:52:17 字数 2309 浏览 3 评论 0原文

我有一个托管无模式 Win32 表单的 WPF 应用程序。一切都运行顺利,直到我将 VNC 连接到机器或从机器上分离。然后应用程序陷入死锁:它不再重绘任何内容,也不对用户交互做出反应。我使用 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 的情况下更改显示设置(例如 res)时是否会发生同样的情况? ->不会。
  • VNC 上的几个不同版本(包括最新版本)是否会发生同样的情况? ->我只尝试过最新版本1.0.9.5。
  • 有关 WPF 应用程序、控件或 Win32 控件的任何其他详细信息吗? ->有一个 WPF 主窗口和一个无模式 WinForms 窗体。

I have a WPF application that hosts a modeless Win32 form. Everything runs smoothly, until I attach or detach VNC to the machine. Then the application deadlocks: It doesn't redraw anything anymore, doesn't react to user interaction. I've looked at the stack trace using 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()

Apparently, the VNC attach/detach raises an OnDisplaySettingsChanging event, which in turn tries to call some event using System.Windows.Forms.Control.Invoke, which sends a message to the main thread and then waits for a response. But since this all happens in the main thread, the message loop never gets the message and the wait never returns.

I've found a workaround using EnableSystemEventsThreadAffinityCompatibility (which essentially bypasses the Control.Invoke call), but it feels like a dirty hack.

Did anybody ever see something like this happen?

Does someone have a clue why the SystemEvents class would use Control.Invoke when the message arrives on the main (STA) thread (it does, I checked)?

EDIT: Answers to questions in comments:

  • Does the same thing happen when changing display settings (e.g. res) without VNC? -> No.
  • Does the same thing happen with a couple of different versions on VNC (including hte latest)? -> I've only tried the latest version 1.0.9.5.
  • Any other details about the WPF app, controls, or Win32 contorls? -> There's a WPF main window and a modeless WinForms Form.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人生戏 2024-11-25 18:52:17

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

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

This is a program initialization problem. Watch out for custom splash screens. If the first event subscription doesn't happen on the main thread then it will fire notifications on the wrong thread. That can cause all kinds of nasty problems, ranging from odd painting artifacts to outright deadlock. Beware that several standard Winforms controls will use SystemEvents to know when they should repaint themselves when the Windows theme or system colors were changed.

One workaround is to explicitly subscribe a dummy event handler in the Main() method, before anything else is done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文