Partilhar via


Escrevendo uma procuração personalizada

Embora o substituto fornecido pelo sistema seja mais do que adequado para a maioria das situações, há alguns casos em que escrever um substituto personalizado pode valer a pena. Seguem-se alguns exemplos:

  • Um substituto personalizado pode fornecer algumas otimizações ou semânticas não presentes no substituto do sistema.
  • Se uma DLL em processo contiver código que depende de estar no mesmo processo que o cliente, o servidor DLL não funcionará corretamente se estiver sendo executado no substituto do sistema. Um substituto personalizado pode ser adaptado a uma DLL específica para lidar com isso.
  • O substituto do sistema suporta um modelo de threads misto para que possa carregar tanto DLLs de modelo livre como de apartamento. Um substituto personalizado pode ser adaptado para carregar apenas apartment DLLs por motivos de eficiência ou para aceitar um argumento de linha de comando, especificando o tipo de DLL que o substituto está autorizado a carregar.
  • Um substituto personalizado pode ter parâmetros de linha de comando extras que o substituto do sistema não tem.
  • O substituto do sistema chama CoInitializeSecurity e informa que deve usar qualquer configuração de segurança existente encontrada na chave de AppID no registro. Um substituto personalizado pode usar outro contexto de segurança.
  • As interfaces que não são remotas (como as de OCXs recentes) não funcionarão com o substituto do sistema. Um substituto personalizado poderia envolver as interfaces da DLL com a sua própria implementação e usar DLLs de proxy/stub com uma definição IDL remotável, o que permitiria que a interface fosse acessada remotamente.

O thread substituto principal normalmente deve executar as seguintes etapas de configuração:

  1. Chame CoInitializeEx para inicializar o thread e definir o modelo de threading.
  2. Se você quiser que os servidores DLL que serão executados no servidor possam usar as configurações de segurança no AppID chave do Registro, chame CoInitializeSecurity com o recurso EOAC_APPID. Caso contrário, as configurações de segurança herdadas serão usadas.
  3. Ligue CoRegisterSurrogate para registar a interface de substituição no COM.
  4. Chame ISurrogate::LoadDllServer para o CLSID solicitado.
  5. Coloque o thread principal em um loop para chamar CoFreeUnusedLibraries periodicamente.
  6. Quando COM chamar ISurrogate::FreeSurrogate, revogue todas as fábricas de classes e saia.

Um processo substituto deve implementar a interface ISurrogate. Essa interface deve ser registrada quando um novo substituto é iniciado e depois de chamar CoInitializeEx. Como indicado nas etapas anteriores, a interface ISurrogate tem dois métodos que COM chama: LoadDllServer, para carregar dinamicamente novos servidores DLL em substitutos existentes; e FreeSurrogate, para libertar o substituto.

A implementação de LoadDllServer, que COM chama com uma solicitação de carga, deve primeiro criar um objeto de fábrica de classe que suporte IUnknown, IClassFactorye IMarshale, em seguida, chamar CoRegisterClassObject para registrar o objeto como a fábrica de classes para o CLSID solicitado.

A fábrica de classe registrada pelo processo substituto não é a fábrica de classe real implementada pelo servidor DLL, mas é uma fábrica de classe genérica implementada pelo processo substituto que suporta IClassFactory e IMarshal. Como é a fábrica de classes do substituto, e não a do servidor DLL que está a ser registado, a fábrica de classes do substituto terá que recorrer à fábrica de classes real para criar uma instância do objeto para o CLSID já registado. O substituto IClassFactory::CreateInstance deve ser semelhante ao exemplo a seguir:

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;
}
 

A fábrica de classe substituta também deve suportar IMarshal porque uma chamada para CoGetClassObject pode solicitar qualquer interface da fábrica de classe registrada, não apenas IClassFactory. Além disso, como a fábrica de classe genérica suporta apenas IUnknown e IClassFactory, as solicitações para outras interfaces devem ser direcionadas para o objeto real. Assim, deve haver um método MarshalInterface que deve ser semelhante ao seguinte:

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;
 

O substituto que hospeda um servidor DLL deve publicar o(s) objeto(s) de classe do servidor DLL com uma chamada para CoRegisterClassObject. Todas as fábricas de classe para substitutos DLL devem ser registadas como REGCLS_SURROGATE. REGCLS_SINGLUSE e REGCLS_MULTIPLEUSE não devem ser usados para servidores DLL carregados em processos substitutos.

Seguir essas diretrizes para criar um processo substituto quando for necessário fazê-lo deve garantir um comportamento adequado.

DLL substitui