Особенности реализации in-proc сервера.

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


Hosted by uCoz