Descripciones y funcionamiento de modelos de subprocesamiento OLE

En este artículo se describen los modelos de subproceso OLE.

Versión original del producto: Modelos de subproceso OLE
Número de KB original: 150777

Resumen

Los objetos COM se pueden usar en varios subprocesos de un proceso. Los términos "Apartamento con subproceso único" (STA) y "Apartamento multiproceso" (MTA) se usan para crear un marco conceptual para describir la relación entre objetos y subprocesos, las relaciones de simultaneidad entre objetos, los medios por los que se entregan llamadas de método a un objeto y las reglas para pasar punteros de interfaz entre subprocesos. Los componentes y sus clientes eligen entre los dos modelos de apartamento que actualmente admite COM:

  1. Modelo de apartamento de un solo subproceso (STA): uno o varios subprocesos de un proceso usan COM y com sincroniza las llamadas a objetos COM. Las interfaces se serializan entre subprocesos. Un caso degenerado del modelo de apartamento de un solo subproceso, donde solo un subproceso de un proceso determinado usa COM, se denomina modelo de subproceso único. Anteriormente, a veces se hacía referencia al modelo STA simplemente como el "modelo de apartamento".

  2. Modelo de apartamento multiproceso (MTA): uno o más subprocesos usan COM y las llamadas a objetos COM asociados con MTA se realizan directamente por todos los subprocesos asociados al MTA sin ninguna interposición de código del sistema entre el autor de la llamada y el objeto. Dado que varios clientes simultáneos pueden llamar a objetos de forma más o menos simultánea (simultáneamente en sistemas multiprocesador), los objetos deben sincronizar su estado interno por sí mismos. Las interfaces no se serializan entre subprocesos. Anteriormente, a veces se hacía referencia a este modelo como el "modelo de subproceso libre".

  3. Tanto el modelo STA como el modelo MTA se pueden usar en el mismo proceso. Esto a veces se conoce como un proceso de "modelo mixto".

MTA se introdujo en NT 4.0 y está disponible en Windows 95 con DCOM95. El modelo STA existe en Windows NT 3.51 y Windows 95, así como NT 4.0 y Windows 95 con DCOM95.

Información general

Los modelos de subprocesos de COM proporcionan el mecanismo para que los componentes que usan distintas arquitecturas de subproceso funcionen conjuntamente. También proporcionan servicios de sincronización a los componentes que los requieren. Por ejemplo, un objeto determinado se puede diseñar para que solo lo llame un único subproceso y es posible que no sincronice las llamadas simultáneas de los clientes. Si varios subprocesos llaman a este tipo de objeto simultáneamente, se bloquea o provoca errores. COM proporciona los mecanismos para abordar esta interoperabilidad de las arquitecturas de subprocesos.

Incluso los componentes compatibles con subprocesos suelen necesitar servicios de sincronización. Por ejemplo, los componentes que tienen una interfaz gráfica de usuario (GUI), como controles OLE/ActiveX, incrustaciones activas en contexto y documentos ActiveX, requieren sincronización y serialización de llamadas COM y mensajes de ventana. COM proporciona estos servicios de sincronización para que estos componentes se puedan escribir sin código de sincronización complejo.

Un "apartamento" tiene varios aspectos interrelaciones. En primer lugar, es una construcción lógica para pensar en la simultaneidad, como cómo se relacionan los subprocesos con un conjunto de objetos COM. En segundo lugar, es un conjunto de reglas que los programadores deben obedecer para recibir el comportamiento de simultaneidad que esperan del entorno COM. Por último, es el código proporcionado por el sistema el que ayuda a los programadores a administrar la simultaneidad de subprocesos con respecto a los objetos COM.

El término "apartamento" procede de una metáfora en la que un proceso se concibe como una entidad discreta, como un "edificio" que se subdivide en un conjunto de "configuraciones regionales" relacionadas pero diferentes denominadas "apartamentos". Un apartamento es un "contenedor lógico" que crea una asociación entre objetos y, en algunos casos, subprocesos. Los subprocesos no son apartamentos, aunque puede haber un único subproceso asociado lógicamente a un apartamento en el modelo STA. Los objetos no son apartamentos, aunque cada objeto está asociado a un solo apartamento. Pero los apartamentos son algo más que una construcción lógica; sus reglas describen el comportamiento del sistema COM. Si no se siguen las reglas de los modelos de apartamento, los objetos COM no funcionarán correctamente.

Más detalles

Un apartamento de un solo subproceso (STA) es un conjunto de objetos COM asociados a un subproceso determinado. Estos objetos se asocian con el apartamento mediante la creación del subproceso o, más concretamente, la primera vez que se exponen al sistema COM (normalmente mediante serialización) en el subproceso. UN STA se considera un lugar donde un objeto o un proxy "vive". Si otro apartamento necesita acceder al objeto o proxy (en el mismo proceso o en otro), su puntero de interfaz debe serializarse a ese apartamento donde se crea un nuevo proxy. Si se siguen las reglas del modelo de apartamento, no se permiten llamadas directas desde otros subprocesos en el mismo proceso en ese objeto; que infringiría la regla de que todos los objetos de un apartamento determinado se ejecuten en un único subproceso. La regla existe porque la mayoría del código que se ejecuta en un STA no funcionará correctamente si se ejecuta en subprocesos adicionales.

