Распределенная обработка данных
Содержание
Задание
№1 Реализация интерфейса COM
Задание
№1А QueryInterface
Задание №1B Подсчет
ссылок
Задание №1 Реализация
интерфейса COM
Цель работы:
Разработать
код на С++, реализующий простой интерфейс СОМ без динамической компоновки:
-
клиент
и компонент взаимодействуют через два интерфейса IX иIY, интерфейсы COM
реализованы как чисто абстрактные базовые классы С++;
-
в
качестве клиента использовать процедуру main;
-
компонент
реализуется классом СА, который наследует как IX так и IY;
-
класс
СА реализует функции-члены обоих интерфейсов (множественное наследование);
-
клиент
создает экземпляр компонента (для управления существованием компонента клиент
применяет оператора new и delete), далее он получает указатели на интерфейсы, поддерживаемые
компонентом, использовать эти указатели анологично указателям на классы С++;
-
выводить
промежуточные сообщения при использовании интерфейсов IX и IY;
-
удалить
компонент;
-
вместо
определения интерфейса как класса использовать определение из заголовочного
файла OBJBASE.H
#define interface struct
и
функции-члены объявлять с помощью
virtual void _stdcall … .
Теоретические
сведения:
В СОМ интерфейсы — это все. Для клиента компонент представляет
собой набор интерфейсов. Клиент может взаимодействовать с компонентом СОМ
только через интерфейс. С точки зрения программиста СОМ, интерфейсы — важная
часть любого приложения. Компоненты сами по себе есть просто детали реализации
интерфейсов.
Утверждение, что компонент — всего лишь деталь реализации
интерфейса, конечно, преувеличение. В конце концов, интерфейс без реализации
ничего не сделает. Однако компонент можно удалить и заменить другим; если новый
компонент поддерживает те же интерфейсы, что и старый, приложение будет
работать по-прежнему. Отдельные компоненты сами по себе не определяют
приложения. Приложение определяют интерфейсы между компонентами. Пока
интерфейсы неизменны, компоненты могут появляться и исчезать
Теперь рассмотрим код, реализующий простой интерфейс. В
приведенном ниже тексте программы компонент CA использует IX и IY для реализации двух
интерфейсов.
class IX // Первый интерфейс
{
public:
virtual
void Fx1() = 0;
virtual
void Fx2() = 0;
};
class
IY // Второй интерфейс
{
public:
virtual
void Fy1() = 0;
virtual
void Fy2() = 0;
};
class
CA : public IX, public IY // Компонент
{
public:
// Реализация
абстрактного базового класса IX
virtual
void Fx1() { cout << “Fx1” << endl; }
virtual
void Fx2() { cout << “Fx2” << endl; }
//
Реализация абстрактного базового класса IY
virtual
void Fy1() { cout << “Fy1” << endl; }
virtual
void Fy2() { cout << “Fy2” << endl; }
};
IX и IY — это чисто абстрактные базовые классы, которые используются для
реализации интерфейсов. Чистоабстрактный базовый класс (pure abstract base class) — это базовый класс,
который содержит только чисто виртуальные функции (pure virtual functions). Чисто виртуальная
функция — это виртуальная функция, «помеченная =0 — знаком спецификатора
чистоты (pure specifier). Чисто виртуальные функции не реализуютсяв классах, в которых
объявлены. Как видно из приведенного выше примера, функции IX::Fx1, IX::Fx2, IY::Fy1 и IY::Fy2 только декларируются.
Реализуются же они в производном классе. В приведенном фрагменте кода компонент
CA наследует два чисто
абстрактных базовых класса — IX и IY — и реализует их чисто виртуальные функции.
Для того, чтобы реализовать функции-члены IX и IY, CA использует множественное
наследование. Последнее означает, что класс является производным более чем от
одного базового класса. Класс С++ чаще всего использует единичное наследование,
т.е. имеет только один базовый класс.
Текст программы:
#include "stdafx.h"
#include
"iostream.h"
#include
"objbase.h" // Определить интерфейс
#include
"conio.h"
void
trace(const char* pMsg) { cout << pMsg << endl; }
// Абстрактные
интерфейсы
interface IX
{
virtual void
__stdcall Fx1() = 0;
virtual void
__stdcall Fx2() = 0;
};
interface IY
{
virtual void
__stdcall Fy1() = 0;
virtual void
__stdcall Fy2() = 0;
};
// Реализация интерфейса
class CA : public IX,
public IY
{
public:
// Реализация интерфейса IX
virtual void
__stdcall Fx1() { cout << "CA::Fx1" << endl; }
virtual void
__stdcall Fx2() { cout << "CA::Fx2" << endl; }
// Реализация
интерфейса IY
virtual void
__stdcall Fy1() { cout << "CA::Fy1" << endl; }
virtual void
__stdcall Fy2() { cout << "CA::Fy2" << endl; }
};
// Клиент
int main()
{
trace("Client:
Sozdanie ekzemplyra komponenta");
CA* pA = new CA;
// Получить указатель IX
IX* pIX = pA;
trace("Client:
Ispol'zovanie interface IX");
pIX->Fx1();
pIX->Fx2();
// Получить указатель IY
IY* pIY = pA;
trace("Client:
Ispol'zovanie interface IY");
pIY->Fy1();
pIY->Fy2();
trace("Client:
Delete komponent");
delete pA;
getch();
return 0; }
Результат работы
программы:
Вывод:
В данном
задании мы реализововали простой интерфейс СОМ без динамической компоновки. Интерфейсы
COM реализованы как чисто абстрактные базовые классы С++, в качестве клиента
использовали процедуру main.
Цель
работы:
1.
Объявить
интерфейсы IX, IY, IZ . Объявить интерфейс IUnknown.
2.
Реализация
компонента. Класс СА реализует компонент, поддерживающий интерфейсы IX и IY. Реализовать QueryInterface описанным выше способом.
Функцию CreateInstance определить после класса CA. Клиент использует ее,
чтобы создать компонент, представляемый при помощи СА, и получить указатель на IUnknown этого компонента. После CreateInstance определить IID для интерфейсов. (Для
того, чтобы определить IID для IUnknown компоновать с UUID.LIB).
3.
Реализация
клиента, роль которого выполняет main. Клиент начинает с создания компонента при
помощи CreateInstance. CreateInstance возвращает указатель на интерфейс IUnknown компонента. Клиент при
помощи QueryInterface запрашивает через интерфейс IUnknown указатель на интерфейс IX компонента. Анологично
запросить и IY. Использовать эти указатели для доступа к функциям-членам.
Запросить интерфейс IZ. QueryInterface возвращает код ошибки, так как СА не реализует IZ. Далее Клиент
запрашивает указатель на интерфейс IY через указатель на интерфейс IX, pIX. Поскольку компонент
поддерживает IY, этот запрос будет успешным, и клиент сможет использовать
возвращенный указатель на интерфейс IY так же, как он использовал первый указатель.
Затем клиент запрашивает интерфейс IUnknown через указатель на IY. Поскольку все
интерфейсы COM наследуют IUnknown, этот запрос должен быть успешным, причем
возвращенный указатель совпадет с первым указателем, так как . QueryInterface возвращает один и тот же
указатель на все запросы к IUnknown.
Теоретические сведения:
В COM клиент взаимодействует с
компонентом с помощью интерфейса
IUnknown, который определен в
заголовочном файле UNKWN.H:
Interface
IUnknown
{
virtual
HREZULT --stdcall QueryInterface( const IID&iid,
void
* * ppv) = 0 ;
virtual
ULONG --stdcall Addref( ) = 0 ;
virtual ULONG --stdcall
Release( ) = 0 ;
};
Функцию с
именем QueryInterface клиент вызывает, чтобы определить, поддерживает ли компонент
некоторый интерфейс. У функции QueryInterface два параметра. Первый
параметр – идентификатор интерфейса. Второй параметр - адрес, по которому QueryInterface помещает указатель на
искомый интерфейс.
QueryInterface возвращает HREZULT – 32-разрядный код
результата.
QueryInterface может возвратить либо S_OK, либо E_NOINTERFACE. Клиент не должен прямо
сравнивать возвращаемое QueryInterface значение с этими константами; для проверки надо
использовать макросы SUCCEEDED или FAILED.
Получение указателя на IUnknown
Для получения
указателя на IUnknown использовать функцию, например, CreateInstance которая создает
компонент и возвращает указатель на IUnknown:
IUnknown *
CreateInstance( )
Реализация
функции CreateInstance:
IUnknown * pI
= static_cast<IX*>(new CA) ;
PI->Addref(
) ;
Return pI ;
Использование QueryInterface.
Предположим,
что у нас есть указатель на IUnknown, pI. Чтобы определить, можно ли использовать
некоторый другой интерфейс, мы вызываем QueryInterface, передавая ей
идентификатор нужного нам интерфейса. Если QueryInterface отработала успешно, мы
можем пользоваться указателем:
void foo(IUnknown* pI)
{
// Определить указатель
на интерфейс
IX* pIX=NULL;
// Запросить интерфейс IX
HREZULT hr = pI-> QueryInterface(IID_IX, (void**)&pIX) ;
// Проверить значение
результата
if (SUCCEEDED(hr))
{
// Использовать интерфейс
pIXFx( ) ;
}
}
Реализация QueryInterface.
Запишем QueryInterface для следующего
компонента, реализуемого классом CA:
Interface IX :
IUnknown { /*…*/ } ;
Interface IY :
IUnknown { /*…*/ } ;
Class CA : public
IX, public IY { /*…*/ } ;
Следующий фрагмент кода
реализует QueryInterface для класса, приведенного выше фрагмента кода.
HREZULT --stdcall
CA:: QueryInterface( const IID&iid, void * * ppv);
{
if (iid
==IID_IUnknown)
{
// Клиент
запрашивает интерфейс IUnknown
*ppv =
static_cast<IX*>(this) ;
}
else if (iid
==IID_IX)
{
// Клиент запрашивает
интерфейс IX
*ppv = static_cast<IX*>(this) ;
}
else if (iid
==IID_IY)
{
// Клиент
запрашивает интерфейс IY
*ppv =
static_cast<IY*>(this) ;
}
else
{
// Мы не поддерживаем
запрашиваемый клиентом интерфейс.
// Установить возвращаемый
указатель в NULL.
*ppv = NULL ;
return
E_NOINTERFACE ;
}
static_cast<
IUnknown*>(*ppv)->AddRef( ) ;
return S_OK ;
}
Текст программы:
#include
"stdafx.h"
#include
"iostream.h"
#include
"objbase.h"
#include
"conio.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;
//
// Компонент
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:
Vernyt' ykazatel' na IUnknown");
*ppv =
static_cast<IX*>(this);
}
else if (iid
== IID_IX)
{
trace("QueryInterface:
Vernyt' ykazatel' na IX");
*ppv =
static_cast<IX*>(this);
}
else if (iid
== IID_IY)
{
trace("QueryInterface:
Vernyt' ykazatel' na IY");
*ppv =
static_cast<IY*>(this);
}
else
{
trace("QueryInterface:
Interface No!");
*ppv = NULL;
return
E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
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,
{0xa6, 0xbb,
0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};
// Клиент
int main()
{
HRESULT hr;
trace("Client:
Polychit' ykazatel' na IUnknown");
IUnknown*
pIUnknown = CreateInstance();
trace("Client:
Polychit' ykazatel' na IX");
IX* pIX =
NULL;
hr =
pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if
(SUCCEEDED(hr))
{
trace("Client:
IX polychen");
pIX->Fx(); //
Использовать интерфейс IX
}
trace("Client:
Polychit' ykazatel na IY");
IY* pIY =
NULL;
hr =
pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if
(SUCCEEDED(hr))
{
trace("Client:
IY polychen");
pIY->Fy(); //
Использовать интерфейс IY
}
trace("Client:
Zaprosit' nepodderjivaemuy interface");
IZ* pIZ =
NULL;
hr =
pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ);
if
(SUCCEEDED(hr))
{
trace("Client:
Interface IZ polychen");
pIZ->Fz();
}
else
{
trace("Client:
No Interface IZ");
}
trace("Client:
Polychit' Interface IY cherez Interface IX");
IY* pIYfromIX
= NULL;
hr =
pIX->QueryInterface(IID_IY, (void**)&pIYfromIX);
if
(SUCCEEDED(hr))
{
trace("Client:
IY polychen");
pIYfromIX->Fy();
}
trace("Client:
Polechit' Interface IUnknown cherez IY");
IUnknown*
pIUnknownFromIY = NULL;
hr =
pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY);
if
(SUCCEEDED(hr))
{
cout <<
"Sovpadaut li ykazateli na IUnknown? ";
if
(pIUnknownFromIY == pIUnknown)
{
cout <<
"Yes, pIUnknownFromIY == pIUnknown" << endl;
}
else
{
cout <<
"No, pIUnknownFromIY != pIUnknown" << endl;
}
}
// Удалить компонент
delete
pIUnknown;
getch();
return 0;
}
Результат работы
программы:
Вывод:
В данном
задании объявили интерфейсы IX, IY, IZ, и интерфейс IUnknown.
Реализовали
компонент. Класс СА который реализует компонент, поддерживающий интерфейсы IX и IY. Реализовали QueryInterface. Функцию CreateInstance, которая определяется после
класса CA. Клиент использует ее, чтобы создать компонент, представляемый
при помощи СА, и получили указатель на IUnknown этого компонента.
Цель
работы:
Добавить к
предыдущей программе из лабороторной работы №1А подсчет ссылок. Для этого к
компоненту добавить реализации двух методов IUnknown – AddRef и Release.используя функции Win32 InterlockedIncrement и InterlockedDecrement. Функцию AddRef вызывают CreateInstance и QueryInterface для соответствующих
указателей на интерфейсы. Вызовы Release добавить в клиенте, чтобы обозначить окончание
работы с различными интерфейсами.
Ликвидировать
компонент с помощью деструктора.
Теоретические сведения:
Вместо того, чтобы удалять компоненты напрямую, мы будем сообщать
компоненту, что нам нужен интерфейс или что мы закончили с ним работать. Мы
точно знаем, когда начинаем использовать интерфейс, и знаем (обычно), когда
перестаем его использовать. Однако, как уже ясно, мы можем не знать, что
закончили использовать компонент вообще. Поэтому имеет смысл ограничиться
сообщением об окончании работы с данным интерфейсом — и пусть компонент сам
отслеживает, когда мы перестаем пользоваться всеми интерфейсами.
Именно для реализации этой стратегии и предназначены еще две
функции-члена IUnknown — AddRef и Release.
определение интерфейса IUnknown:
interface IUnknown
{
virtual HRESULT __stdcall QueryInterface(const IID& iid,
void** ppv) = 0;
virtual ULONG __stdcall AddRef() = 0;
virtual
ULONG __stdcall Release() = 0;
};
AddRef и Release реализуют и технику
управления памятью, известную как подсчет ссылок (reference counting).
Подсчет ссылок — простой и быстрый способ, позволяющий компонентам
самим удалять себя. Компонент СОМ поддерживает счетчик ссылок. Когда клиент
получает некоторый интерфейс, значение этого счетчика увеличивается на единицу.
Когда клиент заканчивает работу с интерфейсом, значение на единицу уменьшается.
Когда оно доходит до нуля, компонент удаляет себя из памяти. Клиент также
увеличивает счетчик ссылок, когда создает новую ссылку на уже имеющийся у него
интерфейс. Как Вы, вероятно, догадались, увеличивается счетчик вызовом AddRef, а уменьшается — вызовом
Release.
Для того, чтобы пользоваться подсчетом ссылок, необходимо знать
лишь три простых правила:
1. Вызывайте AddRef перед возвратом. Функции, возвращающие
интерфейсы, перед возвратом всегда
должны вызывать AddRef для соответствующего указателя. Это также
относится к QueryInterface и функции CreateInstance. Таким образом, Вам не нужно вызывать AddRef в своей программе после получения
(от функции) указателя на интерфейс.
2. По завершении работы вызывайте Release. Когда Вы закончили работу
с интерфейсом, следует вызвать для него Release.
3. Вызывайте AddRef после присваивания. Когда бы Вы ни
присваивали один указатель на интерфейс другому, вызывайте AddRef. Иными словами: следует
увеличить счетчик ссылок каждый раз, когда создается новая ссылка на данный
интерфейс.
Приведенный
ниже фрагмент кода создает компонент и получает указатель на интерфейс IX. Мы не вызываем AddRef, так как за нас это
делают CreateInstance и QueryInterface. Однако мы вызываем Release как для интерфейса IUnknown, возвращенного CreateInstance, так и для интерфейса IX, возвращенного QueryInterface.
//
Создать компонент
IUnknown*
pIUnknown = CreateInstance();
// Получить
интерфейс IX
IX* pIX = NULL;
HRESULT
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if
(SUCCEEDED(hr))
{
pIX->Fx();
// Использовать интерфейс IX
pIX->Release(); // Завершить работу с
IX
}
pIUnknown->Release(); // Завершить работу с
Iunknown
QueryInterface, так что его можно
освободить раньше.
//
Создать компонент
IUnknown*
pIUnknown = CreateInstance();
// Получить
интерфейс IX
IX* pIX = NULL;
HRESULT
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
// Завершить
работу с IUnknown
pIUnknown->Release();
//
Использовать IX, если он был получен успешно
if (SUCCEEDED(hr))
{
pIX->Fx(); // Использовать
интерфейс IX
pIX->Release(); // Завершить работу с
IX
}
Легко забыть, что всякий раз, когда Вы копируете указатель на
интерфейс, надо увеличить его счетчик ссылок. В приведенном далее фрагменте
кода делается еще одна ссылка на интерфейс IX. В общем случае
необходимо увеличивать счетчик ссылок всякий раз, когда создается копия
указателя на интерфейс, о чем говорит приведенное выше правило 3.
//
Создать компонент
IUnknown*
pIUnknown = CreateInstance();
IX*
pIX = NULL;
HRESULT
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
pIUnknown->Release();
if
(SUCCEEDED(hr))
{
pIX->Fx(); // Использовать
интерфейс IX
IX* pIX2 = pIX; // Создать копию pIX
pIX2->AddRef(); // Увеличить счетчик
ссылок
pIX2->Fx(); // Что-то делать при
помощи pIX2
pIX2->Release(); // Завершить работу с
pIX2
pIX->Release(); // Завершить работу с
pIX
}
Клиент сообщает компоненту о своем желании использовать интерфейс,
когда вызывается
QueryInterface. QueryInterface вызывает AddRef для запрашиваемого
интерфейса. Когда клиент заканчивает работу с интерфейсом, он вызывает для
этого интерфейса Release. Компонент остается в памяти, ожидая, пока счетчик ссылок не
станет равен 0. Когда счетчик становится нулем, компонент сам себя удаляет.
Текст программы:
#include
"stdafx.h"
#include
"iostream.h"
#include
"objbase.h"
#include
"conio.h"
void
trace(const char* msg) { cout << msg << endl; }
// Предварительные
описания GUID
extern const IID IID_IX;
extern const
IID IID_IY;
extern const
IID IID_IZ;
// Интерфейсы
interface IX :
IUnknown
{
virtual void
__stdcall Fx() = 0;
};
interface IY :
IUnknown
{
virtual void
__stdcall Fy() = 0;
};
interface IZ :
IUnknown
{
virtual void
__stdcall Fz() = 0;
};
// Компонент
class CA :
public IX, public IY
{
// Реализация
IUnknown
virtual
HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG
__stdcall AddRef();
virtual ULONG
__stdcall Release();
// Реализация
интерфейса IX
virtual void
__stdcall Fx() { cout << "Fx" << endl; }
// Реализация
интерфейса IY
virtual void
__stdcall Fy() { cout << "Fy" << endl; }
public:
// Конструктор
CA() : m_cRef(0) {}
// Деструктор
~CA() {
trace("CA: Likvidirovat' seby"); }
private:
long m_cRef;
};
HRESULT
__stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
if (iid ==
IID_IUnknown)
{
trace("CA
QI: Vozvratit' ykazateel na IUnknown");
*ppv =
static_cast<IX*>(this);
}
else if (iid
== IID_IX)
{
trace("CA
QI: Vozvratit' ykazateel na IX");
*ppv =
static_cast<IX*>(this);
}
else if (iid
== IID_IY)
{
trace("CA
QI:Vozvratit' ykazateel na IY");
*ppv =
static_cast<IY*>(this);
}
else
{
trace("CA
QI: Interface No!");
*ppv = NULL;
return
E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
ULONG
__stdcall CA::AddRef()
{
cout <<
"CA: AddRef = " << m_cRef+1 << endl;
return
InterlockedIncrement(&m_cRef);
}
ULONG
__stdcall CA::Release()
{
cout <<
"CA: Release = " << m_cRef-1 << endl;
if
(InterlockedDecrement(&m_cRef) == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//
// Функция
создания
//
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,
{0xa6, 0xbb,
0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};
//
// Клиент
//
int main()
{
HRESULT hr;
trace("Client:
Polychit' ykazatel IUnknown");
IUnknown*
pIUnknown = CreateInstance();
trace("Client:
Polychit' Interface IX");
IX* pIX =
NULL;
hr =
pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if
(SUCCEEDED(hr))
{
trace("Client:
IX polychen");
pIX->Fx(); // Использовать интерфейс
IX
pIX->Release();
}
trace("Client:
Polychit' Interface IY");
IY* pIY =
NULL;
hr =
pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if
(SUCCEEDED(hr))
{
trace("Client:
IY polychen");
pIY->Fy(); // Использовать
интерфейс IY
pIY->Release();
}
trace("Client:
Zaprosit' nepodderjivaemue Interface");
IZ* pIZ =
NULL;
hr =
pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ);
if
(SUCCEEDED(hr))
{
trace("Client:
Interface IZ polychen");
pIZ->Fz();
pIZ->Release();
}
else
{
trace("Client:
No! Interface IZ");
}
trace("Client:
Osvobodit' Interface IUnknown");
pIUnknown->Release();
getch();
return 0;
}
Результат работы
программы:
Вывод:
В этом
задании мы добавили подсчет ссылок. Для этого к компоненту добавили реализацию
двух методов IUnknown – AddRef и Release, используя функции Win32 InterlockedIncrement и InterlockedDecrement. Функцию AddRef вызывают CreateInstance и QueryInterface для соответствующих
указателей на интерфейсы. Вызовы Release добавили в клиенте, чтобы обозначить окончание
работы с различными интерфейсами. Ликвидировали компонент с помощью деструктора.