In-proc сервер должен уметь делать следующие вещи : регистрировать компоненты в реестре
Windows ( поддерживать саморегистрацию ), создавать фабрику класса и управлять своим
временем жизни.
Для поддержки саморегистрации DLL сервера должна экспортировать две функции : DllRegisterServer() и DllUnregisterServer(). Эти
функции должны вставлять или удалять соответствующие ключи в реестр системы.
Для создания фабрики класса предназначена функция DllGetClassObject()
.Реализована она может быть примерно так:
STDAPI DllGetClassObject(const CLSID& clsid,
const IID& iid,
void** ppv)
{
HRESULT hr;
CMyClassFactory* pFactory;
if(clsid!=CLSID_MyComObject) return E_CLASSNOTAVAILABLE;
pFactory=new CMyClassFactory;
hr=pFactory->QueryInterface(iid,ppv);
if(FAILED(hr)) delete pFactory;
return hr;
}
Когда клиент хочет создать компонент, он вызывает функцию библиотеки COM
CoCreateInstance(). Та, в свою очередь, вызывает CoGetClassObject()
для получения фабрики класса. В случае in-proc сервера
CoGetClassObject() запрашивает у DLL сервера DllGetClassObject()
. Получив фабрику класса, CoGetClassObject() вызывает функцию
CreateInstance() интерфейса IClassFactory,
которая и создает требуемый компонент.
Для управления временем жизни сервера предназначена функция
DllCanUnloadNow(). Для освобождения неиспользуемых DLL библиотека COM предоставляет
функцию CoFreeUnusedLibraries(), которая опрашивает DLL, вызывфя
DllCanUnloadNow(). DllCanUnloadNow() проверяет,
есть ли еще обслуживаемые компоненты. Если их нет, DLL может быть выгружена. Для определения
наличия обслуживаемых компонентов необходимо завести два счетчика. Значение первого
увеличивает конструктор компонента, а уменьшает деструктор. Вторым счетчиком управляет
функция LockServer() фабрики класса. Когда оба счетчика становятся
равными нулю, DLL выгружается из памяти.
int g_ComponentCoun;
int g_LockCount;
STDAPI DllCanUnloadNow()
{
if((g_ComponentCount==0) && (g_LockCount==0)) return S_OK;
else return S_FALSE;
}
CMyComObject::CMyComObject()
{
InterlockedIncrement(&g_ComponentCount);
}
CMyComObject::~CMyComObject()
{
InterlockedDecrement(&g_ComponentCount);
}
STDMETHODIMP CMyFactory::LockServer(BOOL bLock)
{
if(bLock) InterlockedIncrement(&g_LockCount);
else InterlockedDecrement(&g_LockCount);
return S_OK;
}
|