WPF взаимоблокировка взаимодействия на DisplaySettingsChanging

У меня есть приложение 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 (включая последнюю версию)? -> Я только попробовал последнюю версию 1.0.9.5.
  • Любые другие подробности о приложении WPF, элементах управления или элементах управления Win32? -> Есть главное окно WPF и немодальная форма WinForms.

1 ответ

Решение

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

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

Другие вопросы по тегам