Pregunta

venir a través de lo que parece a primera vista como un MT-tema, pero estoy tratando de comprender en detalle el modelo utilizado por la STA COM +.

En efecto, tengo una herencia COM + componente, escrito en Visual Basic 6, que pone en un nativo (es decir, no-COM) Win32 DLL escrito en C ++.

Tener algunos problemas intermittant (e imposibles de reproducir en pruebas) con él, he añadido algo de código de depuración para averiguar lo que estaba pasando y se encontró que cuando se producen los problemas, que tenía mensajes intercalados en el archivo de registro - por lo que implicaba que el DLL estaba siendo llamado por dos hilos a la vez.

Ahora el registro va a un archivo para cada subproceso basado en _getpid () y GetCurrentThreadId (), por lo que parece que cuando el código en el C ++ DLL se llama, se está haciendo llama dos veces en el mismo hilo al mismo tiempo. Mi comprensión de STA dice sugiere que esto podría ser el caso como COM marshalls los casos individuales de los objetos en un único hilo suspende y reanuda la ejecución a voluntad.

Unfortuantly No estoy seguro de dónde ir desde aquí. Estoy leyendo que yo debería estar llamando CoInitialiseEx () en DllMain () para contar COM que este es un DLL de STA, pero otros lugares dicen que esto es válido sólo para archivos DLL COM y no tendrá ningún efecto en un DLL nativa. La única otra opción es envolver partes de la DLL por secciones como críticos para serializar el acceso (teniendo éxito cualquier actuación que tiene en la barbilla).

Yo podría tratar de reelaborar el DLL, pero no hay VARs estatales o compartidos a nivel mundial - todo está en las variables locales así que en teoría cada llamada debe recibir su propia pila, pero me pregunto si el modelo STA es, básicamente, teniendo algún extraño efecto sobre esto y acaba de volver a entrar en el DLL ya cargado en el mismo punto de entrada como otra llamada. Unfortuantly, no sé cómo demostrar o probar esta teoría.

Las preguntas son básicamente:

  1. Cuando un componente STA COM + llama a una DLL nativa, no hay nada en el modelo STA evitar el "hilo" activo de ser suspendido y el control se pasa a otro "hilo" en el medio de una llamada DLL?
  2. ¿Es CoInitialiseEx () de la manera correcta para resolver esto, o no?
  3. Si ninguno (1) o (2) son "buenas" suposiciones, lo que está pasando?
¿Fue útil?

Solución

En un servidor COM apartamento roscada, cada instancia de la clase COM se garantiza que se accede por un solo hilo. Este medio de la instancia es seguro para subprocesos. Sin embargo, muchos casos pueden ser creados simultaneamente, utilizando diferentes hilos. Ahora, en lo que se refiere al servidor COM, DLL nativa no tiene que hacer nada especial. Basta con pensar en kernel32.dll, que es utilizado por todos los ejecutables -? Qué inicializar COM cuando es utilizado por un servidor COM

Desde el punto de vista de DLL, usted tiene que asegurarse de que está seguro para subprocesos, ya que diferentes instancias que pueden llamar al mismo tiempo. STA no le protegerá en este caso. Puesto que usted dice que no está utilizando las variables globales, sólo puedo asumir que el problema está en otra parte, y sólo pasa a mostrar en circunstancias que parecen apuntar a las cosas COM. ¿Está seguro de que usted no tiene algunos viejos temas de fricción de memoria C ++?

Otros consejos

Sospecho que su problema era que en algún lugar profundo dentro de la llamada DLL, se hizo una llamada COM de salida a otro apartamento (otro hilo en el mismo proceso, o un objeto en el MTA, u otro proceso en su totalidad). COM permite que un subproceso STA esperando el resultado de una llamada saliente para recibir otra llamada entrante, procesarla de forma recursiva. Está pensado sólo para las conversaciones en curso entre los mismos objetos - es decir, A llama a B, B llama a una vuelta, A llama a B de nuevo - pero puede recibir llamadas de otros objetos si se ha entregado a cabo un puntero de interfaz a varios clientes, o el cliente ha compartido el puntero de interfaz a otro cliente. En general es una mala idea para repartir punteros de interfaz a un objeto de un único subproceso de múltiples subprocesos de cliente, ya que sólo tendrán que esperar por los demás. Crear un objeto trabajador por hilo.

COM no se puede suspender y reanudar la ejecución a voluntad sobre cualquier tema - una nueva llamada entrante en un subproceso STA sólo puede llegar a través de la bomba de mensajes. Cuando 'bloqueado' a la espera de una respuesta, el subproceso STA es en realidad bombeando mensajes, a instancias de Message Filter (ver IMessageFilter) si el mensaje debe ser manejado. Sin embargo, manejadores de mensajes no debe hacer una nueva llamada saliente - si lo hacen COM devolverá un error RPC_E_CANTCALLOUT_INEXTERNALCALL ( "Es ilegal llamar a cabo mientras que el filtro mensaje dentro")

Problemas similares podrían ocurrir si usted tiene un suministro de mensajes (GetMessage / DispatchMessage) en cualquier lugar dentro de la DLL nativa. He tenido problemas con DoEvents de VB en los procedimientos de interfaz.

CoInitializeEx sólo debe ser llamado por el creador de un hilo, porque sólo ellos saben cuál será su mensaje comportamiento de bombeo. Es probable que si se intenta llamar en DllMain que simplemente fallar, como su DLL nativa está siendo llamado en respuesta a una llamada COM, por lo que la persona que llama debe haber en última instancia, ya llamada CoInitializeEx en el hilo con el fin de realizar la llamada. Hacerlo en la notificación DLL_THREAD_ATTACH, por hilos de nueva creación, que podría funcionar superficial sino hacer que el programa no funcione correctamente si COM bloques cuando se debe bombear y viceversa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top