El subproceso asociado a un STA debe llamar CoInitialize a o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) y debe recuperar y enviar mensajes de ventana para que los objetos asociados reciban llamadas entrantes. COM envía y sincroniza las llamadas a objetos de un STA mediante mensajes de ventana, como se describe más adelante en este artículo.

El "STA principal" es el subproceso que llama CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) primero dentro de un proceso determinado. El STA principal de un proceso debe permanecer activo hasta que se complete todo el trabajo COM porque algunos objetos en proceso siempre se cargan en el STA principal, como se describe más adelante en este artículo.

Windows NT 4.0 y DCOM95 presentan un nuevo tipo de apartamento denominado apartamento multiproceso (MTA). Un MTA es un conjunto de objetos COM asociados a un conjunto de subprocesos en el proceso de modo que cualquier subproceso pueda llamar a cualquier implementación de objetos directamente sin la interposición del código del sistema. Los punteros de interfaz a cualquier objeto del MTA se pueden pasar entre los subprocesos asociados al MTA sin tener que serializarse. Todos los subprocesos del proceso que llaman CoInitializeEx(NULL, COINIT_MULTITHREADED) están asociados al MTA. A diferencia del STA descrito anteriormente, los subprocesos de un MTA no necesitan recuperar y enviar mensajes de ventana para que los objetos asociados reciban llamadas entrantes. COM no sincroniza las llamadas a objetos de un MTA. Los objetos de un MTA deben proteger su estado interno frente a daños por la interacción de varios subprocesos simultáneos y no pueden hacer suposiciones sobre el contenido de Thread-Local Constante restante de Storage entre invocaciones de método diferentes.

Un proceso puede tener cualquier número de ATA, pero, como máximo, puede tener un MTA. MTA consta de uno o varios subprocesos. Las STA tienen un subproceso cada uno. Un subproceso pertenece, como máximo, a un apartamento. Los objetos pertenecen a un solo apartamento. Los punteros de interfaz siempre deben serializarse entre apartamentos (aunque el resultado de la serialización puede ser un puntero directo en lugar de un proxy). Consulte la información siguiente sobre CoCreateFreeThreadedMarshaler.

Un proceso elige uno de los modelos de subproceso proporcionados por COM. Un proceso de modelo STA tiene uno o varios STA y no tiene un MTA. Un proceso de modelo MTA tiene un MTA con uno o varios subprocesos y no tiene ningún STA. Un proceso de modelo mixto tiene un MTA y cualquier número de STA.

Modelo de apartamento de un solo subproceso

El subproceso de un STA debe llamar CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) y debe recuperar y enviar mensajes de ventana porque COM usa mensajes de ventana para sincronizar y enviar la entrega de llamadas a un objeto de este modelo. Consulte la sección REFERENCIAS a continuación para obtener más información.

Servidor que admite el modelo STA:

En el modelo STA, com sincroniza las llamadas a un objeto de la misma manera que se sincronizan los mensajes de ventana publicados en una ventana. Las llamadas se entregan mediante mensajes de ventana al subproceso que creó el objeto. Por lo tanto, el subproceso del objeto debe llamar a Get/PeekMessage y DispatchMessage para recibir llamadas. COM crea una ventana oculta asociada a cada STA. El tiempo de ejecución COM transfiere una llamada a un objeto desde fuera del STA al subproceso del objeto mediante un mensaje de ventana publicado en esta ventana oculta. Cuando el subproceso asociado al STA del objeto recupera y envía el mensaje, el procedimiento de ventana de la ventana oculta, también implementado por COM, lo recibe. El runtime com usa el procedimiento de ventana para "enlazar" el subproceso asociado al STA porque el tiempo de ejecución COM está a ambos lados de la llamada desde el subproceso propiedad de COM al subproceso de STA. El entorno de ejecución COM (que ahora se ejecuta en el subproceso del STA) llama a "up" a través de un código auxiliar proporcionado por COM en el método de interfaz correspondiente del objeto. La ruta de acceso de ejecución que devuelve la llamada al método invierte la llamada "up"; La llamada vuelve al código auxiliar y al entorno de ejecución COM, que pasa el control al subproceso de tiempo de ejecución COM a través de un mensaje de ventana, que luego devuelve a través del canal COM al autor de la llamada original.

Cuando varios clientes llaman a un objeto STA, las llamadas se ponen automáticamente en cola en la cola de mensajes mediante la transferencia del mecanismo de control usado en sta. El objeto recibe una llamada cada vez que su STA recupera y envía mensajes. Dado que com sincroniza las llamadas de esta manera y que las llamadas siempre se entregan en el único subproceso asociado al STA del objeto, las implementaciones de interfaz del objeto no necesitan proporcionar sincronización.

