Dela via


Skriva en anpassad ersättare

Även om det systemlevererade surrogatet kommer att vara mer än tillräckligt för de flesta situationer, finns det vissa fall där det kan vara värt att skriva ett anpassat surrogat. Följande är några exempel:

  • En anpassad surrogat kan ge vissa optimeringar eller semantik som inte finns i systemet surrogat.
  • Om en processbaserad DLL innehåller kod som är beroende av att vara i samma process som klienten fungerar inte DLL-servern korrekt om den körs i systemsurrogaten. En anpassad surrogat kan skräddarsys för en specifik DLL för att hantera detta.
  • System surrogat stöder en modell för blandad trådning så att den kan läsa in både kostnadsfria DLL:er och lägenhetsmodell-DLL:er. En anpassad surrogat kan skräddarsys för att endast läsa in lägenhets-DLL:er av effektivitetsskäl eller för att acceptera ett kommandoradsargument för den typ av DLL som den tillåts läsa in.
  • Ett anpassat surrogat kan ta extra kommandoradsparametrar som systemets surrogat inte kan.
  • Systemets surrogat anropar CoInitializeSecurity och instruerar det att använda befintliga säkerhetsinställningar som finns under nyckeln AppID i registret. En anpassad surrogat kan använda en annan säkerhetskontext.
  • Gränssnitt som inte är fjärråtkomliga (till exempel de för de senaste OCX-komponenterna) fungerar inte med systemets surrogat. En anpassad surrogat kan omsluta DLL-gränssnittet med sin egen implementering och använda proxy-/stub-DLL:er med en fjärrkommunikationsbar IDL-definition som gör att gränssnittet kan fjärranslutas.

Den huvudsakliga surrogattråden bör vanligtvis utföra följande installationssteg:

  1. Anropa CoInitializeEx för att initiera tråden och ange trådmodellen.
  2. Om du vill att DLL-servrarna som ska köras på servern ska kunna använda säkerhetsinställningarna i registernyckeln AppID anropar du CoInitializeSecurity med funktionen EOAC_APPID. Annars används äldre säkerhetsinställningar.
  3. Anropa CoRegisterSurrogate för att registrera surrogatgränssnittet till COM.
  4. Anropa ISurrogate::LoadDllServer för det begärda CLSID:t.
  5. Placera huvudtråden i en loop för att anropa CoFreeUnusedLibraries regelbundet.
  6. När COM anropar ISurrogate::FreeSurrogateåterkallar du alla klassfabriker och avslutar.

En surrogatprocess måste implementera gränssnittet ISurrogate. Det här gränssnittet bör registreras när en ny surrogat startas och efter att ha anropat CoInitializeEx. Som du ser i föregående steg har gränssnittet ISurrogate två metoder som COM anropar: LoadDllServerför att dynamiskt läsa in nya DLL-servrar i befintliga surrogatservrar. och FreeSurrogate, för att frigöra surrogat.

Implementeringen av LoadDllServer, som COM anropar med en belastningsbegäran, måste först skapa ett klassfabriksobjekt som stöder IUnknown, IClassFactoryoch IMarshaloch sedan anropa CoRegisterClassObject för att registrera objektet som klassfabrik för det begärda CLSID.

Klassfabriken som registrerats av surrogatprocessen är inte den faktiska klassfabriken som implementeras av DLL-servern, utan är en generisk klassfabrik som implementeras av surrogatprocessen som stöder IClassFactory och IMarshal. Eftersom det är surrogatens klassfabrik, snarare än DLL-serverns, som registreras, måste surrogatens klassfabrik använda den riktiga klassfabriken för att skapa en instans av objektet för den registrerade CLSID:n. Surrogatens IClassFactory::CreateInstance bör se ut ungefär som i följande exempel:

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

Surrogatens klassfabrik måste också ha stöd för IMarshal- eftersom ett anrop till CoGetClassObject kan begära valfritt gränssnitt från den registrerade klassfabriken, inte bara IClassFactory. Eftersom den generiska klassfabriken endast stöder IUnknown och IClassFactorymåste begäranden om andra gränssnitt dirigeras till det verkliga objektet. Det bör därför finnas en MarshalInterface- metod som bör likna följande:

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;
 

Surrogaten som rymmer en DLL-server måste publicera DLL-serverns klassobjekt med ett anrop till CoRegisterClassObject. Alla klassfabriker för DLL-surrogater bör registreras som REGCLS_SURROGATE. REGCLS_SINGLUSE och REGCLS_MULTIPLEUSE ska inte användas för DLL-servrar som läses in i surrogater.

Att följa dessa riktlinjer för att skapa en surrogatprocess när det är nödvändigt att göra det bör säkerställa korrekt beteende.

DLL-surrogater