Escribir un suplente personalizado

Aunque el suplente proporcionado por el sistema será más adecuado para la mayoría de las situaciones, hay algunos casos en los que escribir un suplente personalizado podría ser útil. A continuación se muestran algunos ejemplos:

  • Un suplente personalizado podría proporcionar algunas optimizaciones o semánticas que no están presentes en el suplente del sistema.
  • Si un archivo DLL en proceso contiene código que depende de estar en el mismo proceso que el cliente, el servidor DLL no funcionará correctamente si se ejecuta en el suplente del sistema. Un suplente personalizado podría adaptarse a un archivo DLL específico para tratar con esto.
  • El suplente del sistema admite un modelo de subproceso mixto para que pueda cargar archivos DLL de modelo de apartamento y gratuitos. Un suplente personalizado puede adaptarse para cargar solo archivos DLL de apartamento por motivos de eficacia o para aceptar un argumento de línea de comandos para el tipo de DLL que se permite cargar.
  • Un suplente personalizado podría tomar parámetros de línea de comandos adicionales que el suplente del sistema no.
  • El suplente del sistema llama a CoInitializeSecurity y le indica que use cualquier configuración de seguridad existente que se encuentre en la clave AppID del Registro. Un suplente personalizado podría usar otro contexto de seguridad.
  • Las interfaces que no son remotables (como las de ocX recientes) no funcionarán con el suplente del sistema. Un suplente personalizado podría encapsular las interfaces de la DLL con su propia implementación y usar archivos DLL proxy/stub con una definición IDL remotable que permitiría que la interfaz se remoto.

El subproceso suplente principal normalmente debe realizar los siguientes pasos de configuración:

  1. Llame a CoInitializeEx para inicializar el subproceso y establecer el modelo de subprocesos.
  2. Si desea que los servidores DLL que se ejecuten en el servidor puedan usar la configuración de seguridad en la clave del Registro AppID , llame a CoInitializeSecurity con la funcionalidad EOAC_APPID. De lo contrario, se usará la configuración de seguridad heredada.
  3. Llame a CoRegisterSurrogate para registrar la interfaz suplente en COM.
  4. Llame a ISurrogate::LoadDllServer para el CLSID solicitado.
  5. Coloque el subproceso principal en un bucle para llamar a CoFreeUnusedLibraries periódicamente.
  6. Cuando COM llama a ISurrogate::FreeSurrogate, revoque todas las factorías de clase y salga.

Un proceso suplente debe implementar la interfaz ISurrogate . Esta interfaz debe registrarse cuando se inicia un nuevo suplente y después de llamar a CoInitializeEx. Como se indica en los pasos anteriores, la interfaz ISurrogate tiene dos métodos que llaman COM: LoadDllServer, para cargar dinámicamente nuevos servidores DLL en suplentes existentes; y FreeSurrogate, para liberar al suplente.

La implementación de LoadDllServer, que llama COM con una solicitud de carga, primero debe crear un objeto de generador de clases que admita IUnknown, IClassFactory e IMarshal y, a continuación, llamar a CoRegisterClassObject para registrar el objeto como generador de clases para el CLSID solicitado.

El generador de clases registrado por el proceso suplente no es el generador de clases real implementado por el servidor DLL, pero es un generador de clases genérico implementado por el proceso suplente que admite IClassFactory e IMarshal. Dado que es el generador de clases del suplente, en lugar del servidor DLL que se está registrando, el generador de clases del suplente deberá usar el generador de clases real para crear una instancia del objeto para el CLSID registrado. El IClassFactory::CreateInstance del suplente debe tener un aspecto similar al del ejemplo siguiente:

STDMETHODIMP CSurrogateFactory::CreateInstance(
  IUnknown* pUnkOuter, 
  REFIID iid, 
  void** ppv)
{
    void* pcf;
    HRESULT hr;
 
    hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, &pcf);
    if ( FAILED(hr) )
        return hr;
    hr = ((IClassFactory*)pcf)->CreateInstance(pUnkOuter, iid, ppv);
    ((IClassFactory*)pcf)->Release();
    return hr;
}
 

El generador de clases suplente también debe admitir IMarshal porque una llamada a CoGetClassObject puede solicitar cualquier interfaz desde el generador de clases registrado, no solo IClassFactory. Además, dado que el generador de clases genérico solo admite IUnknown e IClassFactory, las solicitudes de otras interfaces deben dirigirse al objeto real. Por lo tanto, debe haber un método MarshalInterface que debe ser similar al siguiente:

STDMETHODIMP CSurrogateFactory::MarshalInterface(
  IStream *pStm,  
  REFIID riid, void *pv, 
  WORD dwDestContext, 
  void *pvDestContext, 
  DWORD mshlflags )
{   
    void * pCF = NULL;
    HRESULT hr;
 
    hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, riid, &pCF);
    if ( FAILED(hr) )
        return hr;   
    hr = CoMarshalInterface(pStm, riid, (IUnknown*)pCF, dwDestContext, pvDestContext,  mshlflags);
    ((IUnknown*)pCF)->Release();
    return S_OK;
 

El suplente que aloja un servidor DLL debe publicar los objetos de clase del servidor DLL con una llamada a CoRegisterClassObject. Todos los generadores de clases para suplentes DLL deben registrarse como REGCLS_SURROGATE. REGCLS_SINGLUSE y REGCLS_MULTIPLEUSE no deben usarse para los servidores DLL cargados en suplentes.

Siga estas instrucciones para crear un proceso suplente cuando sea necesario hacerlo, debe garantizar un comportamiento adecuado.

Suplentes de DLL