Nota:

El objeto se puede volver a escribir si una implementación de método de interfaz recupera y envía mensajes al procesar una llamada de método, lo que hace que el mismo STA entregue otra llamada al objeto. Una manera común en la que esto ocurre es si un objeto STA realiza una llamada de salida (entre apartamentos o entre procesos) mediante COM. Esto es idéntico a la manera en que se puede volver a escribir un procedimiento de ventana si recupera y envía mensajes durante el procesamiento de un mensaje. COM no impide volver a entrar en el mismo subproceso, pero impide la ejecución simultánea. También proporciona un medio por el que se puede administrar la reentrada relacionada con COM. Consulte la sección REFERENCIAS a continuación para obtener más información. El objeto no se vuelve a especificar si las implementaciones del método no llaman a su apartamento o, de lo contrario, recuperan y envían mensajes.

Responsabilidades de cliente en el modelo STA:

El código de cliente que se ejecuta en un proceso o subproceso que usa el modelo STA debe serializar las interfaces de un objeto entre apartamentos mediante CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream. Por ejemplo, si El apartamento 1 del cliente tiene un puntero de interfaz y El apartamento 2 requiere su uso, el apartamento 1 debe serializar la interfaz mediante CoMarshalInterThreadInterfaceInStream. El objeto de secuencia devuelto por esta función es seguro para subprocesos y su puntero de interfaz debe almacenarse en una variable de memoria directa accesible por Apartment 2. Apartment 2 debe pasar esta interfaz de flujo a para CoGetInterfaceAndReleaseStream anular elmar la interfaz en el objeto subyacente y obtener de nuevo un puntero a un proxy a través del cual puede acceder al objeto.

El apartamento principal de un proceso determinado debe permanecer activo hasta que el cliente haya completado todo el trabajo COM porque algunos objetos en proceso se cargan en el apartamento principal. (Más información se detalla a continuación).

Modelo de apartamento multiproceso

Un MTA es la colección de objetos creados o expuestos por todos los subprocesos del proceso que han llamado a CoInitializeEx(NULL, COINIT_MULTITHREADED).

Nota:

Las implementaciones actuales de COM permiten que un subproceso que no inicialice EXPLÍCITAmente COM forme parte del MTA. Un subproceso que no inicializa COM forma parte del MTA solo si comienza a usar COM después de que al menos otro subproceso del proceso haya llamado CoInitializeEx(NULL, COINIT_MULTITHREADED)previamente a . (Incluso es posible que el propio COM haya inicializado el MTA cuando ningún subproceso de cliente lo haya hecho explícitamente; por ejemplo, un subproceso asociado a una llamada CoGetClassObject/CoCreateInstance[Ex] STA en un CLSID marcado como "ThreadingModel=Free" y COM crea implícitamente un MTA en el que se carga el objeto de clase). Consulte la información sobre la interoperabilidad del modelo de subprocesos a continuación.

Sin embargo, se trata de una configuración que puede causar problemas, como infracciones de acceso, en determinadas circunstancias. Por lo tanto, se recomienda que cada subproceso que necesite realizar el trabajo COM inicialice COM llamando a CoInitializeEx y, después, al finalizar el trabajo COM, llame a CoUninitialize. El costo de inicializar un MTA "innecesariamente" es mínimo.

Los subprocesos MTA no necesitan recuperar y enviar mensajes porque COM no usa mensajes de ventana en este modelo para entregar llamadas a un objeto.

  • Servidor que admite el modelo MTA:

    En el modelo MTA, com no sincroniza las llamadas a un objeto. Varios clientes pueden llamar simultáneamente a un objeto que admite este modelo en subprocesos diferentes y el objeto debe proporcionar sincronización en sus implementaciones de interfaz o método mediante objetos de sincronización como eventos, exclusión mutua, semáforos, etc. Los objetos MTA pueden recibir llamadas simultáneas de varios clientes fuera de proceso a través de un grupo de subprocesos creados por COM que pertenecen al proceso del objeto. Los objetos MTA pueden recibir llamadas simultáneas de varios clientes en proceso en varios subprocesos asociados al MTA.

  • Responsabilidades del cliente en el modelo MTA:

    El código de cliente que se ejecuta en un proceso o subproceso que usa el modelo MTA no tiene que serializar los punteros de interfaz de un objeto entre sí y otros subprocesos MTA. En su lugar, un subproceso MTA puede usar un puntero de interfaz obtenido de otro subproceso MTA como puntero de memoria directo. Cuando un subproceso de cliente realiza una llamada a un objeto fuera de proceso, se suspende hasta que se complete la llamada. Las llamadas pueden llegar a objetos asociados al MTA mientras todos los subprocesos creados por la aplicación asociados al MTA están bloqueados en las llamadas fuera de servicio. En este caso y, en general, las llamadas entrantes se entregan en subprocesos proporcionados por el entorno de ejecución COM. Los filtros de mensajes (IMessageFilter) no están disponibles para su uso en el modelo MTA.

