Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
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);