2011-07-06 18 views
5

Tengo una aplicación WPF que aloja un formulario Win32 no modal. Todo funciona sin problemas, hasta que conecte o desconecte VNC a la máquina. Luego, los puntos muertos de la aplicación: ya no vuelve a dibujar nada, no reacciona a la interacción del usuario. He mirado en el seguimiento de la pila utilizando WinDbg:Interbloqueo interoperabilidad WPF en DisplaySettingsChanging

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() 

Al parecer, el VNC se acopla/desacopla provoca un evento OnDisplaySettingsChanging, que a su vez intenta llamar a algún evento usando System.Windows.Forms.Control.Invoke, que envía un mensaje al hilo principal y luego espera una respuesta. Pero como todo esto sucede en el hilo principal, el ciclo de mensajes nunca recibe el mensaje y la espera nunca vuelve.

He encontrado una solución usando EnableSystemEventsThreadAffinityCompatibility (que esencialmente pasa por alto la llamada Control.Invoke), pero se siente como un hack sucio.

¿Alguien ha visto algo así?

¿Alguien tiene una pista de por qué la clase SystemEvents usaría Control.Invoke cuando el mensaje llegue al hilo principal (STA) (lo compruebo)?

EDIT: Las respuestas a las preguntas en los comentarios:

  • ¿Sucede lo mismo cuando se cambia la configuración de pantalla (por ejemplo) sin cosa VNC? -> No.
  • ¿Ocurre lo mismo con un par de versiones diferentes en VNC (incluida la última)? -> Solo he probado la última versión 1.0.9.5.
  • ¿Algún otro detalle sobre la aplicación WPF, los controles o los contornos de Win32? -> Hay una ventana principal de WPF y un formulario WinForms no modal.
+0

Pocos Qs: '1)' ¿Ocurre lo mismo al cambiar la configuración de pantalla (por ejemplo, res) sin VNC? '2)' ¿Pasa lo mismo con un par de versiones diferentes en VNC (incluida la última)? '3)' ¿Algún otro detalle sobre la aplicación WPF, los controles o los contornos de Win32? –

+1

Este es un problema de inicialización del programa. Tenga cuidado con las pantallas de presentación personalizadas. –

+0

@ Hans Passant: ¡Gracias! Creé un 'Form' al inicio porque necesitaba un' ISynchronizeInvoke', y eso causó el problema. Lo cambié a un 'Control', y todo funciona sin problemas ahora. Por favor, publique su comentario como respuesta, para que yo pueda aceptarlo. – Niki

Respuesta

1

Este es un problema de inicialización del programa. Tenga cuidado con las pantallas de presentación personalizadas. Si la suscripción al primer evento no ocurre en el hilo principal, disparará las notificaciones en el hilo equivocado. Eso puede causar todo tipo de problemas desagradables, desde extraños artefactos de pintura hasta un punto muerto total. Tenga en cuenta que varios controles estándar de Winforms usarán SystemEvents para saber cuándo deberían volver a pintarse cuando se modifique el tema de Windows o los colores del sistema.

Una solución consiste en suscribir explícitamente un controlador de eventos ficticio en el método Main(), antes de que se haga cualquier otra cosa.