Vytvoření vlastní náhradní náhražky
I když bude systémová náhrada ve většině situací naprosto dostačující, někdy může být přínosné napsat vlastní náhradu. Tady je několik příkladů:
- Vlastní náhrada by mohla poskytnout některé optimalizace nebo sémantiku, které nejsou přítomné v náhradním systému.
- Pokud knihovna DLL v procesu obsahuje kód, který závisí na tom, že je ve stejném procesu jako klient, server knihovny DLL nebude správně fungovat, pokud je spuštěn v náhradním systému. Vlastní náhrada by mohla být přizpůsobena konkrétní knihovně DLL, aby se s tím mohla vypořádat.
- Náhradní systém podporuje model se smíšenými vlákny, aby mohl načíst knihovny DLL modelu volného i apartmánového modelu. Vlastní zástupce může být upraven tak, aby z důvodu efektivity načítal pouze knihovny DLL apartmánů nebo aby přijímal argument příkazového řádku pro typ knihovny DLL, který je povoleno načíst.
- Vlastní náhradní objekt může mít další parametry příkazového řádku, které systémový náhradní objekt nepodporuje.
- Systémový náhradník volá CoInitializeSecurity a informuje ho k tomu, aby používal všechna existující nastavení zabezpečení nalezená v klíči AppID v registru. Vlastní náhradník může použít jiný kontext zabezpečení.
- Rozhraní, která nejsou vzdáleně ovladatelná (například rozhraní pro nedávné OCX), nebudou se systémovým zástupcem fungovat. Vlastní zástupce by mohl zabalit rozhraní knihovny DLL vlastní implementací a používat proxy/zástupné knihovny DLL s IDL definicí, která umožňuje vzdálené rozhraní.
Hlavní náhradní vlákno by obvykle mělo provést následující kroky nastavení:
- Voláním CoInitializeEx inicializujete vlákno a nastavíte model threadingu.
- Pokud chcete, aby DLL servery, které mají běžet na serveru, mohly používat nastavení zabezpečení v klíči registru AppID, volejte CoInitializeSecurity s EOAC_APPID. Jinak se použijí starší nastavení zabezpečení.
- Volání CoRegisterSurrogate zaregistrovat náhradní rozhraní com.
- Volejte ISurrogate::LoadDllServer pro požadovaný CLSID.
- Umístěte hlavní vlákno do smyčky pro pravidelné volání CoFreeUnusedLibraries.
- Když COM volá ISurrogate::FreeSurrogate, odvolejte všechny továrny na třídy a ukončete.
Náhradní proces musí implementovat rozhraní ISurrogate. Toto rozhraní by mělo být registrováno při spuštění nového zástupce a po volání CoInitializeEx. Jak je uvedeno v předchozích krocích, rozhraní ISurrogate má dvě metody, které COM volá: LoadDllServer, pro dynamické načítání nových DLL serverů do stávajících náhradníků; a FreeSurrogate, pro uvolnění náhradníka.
Implementace LoadDllServer, kterou COM volá s žádostí o načtení, musí nejprve vytvořit objekt továrny tříd, který podporuje IUnknown, IClassFactorya IMarshal, a potom zavolat CoRegisterClassObject, aby zaregistroval objekt jako továrnu tříd pro požadovaný CLSID.
Objekt pro vytváření tříd zaregistrovaný náhradním procesem není skutečnou továrnou tříd implementovanou serverem DLL, ale je obecnou továrnou tříd implementovanou náhradním procesem, která podporuje IClassFactory a IMarshal. Vzhledem k tomu, že se jedná o náhradní továrnu tříd, nikoli o server DLL, který je registrován, bude náhradní továrna tříd muset použít skutečnou továrnu třídy pro vytvoření instance objektu pro registrované CLSID. Náhradní funkce IClassFactory::CreateInstance by měla vypadat přibližně následovně:
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;
}
Náhradní továrna tříd musí také podporovat IMarshal, protože volání CoGetClassObject může požadovat libovolné rozhraní z registrované továrny tříd, nejen IClassFactory. Dále, protože obecná objekt pro vytváření tříd podporuje pouze IUnknown a IClassFactory, požadavky na jiná rozhraní musí být směrovány na skutečný objekt. Proto by měla existovat metoda MarshalInterface, která by měla vypadat nějak takto:
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;
Zástupce, který hostí server DLL, musí publikovat objekt(y) třídy serveru DLL voláním CoRegisterClassObject. Všechny továrny tříd pro DLL zástupce musí být registrovány jako REGCLS_SURROGATE. REGCLS_SINGLUSE a REGCLS_MULTIPLEUSE by se neměly používat pro servery DLL načtené do náhradních procesů.
Pokud je to nutné, postupujte podle těchto pokynů pro vytvoření náhradního procesu, aby bylo zajištěno správné chování.
Související témata