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

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

Здесь при определении методов используются следующие макросы

#define STDMETHODIMP HRESULT stdcall

#define STDMETHODIMP (type) type stdcall

теперь надо поговорить об основном стандартном интерфейсе модели COM — IUknown.

Как уже не раз говорилось, любой интерфейс СОМ должен порождаться от IUnknown или от другого интерфейса. Следовательно, все интерфейсы СОМ имеют общего предка — интерфейс IUnknown. Этот интерфейс определяется в <unknwn.h> и его GUID равен

00000000-0000-0000-С000-000000000046.

Интерфейс IUnknown определяет 3 метода, и все эти методы должны быть реализованы в каждом коклассе

• Querylnterfасе()

Данный метод обеспечивает клиента информацией о том, реализован ли интересующий его интерфейс в данном коклассе. В случае реализованное™ запрашиваемого интерфейса клиент получает ссылку на интерфейс. Этот подход обеспечивает необходимую гибкость, позволяя работать с одним компонентам различным клиентам, имеющим различный уровень знаний о доступных интерфейсах.

Семантика этого метода следующая. Имея указатель некоторого интерфейса pIFacel некоторого объекта и передавая в Queryinterfасе ссылку на идентификатор нового интерфейса IID_IFace2 можно получить указатель на новый интерфейс piFace2, если он реализован в данном объекте. В случае успеха возвращаемое значение S_OK, а в случае неудачи — E_NOINTERFACE

hr = pIFacel->QueryInterfасе(IID_IFace2, (void**)&pIFace2);

При реализации этого метода нужно обеспечить выполнение следующего принципа — клиент, имеющий ссылку на некоторый интерфейс объекта, должен иметь возможность перехода к любому другому интерфейсу этого объекта.

Эта реализация может обеспечиваться за счет использования таблиц виртуальных функций, которыми и являются все методы всех интерфейсов (при реализации кокласса на C++). Заметим, что если кокласс порожден от независимых друг от друга интерфейсов (т. е. один интерфейс не является потомком другого), то компилятор C++ создает виртуальных таблиц — по одной на каждый интерфейс. В каждой таблице хранятся указатели на все методы всех интерфейсов, от которых порожден данный интерфейс. Следовательно, начинается каждая таблица виртуальных функций с указателей на методы интерфейса iunknown. Обратите внимание, что реализовать каждый метод нужно только один раз, не зависимо от числа его появлений в таблицах виртуальных функций данного класса.

• AddRef()

В СОМ управление временем жизни объекта выполняется при использовании функций AddRef() и Reiease(). Taк как объект может использоваться многими клиентами одновременно, ни один из клиентов не имеет права удалить объект из памяти. В СОМ каждый активизированный объект ведет подсчет сделанных на него ссылок. При обнулении этого счетчика кокласс удаляет себя из памяти. Метод AddRef() вызывается при появлении новой ссылки на объект и увеличивает значение счетчика (в нашем случае это m refcount) на 1. Возвращает данный метод текущее число ссылок.

• Release ()

Этот метод вызывается при освобождении ссылки на объект и уменьшает значение счетчика на 1. Он же удаляет кокласс из памяти при обнулении счетчика ссылок. Метод возвращает текущее число ссылок.

Теперь реализация класса CoBоок

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

// СоВоок. срр: реализация класса СоВоок.

//

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

#include <stdio.h>

#include "СоВоок. h"

extern ULONG g_objCount; // Счетчик числа объектов

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

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

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

СоВоок::СоВоок()

{

              m_refCount = 0;

              ++g_obj Count;

              m_bstrTitle = SysAllocString(L"");

              m_bstrAuthor = SysAllocString(L"");

}

CoBook::~CoBook()

{

             -- g_objCount;

             if(m_bstrTitle)

                        SysFreeString(m_bstrTitle);

              if(m_bstrAuthor)

                        SysFreeString(m_bstrAuthor);

}

// IUnknown

STDMETHODIMP_(ULONG) CoBook::AddRef()

{

               return ++m_refCount;

}

STDMETHODIMP_(ULONG) CoBook::Release()

{

              if (--m_refCount == 0)

              {

                          delete this;

                          return 0;

               }

               else

                          return m_refCount;





}

STDMETHODIMP CoBook::Querylnterface(REFIID riid, void** pIFace)

{

                if (riid == IID_IUnknown)

                {

                            *pIFace = (IUnknown*)this;

                }

                else if (riid == IID_IPub)

                }

                            *pIFace = (IPub*)this;

                 }

                else if (riid == IID_IBook)

                 {

                            *pIFace = (IBook*)this;

                 }

                 else

                 {

                            *pIFace = NULL; return E_NOINTERFACE;

                 }

                 ((IUnknown*)(*pIFace))->AddRef();

                 return S OK;

}

//IPub&IBook

                 STDMETHODIMP CoBook::SetTitle (BSTR bstrTitle)

                 {

                            SysReAllocString(&m_bstrTitle, bstrTitle);

                            return S_OK;

                  }

                  STDMETHODIMP CoBook::SetYear(int nYear)

                  {

                           m_nYear = nYear;

                           return S_OK;

                  }

                  STDMETHODIMP CoBook::SetAuthor(BSTR bstrAuthor)

                  {

                           SysReAllocString(&m_bstrAuthor, bstrAuthor);

                           return S_OK;

                   }

                   STDMETHODIMP CoBook::Getlnfo(BSTR *pbstrInfo)

                   {

                         char* pszTitle = NULL;

                         char* pszAuthor = NULL;

                         char* pszText = NULL;

                         int nAuthorLength, nTitleLength;

                         nAuthorLength = SysStringLen(m_bstrAuthor);

                         nTitleLength = SysStringLen(m_bstrTitle);

                         pszAuthor = (char*)malloc(2*nAuthorLength);

                         pszTitle = (char*)malloc(2*nTitleLength);

                         pszText = (char*)malloc(2*nAuthorLength + 2*nTitleLength + 50);

                         wcstombs(pszTitle, m_bstrTitle, 2*nTitleLength);

                         wcstombs(pszAuthor, m_bstrAuthor, 2*nAuthorLength);

                         sprintf(pszText,

                              "Book

                                  *pbstrInfo = SysAllocStringLen(NULL, 2*strlen(pszText));

                          mbstowcs (*pbstrInfo, pszText, 2*strlen (pszText));