WPF взаимоблокировка взаимодействия на DisplaySettingsChanging - PullRequest
5 голосов
/ 06 июля 2011

У меня есть приложение WPF, которое содержит немодальную форму Win32. Все работает без сбоев, пока я не присоединю 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), но это похоже на грязный хак.

Кто-нибудь когда-нибудь видел что-нибудь подобное?

Кто-нибудь знает, почему класс SystemEvents будет использовать Control.Invoke, когда сообщение поступит в основной поток (STA) (это я проверял)?

РЕДАКТИРОВАТЬ: Ответы на вопросы в комментариях:

  • Происходит ли то же самое при изменении настроек дисплея (например, res) без VNC? -> Нет.
  • Происходит ли то же самое с парой разных версий VNC (включая последнюю версию hte)? -> Я пробовал только последнюю версию 1.0.9.5.
  • Любые другие сведения о приложении WPF, элементах управления или элементах управления Win32? -> Есть главное окно WPF и немодальная форма WinForms.

1 Ответ

2 голосов
/ 14 июля 2011

Это проблема инициализации программы. Следите за пользовательскими заставками. Если подписка на первое событие не происходит в главном потоке, то она будет запускать уведомления не в том потоке. Это может вызвать всевозможные неприятные проблемы, начиная от нечетных артефактов рисования и заканчивая тупиковой ситуацией. Помните, что несколько стандартных элементов управления Winforms будут использовать SystemEvents, чтобы знать, когда им следует перекрашиваться при изменении темы или системных цветов Windows.

Одним из обходных путей является явная подписка фиктивного обработчика события в методе Main (), прежде чем что-либо еще будет сделано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...