Modelos de subprocesos mixtos

Un proceso que admita el modelo de subprocesos mixtos usará un MTA y uno o más STA. Los punteros de interfaz deben serializarse entre todos los apartamentos, pero se pueden usar sin serializar dentro del MTA. COM sincroniza las llamadas a objetos de un STA para que se ejecuten solo en un subproceso, mientras que las llamadas a objetos del MTA no lo son. Sin embargo, las llamadas de un STA a un MTA normalmente pasan por el código proporcionado por el sistema y cambian del subproceso STA a un subproceso MTA antes de entregarse al objeto.

Nota:

Consulte la documentación del SDK y CoCreateFreeThreadedMarshaler() la explicación de esa API a continuación para obtener información sobre los casos en los que se pueden usar punteros directos y cómo un subproceso STA puede llamar directamente a un objeto asociado primero a MTA y, viceversa, desde varios apartamentos.

Elección de los modelos de subprocesos

Un componente puede optar por admitir el modelo STA, el modelo MTA o una combinación de los dos mediante el modelo de subproceso mixto. Por ejemplo, un objeto que realiza una E/S extensa puede optar por admitir MTA para proporcionar la máxima respuesta a los clientes al permitir que se realicen llamadas de interfaz durante la latencia de E/S. Como alternativa, un objeto que interactúa con el usuario casi siempre elige admitir STA para sincronizar las llamadas COM entrantes con sus operaciones de GUI. Admitir el modelo STA es más fácil porque COM proporciona sincronización. Admitir el modelo MTA es más difícil porque el objeto debe implementar la sincronización, pero la respuesta a los clientes es mejor porque la sincronización se usa para secciones de código más pequeñas, en lugar de para toda la llamada de interfaz proporcionada por COM.

Microsoft Transaction Server (MTS, anteriormente denominado "Viper") usa el modelo STA y, por tanto, los objetos basados en DLL que planean ejecutarse en el entorno mts deben usar el modelo STA. Los objetos implementados para el modelo MTA normalmente funcionarán bien en un entorno mts. Sin embargo, se ejecutarán de forma menos eficaz porque usarán primitivos de sincronización de subprocesos innecesarios.

Marcar el modelo de subproceso admitido de servidores In-Proc

Un subproceso usa el modelo MTA si llama CoInitializeEx(NULL, COINIT_MULTITHREADED) o usa COM sin inicializarlo. Un subproceso usa el modelo STA si llama a CoInitialize o CoInitializeEx(NULL, COINIT_APARTMENTTHREADED).

Las CoInitialize API proporcionan control de apartamento para el código de cliente y para los objetos empaquetados en . EXE, porque el código de inicio del entorno de ejecución COM puede inicializar COM de la manera deseada.

Sin embargo, un servidor COM en proceso (basado en DLL) no llama a CoInitialize/CoInitializeEx porque esas API se habrán llamado en el momento en que se cargue el servidor DLL. Por lo tanto, un servidor DLL debe usar el Registro para informar a COM del modelo de subprocesos que admite para que COM pueda asegurarse de que el sistema funciona de una manera compatible con él. Para este propósito se usa un valor con nombre de la clave ThreadingModel CLSID\InprocServer32 del componente, como se indica a continuación:

  • ThreadingModel valor no presente: admite el modelo de subproceso único.
  • ThreadingModel=Apartment: admite el modelo STA.
  • ThreadingModel=Both: admite el modelo STA y MTA.
  • ThreadingModel=Free: solo admite MTA.

Nota:

ThreadingModel es un valor con nombre, no una subclave de InprocServer32 como se documentó incorrectamente en algunas versiones anteriores de la documentación de Win32.

Los modelos de subprocesos de los servidores en proceso se describen más adelante en este artículo. Si un servidor en proceso proporciona muchos tipos de objetos (cada uno con su propio CLSID único), cada tipo puede tener un valor diferente ThreadingModel . En otras palabras, el modelo de subprocesos es por CLSID, no por paquete de código o DLL. Sin embargo, los puntos de entrada de API necesarios para "arrancar" y consultar todos los servidores en proceso (DLLGetClassObject(), DLLCanUnloadNow()) deben ser seguros para subprocesos para cualquier servidor en proceso que admita varios subprocesos (es decir, un ThreadingModel valor de Apartment, Both o Free).

Como se indicó anteriormente, los servidores fuera de proceso no se marcan por sí mismos mediante el valor de ThreadingModel. En su lugar, usan CoInitialize o CoInitializeEx. Los servidores basados en DLL que esperan que se ejecuten fuera de proceso mediante la funcionalidad "suplente" de COM (como el DLLHOST.EXE suplente proporcionado por el sistema) siguen las reglas de los servidores basados en DLL; no hay consideraciones especiales en ese caso.

Cuando el cliente y el objeto usan diferentes modelos de subprocesos

