Написание пользовательского суррогата
Хотя суррогат, предоставляемый системой, будет более чем адекватным для большинства ситуаций, есть некоторые случаи, когда написание пользовательского суррогата может быть полезным. Ниже приводятся некоторые примеры.
- Пользовательский суррогат может обеспечить некоторые оптимизации или семантику, отсутствуют в суррогате системы.
- Если внутрипроцессная библиотека DLL содержит код, который зависит от того, что находится в том же процессе, что и клиент, сервер DLL будет работать неправильно, если он выполняется в системном суррогате. Настраиваемый суррогат может быть адаптирован к определенной библиотеке DLL для решения этой проблемы.
- Суррогат системы поддерживает модель смешанного потока, чтобы она могли загружать библиотеки DLL как бесплатных, так и многоквартирных моделей. Настраиваемый суррогат может быть адаптирован для загрузки только библиотек DLL квартир по соображениям эффективности или принятия аргумента командной строки для типа dll, который можно загрузить.
- Настраиваемый суррогат может принимать дополнительные параметры командной строки, которые не имеет системный суррогат.
- Суррогат системы вызывает CoInitializeSecurity и сообщает ему использовать все существующие параметры безопасности, найденные в разделе AppID в реестре. Пользовательский суррогат может использовать другой контекст безопасности.
- Интерфейсы, которые не являются ремотируемыми (например, для последних OCX) не будут работать с суррогатной системой. Настраиваемый суррогат может упаковывать интерфейсы БИБЛИОТЕК DLL в собственную реализацию и использовать библиотеки DLL прокси-сервера или заглушки с помощью определения 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, загруженных в суррогаты.
Следуя этим рекомендациям по созданию суррогатного процесса, когда это необходимо сделать, должно обеспечить правильное поведение.
Связанные темы