Написание пользовательского суррогата
Хотя суррогат, предоставляемый системой, будет более чем достаточно для большинства ситуаций, есть некоторые случаи, когда написание пользовательского суррогата может быть стоит. Ниже приводятся некоторые примеры.
- Пользовательский суррогат может обеспечить некоторые оптимизации или семантику, не присутствующих в суррогатной системе.
- Если библиотека DLL в процессе содержит код, который зависит от того, что находится в том же процессе, что и клиент, сервер DLL не будет работать правильно, если он работает в системе суррогат. Пользовательский суррогат может быть адаптирован к определенной библиотеке DLL для решения этой проблемы.
- Суррогат системы поддерживает модель смешанного потока, чтобы она могли загружать как бесплатные, так и библиотеки DLL моделей квартир. Настраиваемый суррогат может быть адаптирован для загрузки только библиотек DLL квартиры по соображениям эффективности или принять аргумент командной строки для типа БИБЛИОТЕК DLL, который разрешено загрузить.
- Пользовательский суррогат может принимать дополнительные параметры командной строки, которые система суррогат не выполняет.
- Системный суррогат вызывает CoInitializeSecurity и сообщает ему использовать все существующие параметры безопасности, найденные в разделе AppID в реестре. Пользовательский суррогат может использовать другой контекст безопасности.
- Интерфейсы, которые не являются ремотируемыми (например, для последних OCX) не будут работать с суррогатной системой. Пользовательский суррогат может упаковать интерфейсы БИБЛИОТЕКи DLL с собственной реализацией и использовать библиотеки DLL прокси-сервера или заглушки с определением remotable IDL, которое позволит удаленному интерфейсу.
Основной суррогатный поток обычно должен выполнять следующие действия по настройке:
- Вызовите CoInitializeEx , чтобы инициализировать поток и задать модель потоков.
- Если вы хотите, чтобы серверы DLL, выполняемые на сервере, могли использовать параметры безопасности в разделе реестра AppID , вызовите CoInitializeSecurity с возможностью EOAC_APPID. В противном случае будут использоваться устаревшие параметры безопасности.
- Вызовите CoRegisterSurrogate , чтобы зарегистрировать суррогатный интерфейс в COM.
- Вызовите ISurrogate::LoadDllServer для запрошенного CLSID.
- Поместите основной поток в цикл, чтобы периодически вызывать CoFreeUnusedLibraries.
- Когда COM вызывает ISurrogate::FreeSurrogate, отмените все фабрики классов и выход.
Суррогатный процесс должен реализовать интерфейс ISurrogate. Этот интерфейс следует зарегистрировать при запуске нового суррогата и после вызова CoInitializeEx. Как указано на предыдущих шагах, интерфейс ISurrogate имеет два метода, вызывающие COM: LoadDllServer, для динамической загрузки новых dll-серверов в существующие суррогаты; и FreeSurrogate для освобождения суррогата.
Реализация LoadDllServer, которая вызывает COM с запросом нагрузки, должна сначала создать объект фабрики классов, поддерживающий IUnknown, IClassFactory и IMarshal, а затем вызвать CoRegisterClassObject, чтобы зарегистрировать объект в качестве фабрики классов для запрошенного CLSID.
Фабрика классов, зарегистрированная суррогатным процессом, не является фактической фабрикой классов, реализованной сервером DLL, но является фабрикой универсальных классов, реализованной суррогатным процессом, поддерживающим IClassFactory и IMarshal. Так как это фабрика классов суррогата, а не сервер DLL, зарегистрированный, фабрика классов суррогата должна будет использовать фабрику реальных классов для создания экземпляра объекта для зарегистрированного CLSID. Суррогат IClassFactory::CreateInstance должен выглядеть примерно так:
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;
}
Фабрика классов суррогата также должна поддерживать IMarshal, так как вызов CoGetClassObject может запрашивать любой интерфейс из зарегистрированной фабрики классов, а не только IClassFactory. Кроме того, так как фабрика универсальных классов поддерживает только IUnknown и IClassFactory, запросы для других интерфейсов должны направляться в реальный объект. Таким образом, должен быть метод MarshalInterface , который должен быть похож на следующий:
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;
Суррогат, на котором размещается сервер DLL, должен публиковать объекты класса DLL-сервера с вызовом CoRegisterClassObject. Все фабрики классов для суррогатов DLL должны быть зарегистрированы как REGCLS_SURROGATE. REGCLS_SINGLUSE и REGCLS_MULTIPLEUSE не следует использовать для серверов DLL, загруженных в суррогаты.
Следуя этим рекомендациям по созданию суррогатного процесса, если это необходимо сделать, должно обеспечить надлежащее поведение.
См. также