La interacción entre un cliente y un objeto fuera de proceso es directa incluso cuando se usan diferentes modelos de subprocesos porque el cliente y el objeto están en procesos diferentes y COM participa en el paso de llamadas desde el cliente al objeto . Dado que COM se interpone entre el cliente y el servidor, proporciona el código para la interoperación de los modelos de subprocesos. Por ejemplo, si varios clientes STA o MTA llaman simultáneamente a un objeto STA, COM sincroniza las llamadas colocando los mensajes de ventana correspondientes en la cola de mensajes del servidor. Sta del objeto recibe una llamada cada vez que recupera y envía mensajes. Se permiten todas las combinaciones de interoperabilidad del modelo de subprocesos y se admiten totalmente entre los clientes y los objetos fuera de proceso.

La interacción entre un cliente y un objeto en proceso que usa diferentes modelos de subprocesos es más complicada. Aunque el servidor está en proceso, COM debe interponerse entre el cliente y el objeto en algunos casos. Por ejemplo, varios subprocesos de un cliente pueden llamar simultáneamente a un objeto en proceso diseñado para admitir el modelo STA. COM no puede permitir que los subprocesos de cliente accedan directamente a la interfaz del objeto porque el objeto no está diseñado para este acceso simultáneo. En su lugar, COM debe asegurarse de que las llamadas se sincronicen y realicen solo el subproceso asociado al STA que "contiene" el objeto. A pesar de la complejidad agregada, se permiten todas las combinaciones de interoperabilidad del modelo de subprocesos entre clientes y objetos en proceso.

Modelos de subprocesos en servidores fuera de proceso (basados en EXE)

A continuación se muestran tres categorías de servidores fuera de proceso, cada uno de los cuales puede ser utilizado por cualquier cliente COM independientemente del modelo de subprocesos usado por ese cliente:

  1. Servidor de modelos STA:

    El servidor realiza el trabajo COM en uno o varios STA. Com sincroniza las llamadas entrantes y las entrega el subproceso asociado al STA en el que se creó el objeto. El subproceso asociado al STA que registró el generador de clases entrega las llamadas al método de fábrica de clases. El objeto y el generador de clases no necesitan implementar la sincronización. Sin embargo, el implementador debe sincronizar el acceso a las variables globales usadas por varias AS. El servidor debe usar CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream para serializar punteros de interfaz, posiblemente de otros servidores, entre LASAS. Opcionalmente, el servidor puede implementar IMessageFilter en cada STA para controlar los aspectos de la entrega de llamadas por COM. Un caso degenerado es el servidor de modelo de subproceso único que realiza el trabajo COM en un STA.

  2. Servidor de modelos MTA:

    El servidor realiza el trabajo COM en uno o varios subprocesos, todos los cuales pertenecen al MTA. Com no sincroniza las llamadas. COM crea un grupo de subprocesos en el proceso del servidor y cualquiera de estos subprocesos entrega una llamada de cliente. Los subprocesos no necesitan recuperar y enviar mensajes. El generador de objetos y clases debe implementar la sincronización. El servidor no necesita serializar punteros de interfaz entre subprocesos.

  3. Servidor de modelos mixtos:

    Consulte la sección de este artículo titulada "Modelo de subprocesos mixtos" para obtener más información.

Modelos de subprocesos en clientes

Hay tres categorías de clientes:

  1. Cliente del modelo STA:

    El cliente realiza el trabajo COM en subprocesos asociados a uno o más STA. El cliente debe usar CoMarshalInterThreadInterfaceInStream y CoGetInterfaceAndReleaseStream para serializar punteros de interfaz entre LASAS. Un caso degenerado es el cliente de modelo de subproceso único que realiza el trabajo COM en un STA. El subproceso del cliente entra en un bucle de mensajes proporcionado por COM cuando realiza una llamada saliente. El cliente puede usar IMessageFilter para administrar las devoluciones de llamada y el procesamiento de mensajes de ventana mientras espera las llamadas fuera de servicio y otros problemas de simultaneidad.

  2. Cliente del modelo MTA:

    El cliente realiza el trabajo COM en uno o varios subprocesos, todos los cuales pertenecen al MTA. El cliente no necesita serializar punteros de interfaz entre sus subprocesos. El cliente no puede usar IMessageFilter. Los subprocesos del cliente se suspenden cuando realizan una llamada COM a un objeto fuera de proceso y se reanudan cuando se devuelve la llamada. Las llamadas entrantes llegan a subprocesos administrados y creados por COM.

  3. Cliente de modelo mixto:

    Consulte la sección de este artículo titulada "Modelo de subprocesos mixtos" para obtener más información.

Modelos de subprocesos en servidores en proceso (basados en DLL)

