Freigeben über


Schreiben eines benutzerdefinierten Ersatzes

Während das vom System bereitgestellte Ersatz für die meisten Situationen mehr als angemessen ist, gibt es einige Fälle, in denen sich das Schreiben eines benutzerdefinierten Ersatzes lohnen könnte. Nachstehend sind einige Beispiele aufgeführt:

  • Ein benutzerdefiniertes Ersatzmodell kann einige Optimierungen oder Semantiken bereitstellen, die nicht im System surrogate vorhanden sind.
  • Wenn eine prozessinterne DLL Code enthält, der davon abhängt, dass er sich im selben Prozess wie der Client befindet, funktioniert der DLL-Server nicht ordnungsgemäß, wenn er im Systemersatz ausgeführt wird. Ein benutzerdefiniertes Ersatzangebot könnte an eine bestimmte DLL angepasst werden, um dies zu behandeln.
  • Das System surrogate unterstützt ein Mixed-Threading-Modell, sodass sowohl freie als auch Apartmentmodell-DLLs geladen werden können. Ein benutzerdefiniertes Ersatzmodul kann angepasst werden, um aus Gründen der Effizienz nur Apartment-DLLs zu laden oder ein Befehlszeilenargument für den Typ der DLL zu akzeptieren, die geladen werden darf.
  • Ein benutzerdefiniertes Ersatzmodell kann zusätzliche Befehlszeilenparameter verwenden, die vom Systemersatz nicht verwendet werden.
  • Das System surrogate ruft CoInitializeSecurity auf und weist es an, alle vorhandenen Sicherheitseinstellungen unter dem AppID-Schlüssel in der Registrierung zu verwenden. Ein benutzerdefiniertes Ersatzmodell könnte einen anderen Sicherheitskontext verwenden.
  • Schnittstellen, die nicht remotable sind (z. B. die für aktuelle OCX-Versionen), funktionieren nicht mit dem Systemersatz. Ein benutzerdefiniertes Ersatzmodell könnte die Schnittstellen der DLL mit einer eigenen Implementierung umschließen und Proxy-/Stub-DLLs mit einer remotable IDL-Definition verwenden, die die Remoteisierung der Schnittstelle ermöglichen würde.

Der Standard Ersatzthreads sollte in der Regel die folgenden Setupschritte ausführen:

  1. Rufen Sie CoInitializeEx auf, um den Thread zu initialisieren und das Threadingmodell festzulegen.
  2. Wenn die DLL-Server, die auf dem Server ausgeführt werden sollen, die Sicherheitseinstellungen im AppID-Registrierungsschlüssel verwenden können, rufen Sie CoInitializeSecurity mit der EOAC_APPID-Funktion auf. Andernfalls werden Legacysicherheitseinstellungen verwendet.
  3. Rufen Sie CoRegisterSurrogate auf, um die Ersatzschnittstelle bei COM zu registrieren.
  4. Rufen Sie ISurrogate::LoadDllServer für die angeforderte CLSID auf.
  5. Fügen Sie Standard Thread in eine Schleife ein, um CoFreeUnusedLibraries regelmäßig aufzurufen.
  6. Wenn COM ISurrogate::FreeSurrogate aufruft, widerrufen Sie alle Klassenfabriken, und beenden Sie.

Ein Ersatzprozess muss die ISurrogate-Schnittstelle implementieren. Diese Schnittstelle sollte beim Starten eines neuen Ersatzes und nach dem Aufrufen von CoInitializeEx registriert werden. Wie in den vorherigen Schritten angegeben, verfügt die ISurrogate-Schnittstelle über zwei Methoden, die COM aufruft: LoadDllServer, um neue DLL-Server dynamisch in vorhandene Ersatzprogramme zu laden; und FreeSurrogate, um den Ersatz zu befreien.

Die Implementierung von LoadDllServer, die COM mit einer Ladeanforderung aufruft, muss zuerst ein Klassen factory-Objekt erstellen, das IUnknown, IClassFactory und IMarshal unterstützt, und dann CoRegisterClassObject aufrufen, um das Objekt als Klassenfactory für die angeforderte CLSID zu registrieren.

Die vom Ersatzprozess registrierte Klassenfactory ist nicht die tatsächliche Klassenfactory, die vom DLL-Server implementiert wird, sondern eine generische Klassenfactory, die vom Ersatzprozess implementiert wird und IClassFactory und IMarshal unterstützt. Da es sich um die Klassenfactory des Ersatzs und nicht um die des zu registrierenden DLL-Servers handelt, muss die Klassenfactory des Ersatzs die reale Klassenfactory verwenden, um eine instance des Objekts für die registrierte CLSID zu erstellen. Die IClassFactory::CreateInstance des Ersatzanbieters sollte ungefähr wie das folgende Beispiel aussehen:

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

Die Klassenfactory des Ersatzs muss auch IMarshal unterstützen, da ein Aufruf von CoGetClassObject eine beliebige Schnittstelle von der registrierten Klassenfactory anfordern kann, nicht nur IClassFactory. Da die generische Klassenfactory nur IUnknown und IClassFactory unterstützt, müssen Anforderungen für andere Schnittstellen an das reale Objekt weitergeleitet werden. Daher sollte es eine MarshalInterface-Methode geben, die wie folgt aussehen sollte:

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;
 

Das Ersatzobjekt, das einen DLL-Server enthält, muss die Klassenobjekte des DLL-Servers mit einem Aufruf von CoRegisterClassObject veröffentlichen. Alle Klassenfabriken für DLL-Ersatzstellen sollten als REGCLS_SURROGATE registriert werden. REGCLS_SINGLUSE und REGCLS_MULTIPLEUSE sollten nicht für DLL-Server verwendet werden, die in Ersatzserver geladen werden.

Wenn Sie diese Richtlinien zum Erstellen eines Ersatzprozesses befolgen, wenn dies erforderlich ist, sollten Sie ein ordnungsgemäßes Verhalten sicherstellen.

DLL-Ersatz