Добавить в цитаты Настройки чтения

Страница 181 из 372

//////////////////////////////////////////////////

// СоJournalFactory.срр: реализация фабрики класса СоJournalFactory

// для кокласса CoJournal

//////////////////////////////////////////////////

#include "СоJournalFactory.h"

extern ULONG g_lockCount;

extern ULONG g_objCount;

//////////////////////////////////////////////////

// Конструктор и деструктор

//////////////////////////////////////////////////

CoJournalFactory::СоJournalFactory ()

{

         m_refCount = 0;

         g_objCount++;

}

CoJournalFactory::~CoJournalFactory()

{

         g_obj Count-;

}

//IUnknown

STDMETHODIMP_(ULONG) CoJournalFactory::AddRef() {

         return ++m_refCount;

}

STDMETHODIMP_(ULONG) CoJournalFactory::Release()

{

         if (-m_refCount == 0)

         {

                   delete this;

                   return 0;

          }

          else

                   return m refCount;

}

STDMETHODIMP CoJournalFactory::Querylnterface(REFIID riid, void** ppv)

{

           if(riid == IID_IUnknown)

           {

                    *ppv = (IUnknown*)this;

           }

           else if(riid == IID_IClassFactory)

           {

                     *ppv = (IdassFactory*) this;

            }

           else

            {

                     *ppv = NULL;

                     return E_NOINTERFACE;

            }

            (IUnknown*)(*ppv)) — >AddRef();

            return S OK;

}

//IClassFactory

STDMETHODIMP CoJournaiFactory::Createlnstance(

             LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)

{

             if(pUnkOuter!= NULL)

             {

                    return СLASS_E_NOAGGREGATION;

             }

              CoJournal* pJournalObj = NULL;

              HRESULT hr;

              pJournalObj = new CoJournal;

              hr = pJournalObj — > QueryInterface(riid, ppv);

              if (FAILED(hr))

              delete pJournalObj;





              return hr;

}

STDMETHODIMP CoJournalFactory::LockServer(BOOL fLock)

{

              if (fLock)

                       ++g_lockCount;

              else

                       --g_lockCount;

              return S OK;

}

Заканчивая разговор о фабрике класса нужно заметить, что для нее не нужно задавать GUID.

Сервер в процессе клиента

Итак, для активации некоторого СОМ объекта необходимо создать фабрику класса для соответствующего класса и получить указатель на интерфейс IClassFactory. Далее, используя этот интерфейс, можно создать любое число экземпляров этого кокласса и получить указатели на любые реализуемые коклассом интерфейсы. Но как создать фабрику класса?

Все, что достаточно знать клиенту о коклассе, это его глобальный идентификатор (GUID). Зная этот идентификатор, клиент может воспользоваться функцией CoGetClassObject, которая заставит менеджер управления сервисом найти и загрузить нужный сервер (в котором "живет" нужный кокласс), активизировать фабрику класса для этого кокласса и возвратить клиенту указатель на интерфейс IClassFactory.

Всю необходимую информацию менеджер получает из реестра системы. Подробнее это будет обсуждаться далее, пока достаточно заметить, что реестр представляет собой специальную базу данных, используя которую, в частности, по глобальному идентификатору кокласса можно узнать тип сервера, в котором этот кокласс "живет" (сервер в процессе клиента, сервер в другом процессе на этой же машине или сервер на удаленной машине), путь к серверу (для серверов на данной машине) или путь к удаленной машине (для сервера на удаленной машине).

Далее работа менеджера зависит от типа сервера.

Пока мы строим сервер в процессе клиента, реализуемый в виде dll. Для этого, при работе в Visual C++, можно создать пустое рабочее пространство проекта Win32 DLL с именем PubInPrосServer. В этом проекте нужно создать (или перенести созданные в другом месте) классы CoBook, CoJournal, CoBookFactory, СоJournalFactory. Там же ДОЛЖНЫ находиться файлы с определениями интерфейсов IPub, IBook, IJournal, файл с GUID для всех интерфейсов и коклассов iid.h и (как советует Э.Трельсен в книге [3]) следующий файл iid.cpp

// iid.cpp: гарантирует автоматический вызов <initguid.h>

// перед "iid.h"

#include <windows.h>

#include <initguid.h>

#include "iid.h"

Теперь нужно создать файл, имя которого совпадает с именем проекта — PublnProcServer.cpp:

#include "CoBookFactory.h"

#include "CoJournalFactory.h"

ULONG g_lockCount = 0;

ULONG g_objCount = 0;

STDAPI DllCanUnloadNow()

{

          if (g_lockCount == 0 && g_objCount == 0)

                       return S_OK;

          else

                       return S_FALSE;

}

STDAPI DllGetClassObject(REFCLSID rclsid,

           REFIID riid, void** ppv)

{

           HRESULT hr;

           CoBookFactory* pBookFact = NULL;

           CoJournaiFactory* pJournalFact = NULL;

           if (rclsid == CLSID_CoBook)

           {

                       pBookFact = new CoBookFactory;

                       hr = pBookFact —> QueryInterface(riid, ppv);

                       if (FAILED(hr))

                                  delete pBookFact;

                       return hr;

            }

            else if (rclsid == CLSID_CoJournal)

            {

                       pJournalFact = new CoJournaiFactory;

                       hr = pJournalFact->QueryInterface(riid, ppv);

                       if (FAILED(hr))

                                  delete pJournalFact;

                       return hr;

              }

              else

              return СLASS_E_CLASSNOTAVAILABLE;

}

В файле PubInProcServer.cpp определяются и инициализируются нулем две глобальные переменные g_lockCount, g_objCount — соответственно счетчики числа блокировок сервера в памяти и числа активных объектов.

Далее дается реализация двух экспортируемых из dll функций — DllGetClassObject и DllCanUnioadNow. Используя первую, менеджер управления сервисом (из СОМ) сможет активизировать фабрику класса запрашиваемого кокласса и получить указатель на интерфейс ICiassFactory соответствующей фабрики класса. Вторая функция используется менеджером на этапе принятия решения об удалении сервера из памяти.

Рассмотрим подробнее реализацию функции DllGetClassObject.

Эта функция получает в качестве аргументов ссылку на GUID нужного кокласса, ссылку на желаемый интерфейс фабрики класса этого кокласса (обычно IID_IClassFactory) и в качестве выходного параметра возвращает указатель на запрашиваемый интерфейс. Возвращаемое функцией значение типа HRESULT говорит об успехе или неудаче операции. В последнем случае можно выяснить причину неудачи. Дня проверки успешности операции можно использовать определенные в СОМ макроопределения SUCCEEDED() и FAILED(), анализирующие старший бит возвращенного значения типа HRESULT.