Hay cuatro categorías de servidores en proceso, cada uno de los cuales puede ser utilizado por cualquier cliente COM independientemente del modelo de subprocesos usado por ese cliente. Sin embargo, los servidores en proceso deben proporcionar código de serialización para cualquier interfaz personalizada (no definida por el sistema) que implementen si van a admitir la interoperabilidad del modelo de subprocesos, ya que normalmente requiere que COM serializa la interfaz entre los apartamentos de cliente. Las cuatro categorías son:

  1. Servidor en proceso que admite el subproceso único ("main" STA): sin ThreadingModel valor:

    Un objeto proporcionado por este servidor espera tener acceso al mismo STA de cliente mediante el que se creó. Además, el servidor espera que el mismo subproceso acceda a todos sus puntos de entrada, como DllGetClassObject y DllCanUnloadNow, y a los datos globales (el asociado al STA principal). Los servidores que existían antes de la introducción del multiproceso en COM se encuentran en esta categoría. Estos servidores no están diseñados para ser accesibles por varios subprocesos, por lo que COM crea todos los objetos proporcionados por el servidor en el STA principal del proceso y las llamadas a los objetos se entregan por el subproceso asociado al STA principal. Otros apartamentos cliente obtienen acceso al objeto a través de servidores proxy. Las llamadas desde los otros apartamentos van desde el proxy al código auxiliar en el STA principal (serialización entre subprocesos) y, a continuación, al objeto . Esta serialización permite que COM sincronice las llamadas al objeto y las llamadas las entrega el STA en el que se creó el objeto. La serialización entre subprocesos es lenta en relación con las llamadas directas, por lo que se recomienda volver a escribir estos servidores para admitir varias STA (categoría 2).

  2. Servidor en proceso que admite el modelo de apartamento de un solo subproceso (varias ASE): marcado con ThreadingModel=Apartment:

    Un objeto proporcionado por este servidor espera tener acceso al mismo STA de cliente mediante el que se creó. Por lo tanto, es similar a un objeto proporcionado por un servidor en proceso de un solo subproceso. Sin embargo, los objetos proporcionados por este servidor se pueden crear en varias AS del proceso, por lo que el servidor debe diseñar sus puntos de entrada, como DllGetClassObject y DllCanUnloadNow, y datos globales para su uso multiproceso. Por ejemplo, si dos STA de un proceso crean dos instancias del objeto en proceso simultáneamente, DllGetClassObject ambas ATA pueden llamarlas simultáneamente. Del mismo modo, DllCanUnloadNow debe escribirse para que el servidor esté protegido contra la descarga mientras el código sigue ejecutándose en el servidor.

    Si el servidor proporciona solo una instancia del generador de clases para crear todos los objetos, la implementación del generador de clases también debe diseñarse para su uso multiproceso porque tiene acceso a ella mediante varias ASE de cliente. Si el servidor crea una nueva instancia del generador de clases cada vez DllGetClassObject que se llama a , el generador de clases no tiene que ser seguro para subprocesos. Sin embargo, el implementador debe sincronizar el acceso a cualquier variable global.

    No es necesario que los objetos COM creados por el generador de clases sean seguros para subprocesos. Sin embargo, el implementador debe sincronizar el acceso de las variables globales. Una vez creado por un subproceso, siempre se obtiene acceso al objeto a través de ese subproceso y com sincroniza todas las llamadas al objeto. Los apartamentos cliente que son diferentes del STA en el que se creó el objeto deben tener acceso al objeto a través de servidores proxy. Estos servidores proxy se crean cuando el cliente serializa la interfaz entre sus apartamentos.

    Cualquier cliente que crea un objeto STA a través de su generador de clases obtiene un puntero directo al objeto . Esto es diferente de los objetos in-proc de un solo subproceso, donde solo el STA principal del cliente obtiene un puntero directo al objeto y todos los demás STA que crean el objeto obtienen acceso al objeto a través de un proxy. Dado que la serialización entre subprocesos es lenta en relación con las llamadas directas, se puede mejorar la velocidad cambiando un servidor en proceso de un solo subproceso para admitir varias ASE.

  3. Servidor en proceso que solo admite MTA, marcado con ThreadingModel=Free:

    Un objeto proporcionado por este servidor es seguro solo para MTA. Implementa su propia sincronización y tiene acceso a varios subprocesos de cliente al mismo tiempo. Este servidor puede tener un comportamiento incompatible con el modelo STA. (Por ejemplo, por su uso de la cola de mensajes de Windows de una manera que interrumpe la bomba de mensajes de un STA). Además, al marcar el modelo de subprocesos del objeto como "Libre", el implementador del objeto indica lo siguiente: se puede llamar a este objeto desde cualquier subproceso de cliente, pero este objeto también puede pasar punteros de interfaz directamente (sin serializar) a los subprocesos que creó y estos subprocesos pueden realizar llamadas a través de estos punteros. Por lo tanto, si el cliente pasa un puntero de interfaz a un objeto implementado por el cliente (como un receptor) a este objeto, puede optar por volver a llamar a través de este puntero de interfaz desde cualquier subproceso que haya creado. Si el cliente es un STA, se producirá un error en una llamada directa desde un subproceso, que es diferente del subproceso que creó el objeto receptor (como se muestra en el 2 anterior). Por lo tanto, COM siempre garantiza que los clientes de subprocesos asociados a un STA obtengan acceso a este tipo de objeto en proceso solo a través de un proxy. Además, estos objetos no deben agregarse con el serializador de subproceso libre, ya que esto les permite ejecutarse directamente en subprocesos STA.

  4. Servidor en proceso que admite el modelo de apartamento y el subproceso libre: marcado con ThreadingModel=Both:

    Un objeto proporcionado por este servidor implementa su propia sincronización y al que acceden simultáneamente varios apartamentos de cliente. Además, este objeto se crea y se usa directamente, en lugar de a través de un proxy, en LASAS o el MTA de un proceso de cliente. Dado que este objeto se usa directamente en LASAS, el servidor debe serializar interfaces de objetos, posiblemente de otros servidores, entre subprocesos, por lo que se garantiza su acceso a cualquier objeto de forma adecuada para subprocesos. Además, al marcar el modelo de subprocesos del objeto como "Both", el implementador del objeto indica lo siguiente: se puede llamar a este objeto desde cualquier subproceso de cliente, pero las devoluciones de llamada de este objeto al cliente solo se realizarán en el apartamento en el que el objeto recibió el puntero de interfaz al objeto de devolución de llamada. COM permite crear un objeto de este tipo directamente en un STA, así como en un MTA del proceso de cliente.

    Dado que cualquier apartamento que crea un objeto de este tipo siempre obtiene un puntero directo en lugar de un puntero proxy, ThreadingModel "Both" los objetos proporcionan mejoras de rendimiento sobre ThreadingModel "Free" los objetos cuando se cargan en un STA.

    Dado que un ThreadingModel "Both" objeto también está diseñado para el acceso MTA (es seguro para subprocesos internamente), puede acelerar el rendimiento agregando con el serializador proporcionado por CoCreateFreeThreadedMarshaler. Este objeto proporcionado por el sistema se agrega a los objetos que llaman y las referencias personalizadas dirigen punteros al objeto en todos los apartamentos del proceso. Los clientes de cualquier apartamento, ya sea sta o MTA, pueden acceder al objeto directamente en lugar de a través de un proxy. Por ejemplo, un cliente de modelo STA crea el objeto en proceso en STA1 y serializa el objeto en STA2. Si el objeto no se agrega con el serializador de subproceso libre, STA2 obtiene acceso al objeto a través de un proxy. Si lo hace, el serializador de subproceso libre proporciona a STA2 un puntero directo al objeto .

    Nota:

    Se debe tener cuidado al agregar con el serializador de subproceso libre. Por ejemplo, suponga que un objeto marcado como ThreadingModel "Both" (y que también agrega con el serializador de subproceso libre) tiene un miembro de datos que es un puntero de interfaz a otro objeto cuyo ThreadingModel es "Apartment". A continuación, suponga que un STA crea el primer objeto y, durante la creación, el primer objeto crea el segundo objeto. Según las reglas descritas anteriormente, el primer objeto ahora contiene un puntero directo al segundo objeto. Ahora se supone que sta serializa el puntero de interfaz al primer objeto a otro apartamento. Dado que el primer objeto se agrega con el serializador de subproceso libre, se proporciona un puntero directo al primer objeto al segundo apartamento. Si el segundo apartamento llama a través de este puntero y esta llamada hace que el primer objeto llame a través del puntero de interfaz al segundo objeto, se ha producido un error, ya que el segundo objeto no está pensado para llamarse directamente desde el segundo apartamento. Si el primer objeto contiene un puntero a un proxy al segundo objeto en lugar de a un puntero directo, se producirá un error diferente. Los servidores proxy del sistema también son objetos COM asociados a un solo apartamento. Ellos realizar un seguimiento de su apartamento con el fin de evitar ciertas circularidades. Por lo tanto, un objeto que llama a en un proxy asociado a un apartamento diferente al subproceso en el que se ejecuta el objeto recibirá el RPC_E_WRONG_THREAD devolver del proxy y se producirá un error en la llamada.

