Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

40

Из рис. 3-3 видно, что указатель this для CA указывает на указатель таблицы виртуальных функций IX. Таким образом, мы можем без изменения использовать для CA указатель this вместо указателя на IX. Однако очевидно, что указатель this для CA не указывает на указатель vtbl IY. Следовательно, указатель this CA надо модифицировать, прежде чем передавать функции, ожидающей указатель на IY. Для этого компилятор добавляет к указателю this CA смещение указателя vtbl IY (∆ IY). Приведенный ниже код:

IY* pC = pA;

компилятор транслирует во что-то вроде

IY* pC = (char*)pA + IY;

Более подробную информацию Вы можете найти в разделе «Multiple Inheritance and Casting» книги Маргарет А. Эллис (Margaret A. Ellis) и Бьерна Страуструпа (Bjarne Strourstrup) The Annotated C++ Reference Manual.

Компиляторы С++ не обязаны реализовывать vtbl при множественном наследовании именно так, как это показано на рис. 3-3.

А теперь все вместе

Давайте соберем вместе все элементы и рассмотрим полный пример реализации и использования QueryInterface.

Влистинге 3-1 представлен полный текст этой простой программы. Копию программы можно найти на прилагаемом к книге диске. Программа состоит из трех частей.

Впервой части объявляются интерфейсы IX, IY и IZ. Интерфейс IUnknown объявлен в заголовочном файле

UNKNWN.H Win32 SDK.

Вторая часть — это реализация компонента. Класс CA реализует компонент, поддерживающий интерфейсы IX и IY. Реализация QueryInterface совпадает с той, что была представлена в предыдущем разделе книги. Функция CreateInstance определена после класса CA. Клиент использует ее, чтобы создать компонент, предоставляемый при помощи CA, и получить указатель на IUnknown этого компонента.

После CreateInstance следуют определения IID для интерфейсов. Как видно их этих определений, IID — весьма громоздкая структура (более подробно мы рассмотрим ее в гл. 7). Наш пример программы компонуется с UUID.LIB, чтобы получить определения для IID_IUnknown (т.е. IID для IUnknown).

Третья и последняя часть — функция main, которая выступает в качестве клиента.

IUNKNOWN.CPP

//

//IUnknown.cpp

//Чтобы скомпилировать: cl IUnknown.cpp UUID.lib

//

#include <iostream.h> #include <objbase.h>

void trace(const char* msg) { cout << msg << endl; }

// Интерфейсы

interface IX : IUnknown

{

virtual void __stdcall Fx() = 0; };

interface IY : IUnknown

{

virtual void __stdcall Fy() = 0; };

interface IZ : IUnknown

{

virtual void __stdcall Fz() = 0; };

// Предварительные объявления GUID extern const IID IID_IX;

extern const IID IID_IY; extern const IID IID_IZ;

41

//

// Компонент

//

class CA : public IX, public IY

{

// Реализация IUnknown

virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv); virtual ULONG __stdcall AddRef() { return 0; }

virtual ULONG __stdcall Release() { return 0; }

// Реализация интерфейса IX

virtual void __stdcall Fx() { cout << "Fx" << endl; }

// Реализация интерфейса IY

virtual void __stdcall Fy() { cout << "Fy" << endl; }

};

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)

{

if (iid == IID_IUnknown)

{

trace("QueryInterface: Вернуть указатель на IUnknown"); *ppv = static_cast<IX*>(this);

}

else if (iid == IID_IX)

{

trace("QueryInterface: Вернуть указатель на IX"); *ppv = static_cast<IX*>(this);

}

else if (iid == IID_IY)

{

trace("QueryInterface: Вернуть указатель на IY"); *ppv = static_cast<IY*>(this);

}

else

{

trace("QueryInterface: Интерфейс не поддерживается");

*ppv = NULL;

return E_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef(); // См. гл. 4 return S_OK;

}

//

// Функция создания

//

IUnknown* CreateInstance()

{

IUnknown* pI = static_cast<IX*>(new CA); pI->AddRef();

return pI;

}

//

//IID

//{32bb8320-b41b-11cf-a6bb-0080c7b2d682} static const IID IID_IX =

{0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

//{32bb8321-b41b-11cf-a6bb-0080c7b2d682}

static const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

// {32bb8322-b41b-11cf-a6bb-0080c7b2d682} static const IID IID_IZ =

{0x32bb8322, 0xb41b, 0x11cf,

42

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

//

// Клиент

//

int main()

{

HRESULT hr;

trace("Клиент: Получить указатель на IUnknown"); IUnknown* pIUnknown = CreateInstance();

trace("Клиент: Получить указатель на IX");

IX* pIX = NULL;

hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX); if (SUCCEEDED(hr))

{

trace("Клиент: IX получен успешно");

pIX->Fx(); // Использовать интерфейс IX

}

trace("Клиент: Получить указатель на IY");

IY* pIY = NULL;

hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY); if (SUCCEEDED(hr))

{

trace("Клиент: IY получен успешно");

pIY->Fy();

// Использовать интерфейс IY

}

 

trace("Клиент: Запросить неподдерживаемый интерфейс");

IZ* pIZ = NULL;

hr = pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ); if (SUCCEEDED(hr))

{

trace("Клиент: Интерфейс IZ получен успешно"); pIZ->Fz();

}

else

{

trace("Клиент: Не могу получить интерфейс IZ");

}

trace("Клиент: Получить интерфейс IY через интерфейс IX");

IY* pIYfromIX = NULL;

hr = pIX->QueryInterface(IID_IY, (void**)&pIYfromIX); if (SUCCEEDED(hr))

{

trace("Клиент: IY получен успешно"); pIYfromIX->Fy();

}

trace("Клиент: Получить интерфейс IUnknown через IY");

IUnknown* pIUnknownFromIY = NULL;

hr = pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY); if (SUCCEEDED(hr))

{

cout << "Совпадают ли указатели на IUnknown? "; if (pIUnknownFromIY == pIUnknown)

{

cout << "Да, pIUnknownFromIY == pIUnknown" << endl;

}

else

{

cout << "Нет, pIUnknownFromIY != pIUnknown" << endl;

Соседние файлы в предмете Программирование на C++