Asistentes de implementación del servidor fuera de proceso

Hay disponibles cuatro funciones auxiliares a las que pueden llamar los servidores fuera de proceso para simplificar el trabajo de escribir código de servidor. Normalmente, los clientes COM y los servidores COM en proceso no los llamarían. Estas funciones están diseñadas para ayudar a evitar condiciones de carrera en la activación del servidor cuando los servidores tienen varios apartamentos o varios objetos de clase. Sin embargo, también se pueden usar tan fácilmente para servidores de objetos de clase única y subproceso único. Las funciones son las siguientes:

Para apagarse correctamente, un servidor COM debe realizar un seguimiento de cuántas instancias de objeto ha creado una instancia y cuántas veces se ha llamado a su método IClassFactory::LockServer . Solo cuando ambos recuentos alcanzan cero pueden apagar un servidor. En los servidores COM de un solo subproceso, la decisión de apagar se coordinaba con las solicitudes de activación entrantes, que la cola de mensajes serializó. El servidor, al recibir una versión en su instancia de objeto final y decidir apagarse, revocaría sus objetos de clase antes de que se enviaran más solicitudes de activación. Si se produjo una solicitud de activación después de este punto, COM reconocería que los objetos de clase se revocaron y devolverían un error al Administrador de control de servicios (SCM), lo que provocaría que se ejecutara una nueva instancia del proceso del servidor local.

Sin embargo, en un servidor de modelo de apartamento, en el que se registran objetos de clase diferentes en distintos apartamentos y en todos los servidores de subprocesos libres, esta decisión de apagarse debe coordinarse con solicitudes de activación en varios subprocesos para que un subproceso del servidor no decida apagarse mientras otro subproceso del servidor está ocupado entregando objetos de clase o instancias de objeto. Un enfoque clásico pero complicado para resolver esto es tener el servidor, después de haber revocado sus objetos de clase, volver a comprobar su recuento de instancias y mantenerse activo hasta que se hayan liberado todas las instancias.

Para facilitar que los escritores de servidores controle estos tipos de condiciones de carrera, COM proporciona dos funciones de recuento de referencias:

Cuando el recuento global de referencias por proceso alcanza cero, COM llama automáticamente a CoSuspendClassObjects, lo que impide que se produzcan nuevas solicitudes de activación. Después, el servidor puede anular el registro de sus diversos objetos de clase de sus diversos subprocesos en tiempo libre sin preocuparse de que se pueda producir otra solicitud de activación. Por lo tanto, todas las solicitudes de activación nuevas se controlan mediante el SCM que inicia una nueva instancia del proceso del servidor local.

La manera más sencilla para que una aplicación de servidor local use estas funciones es llamar a CoAddRefServerProcess en el constructor para cada uno de sus objetos de instancia y en cada uno de sus métodos IClassFactory::LockServer cuando el parámetro fLock es TRUE. La aplicación de servidor también debe llamar a CoReleaseServerProcess en el destructor de cada uno de sus objetos de instancia y en cada uno de sus métodos IClassFactory::LockServer cuando el parámetro fLock es FALSE.

Por último, la aplicación de servidor debe prestar atención al código de retorno de CoReleaseServerProcess y, si devuelve 0, la aplicación de servidor debe iniciar su limpieza, que, para un servidor con varios subprocesos, normalmente significa que debe indicar sus distintos subprocesos para salir de sus bucles de mensajes y llamar a CoAddRefServerProcess y CoReleaseServerProcess. Si se usan las funciones de administración de duración del proceso del servidor, deben usarse tanto en las instancias de objeto como en el método LockServer ; de lo contrario, la aplicación de servidor puede apagarse prematuramente.

Cuando se realiza una solicitud CoGetClassObject , COM se pone en contacto con el servidor, serializa la interfaz IClassFactory del objeto de clase, vuelve al proceso de cliente, anula la combinación de la interfaz IClassFactory y lo devuelve al cliente. En este momento, los clientes suelen llamar a LockServer con TRUE para evitar que el proceso del servidor se apague. Sin embargo, hay un período de tiempo entre el momento en que se serializa el objeto de clase y cuando el cliente llama a LockServer en el que otro cliente podría conectarse al mismo servidor, obtener una instancia y liberar esa instancia, lo que hace que el servidor se apague y deje el primer cliente alto y seco con un puntero IClassFactory desconectado. Para evitar esta condición de carrera, COM agrega una llamada implícita a LockServer con TRUE al objeto de clase cuando serializa la interfaz IClassFactory y una llamada implícita a LockServer con FALSE cuando el cliente libera la interfaz IClassFactory . Por lo tanto, no es necesario volver a llamar a LockServer remoto al servidor, y el proxy para LockServer simplemente devuelve S_OK sin realmente la comunicación remota de la llamada.

Hay otra condición de carrera relacionada con la activación durante la inicialización de un proceso de servidor fuera de proceso. Un servidor COM que registra varias clases normalmente llama a CoRegisterClassObject con REGCLS_LOCAL_SERVER para cada CLSID que admite. Una vez hecho esto para todas las clases, el servidor entra en su bucle de mensajes. Para un servidor COM de un solo subproceso, todas las solicitudes de activación se bloquean hasta que el servidor entra en el bucle de mensajes. Sin embargo, para un servidor de modelo de apartamento que registra objetos de clase diferentes en apartamentos diferentes y para todos los servidores de subprocesos gratuitos, las solicitudes de activación pueden llegar antes de esto. En el caso de los servidores de modelo de apartamento, las solicitudes de activación podrían llegar tan pronto como cualquier subproceso haya entrado en su bucle de mensajes. En el caso de los servidores de subprocesos libres, una solicitud de activación podría llegar tan pronto como se registre el objeto de primera clase. Dado que una activación puede producirse antes, también es posible que se produzca la versión final (y, por lo tanto, hacer que el servidor comience a apagarse) antes de que el resto del servidor haya tenido la oportunidad de terminar de inicializarse.

Para eliminar estas condiciones de carrera y simplificar el trabajo del escritor del servidor, cualquier servidor que quiera registrar varios objetos de clase con COM debe llamar a CoRegisterClassObject con REGCLS_LOCAL_SERVER | REGCLS_SUSPENDED para cada CLSID diferente que admita el servidor. Una vez registradas todas las clases y el proceso del servidor está listo para aceptar solicitudes de activación entrantes, el servidor debe realizar una llamada a CoResumeClassObjects. Esta función indica a COM que informe al SCM sobre todas las clases registradas y comienza a permitir las solicitudes de activación en el proceso del servidor. El uso de estas funciones proporciona las siguientes ventajas:

  • Solo se realiza una llamada al SCM, independientemente del número de CLSID registrados, lo que reduce el tiempo de registro general (y, por tanto, el tiempo de inicio de la aplicación de servidor).
  • Si el servidor tiene varios apartamentos y clSID diferentes se registran en apartamentos diferentes, o si el servidor es un servidor sin subprocesos, no se producirá ninguna solicitud de activación hasta que el servidor llame a CoResumeClassObjects, lo que da al servidor la oportunidad de registrar todos sus CLSID y configurar correctamente antes de tener que tratar con las solicitudes de activación y las posibles solicitudes de cierre.

Responsabilidades del servidor COM