Interoperabilidad del modelo de subprocesos entre clientes y objetos en proceso

Se permiten todas las combinaciones de interoperabilidad del modelo de subprocesos entre clientes y objetos en proceso.

COM permite que todos los clientes del modelo STA funcionen entre sí con objetos de subproceso único en proceso mediante la creación y el acceso al objeto en el STA principal del cliente y su serialización en el STA de cliente que llamó CoCreateInstance[Ex]a .

Si un MTA de un cliente crea un servidor de modelo STA en proceso, COM inicia un STA de "host" en el cliente. Este STA de host crea el objeto y el puntero de interfaz se serializa de nuevo al MTA. De forma similar, cuando un STA crea un servidor MTA en proceso, COM inicia un MTA de host en el que se crea el objeto y se serializa de nuevo al STA. La interoperabilidad entre el modelo de subproceso único y el modelo MTA se controla de forma similar porque el modelo de subproceso único es simplemente un caso degenerado del modelo STA.

Se debe proporcionar código de serialización para cualquier interfaz personalizada que implemente un servidor en proceso si quiere admitir la interoperabilidad que requiere COM para serializar la interfaz entre los apartamentos de cliente. Consulte la sección REFERENCIAS a continuación para obtener más información.

Relación entre el modelo de subprocesos y el objeto De fábrica de clases devuelto

