ApartmentState para principiantes

Acabo de corregir un error al usar esto:

_Thread.SetApartmentState(ApartmentState.STA); 

¡Ahora me gustaría entender lo que significa y por qué funciona!

COM es el gran padre de .NET. Tenían objectives bastante elevados, una de las cosas que COM hace, pero .NET omite por completo proporcionar garantías de enhebrado para una clase. Una clase COM puede publicar qué tipo de requisitos de subprocesamiento tiene. Y la infraestructura COM se asegura de que se cumplan esos requisitos.

Esto está completamente ausente en .NET. Puede utilizar un objeto Queue <> por ejemplo en varios hilos, pero si no se bloquea correctamente, tendrá un error desagradable en su código que es muy difícil de diagnosticar.

Los detalles exactos del enhebrado COM son demasiado grandes para caber en una publicación. Me enfocaré en los detalles de tu pregunta. Un hilo que crea objetos COM tiene que decirle a COM qué tipo de soporte desea dar a las clases COM que tienen opciones de subprocesamiento restringidas. La gran mayoría de esas clases solo admiten el llamado subprocesamiento de apartamentos, sus métodos de interfaz solo se pueden llamar de forma segura desde el mismo subproceso que creó la instancia. En otras palabras, anuncian que “no soporto enhebrar nada, por favor, cuiden de no llamarme nunca del hilo equivocado”. Incluso si el código del cliente realmente lo llama desde otro hilo.

Hay dos tipos, STA (Single Threaded Apartment) y MTA. Se especifica en la llamada CoInitializeEx (), una función que cualquier subproceso que haga algo con COM debe invocar. El CLR realiza esa llamada automáticamente cada vez que inicia un hilo. Para el hilo principal de inicio de su progtwig, obtiene el valor para pasar del atributo [STAThread] o [MTAThread] en su método Main (). El predeterminado es MTA. Para los hilos que crea usted mismo, esto se determina mediante su llamada a SetApartmentState (). El predeterminado es MTA. Los hilos de Threadpool son siempre MTA, que no se pueden cambiar.

Hay muchos códigos en Windows que requieren una STA. Ejemplos notables son el Portapapeles, Drag + Drop y los diálogos de shell (como OpenFileDialog). El subproceso de interfaz de usuario de un proyecto WPF o Windows Forms siempre debe ser STA, al igual que cualquier subproceso que crea una ventana.

La promesa que le ha hecho a COM de que su hilo es STA, sin embargo , le exige que siga el contrato de un solo hilo. Son bastante rígidos y puede ser bastante difícil diagnosticar problemas cuando rompe el contrato. Los requisitos son que nunca bloquee el hilo por un período de tiempo y que bombee un ciclo de mensajes. El último requisito se cumple con un WPF o un subproceso de interfaz de usuario de Winforms, pero tendrá que encargarse usted mismo si crea su propio subproceso STA. El diagnóstico común para romper el contrato es un punto muerto.

Hay un poco de soporte integrado en el CLR para respaldar estos requisitos, ayudándote a evitar problemas. La instrucción de locking , por ejemplo, bombeará un bucle de mensaje cuando bloquee en un hilo STA. La mayoría de las clases de sincronización también lo hacen, Mutex es una excepción notable. Sin embargo, esto solo se ocupa del requisito de no bloquear , aún necesita crear su propio bucle de mensajes. Application.Run () en WPF y Winforms.

Anteriormente, contribuí con una respuesta que contiene más detalles sobre la importancia de tener un ciclo de mensajes para mantener COM satisfecho. Encontrarás la publicación aquí .