En los dos pasos siguientes se explica una definición precisa de los servidores en proceso que se "cargan en" apartamentos:

  1. Si el archivo DLL que contiene la clase de servidor en proceso no se ha cargado previamente (asignado al espacio de direcciones del proceso) por el cargador del sistema operativo, esa operación se realiza y COM obtiene la dirección de la DLLGetClassObject función exportada por el archivo DLL. Si un subproceso asociado a cualquier apartamento ha cargado previamente el archivo DLL, se omite esta fase.

  2. COM usa el subproceso (o, en el caso de MTA, uno de los subprocesos) asociado al apartamento de "carga" para llamar a la DllGetClassObject función exportada por el archivo DLL que solicita el CLSID de la clase necesaria. A continuación, el objeto de fábrica devuelto se usa para crear instancias de objetos de la clase .

    El segundo paso (la llamada de DllGetClassObject com) se produce cada vez que un cliente llama a CoGetClassObject/CoCreateIntance[Ex], incluso desde el mismo apartamento. En otras palabras, DllGetClassObject un subproceso asociado al mismo apartamento puede llamarlo muchas veces; todo depende del número de clientes de ese apartamento que intentan obtener acceso a un objeto de fábrica de clases para esa clase.

Los autores de implementaciones de clase y, en última instancia, el autor del paquete DLL de un conjunto determinado de clases tienen libertad completa para decidir qué objeto de fábrica devolver en respuesta a la DllGetClassObject llamada de función. El autor del paquete DLL tiene la última palabra porque el código "detrás" del único punto de entrada de todo DllGetClassObject() el archivo DLL es lo que tiene el primer y potencial derecho final para decidir qué hacer. Las tres posibilidades típicas son:

  1. DllGetClassObject devuelve un objeto de generador de clases único por subproceso de llamada (lo que significa un objeto de generador de clases por STA y, potencialmente, varios generadores de clases dentro del MTA).

  2. DllGetClassObject siempre devuelve el mismo objeto de generador de clases, independientemente de la identidad del subproceso que realiza la llamada o del tipo de apartamento asociado al subproceso que realiza la llamada.

  3. DllGetClassObject devuelve un objeto de generador de clases único por apartamento de llamada (uno por apartamento en STA y MTA).

Hay otras posibilidades para la relación entre las llamadas a DllGetClassObject y el objeto de generador de clases devuelto (como un nuevo objeto de generador de clases por llamada a DllGetClassObject), pero actualmente no parecen ser útiles.

Resumen de los modelos de subprocesos de cliente y objeto para servidores In-Proc

En la tabla siguiente se resume la interacción entre distintos modelos de subproceso cuando un subproceso de cliente llama CoGetClassObject por primera vez a una clase que se implementa como un servidor en proceso.

Tipos de clientes o subprocesos:

  • el cliente se ejecuta en un subproceso asociado al STA "principal" (primer subproceso al que llamar CoInitialize o CoInitializeEx con COINIT_APARTMENTTHREADED marca)-llame a este STA0 (también denominado modelo de subproceso único).
  • el cliente se ejecuta en un subproceso asociado a en cualquier otra llamada STA [ASCII 150] a esta STA*.
  • el cliente se ejecuta en un subproceso asociado a en el MTA.

Tipos de servidores DLL:

  • El servidor no tiene ninguna ThreadingModel clave: llame a esta "Ninguno".
  • El servidor está marcado como "Apartment": llame a este "Apt".
  • El servidor está marcado como "Gratis".
  • El servidor está marcado como "Ambos".

Al leer la tabla siguiente, tenga en cuenta la definición anterior de "cargar" un servidor en un apartamento.

Client         Server                 Result
STA0           None                   Direct access; server loaded into STA0  
STA*           None                   Proxy access; server loaded into STA0.  
MTA            None                   Proxy access; server loaded into STA0; STA0 created automatically by COM if necessary;  
STA0           Apt                    Direct access; server loaded into STA0  
STA*           Apt                    Direct access; server loaded into STA*  
MTA            Apt                    Proxy access; server loaded into an STA created automatically by COM.
STA0           Free                   Proxy access; server is loaded into MTA MTA created automatically by COM if necessary.
STA*           Free                   Same as STA0->Free
MTA            Free                   Direct access
STA0           Both                   Direct access; server loaded into STA0
STA*           Both                   Direct access; server loaded into STA*
MTA            Both                   Direct access; server loaded into the MTA

Referencias

Documentación del SDK sobre la CoRegisterMessageFilter() interfaz y IMessageFilter .