Смекни!
smekni.com

Распределенная обработка данных (стр. 2 из 3)

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;

returnE_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 constIID IID_IX =

{0x32bb8320,0xb41b, 0x11cf,

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

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

static constIID IID_IY =

{0x32bb8321,0xb41b, 0x11cf,

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

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

static constIID 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;

}

}

// Удалить компонент

deletepIUnknown;

getch();

return 0;

}

 

Результат работыпрограммы:


Вывод:

 

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

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

Задание№1B Подсчетссылок

 

Цельработы:

Добавить кпредыдущей программе из лабороторной работы №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;

virtualULONG __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;

HRESULThr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);

if(SUCCEEDED(hr))

{

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

pIX->Release(); // Завершить работу сIX

}

pIUnknown->Release(); // Завершить работу сIunknown

В приведенном выше примере мы фактически закончили работать с IUnknown сразу же после вызова

QueryInterface, так что его можноосвободить раньше.

//Создать компонент

IUnknown*pIUnknown = CreateInstance();

// Получитьинтерфейс IX

IX* pIX = NULL;

HRESULThr = 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;

HRESULThr = 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"

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

// Предварительныеописания GUID

extern const IID IID_IX;

extern constIID IID_IY;

extern constIID 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

virtualHRESULT __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("CAQI: Vozvratit' ykazateel na IUnknown");

*ppv =static_cast<IX*>(this);

}

else if (iid== IID_IX)

{

trace("CAQI: Vozvratit' ykazateel na IX");

*ppv =static_cast<IX*>(this);

}

else if (iid== IID_IY)

{

trace("CAQI:Vozvratit' ykazateel na IY");

*ppv =static_cast<IY*>(this);

}

else

{

trace("CAQI: Interface No!");

*ppv = NULL;

returnE_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef();

return S_OK;

}

ULONG__stdcall CA::AddRef()

{

cout <<"CA: AddRef = " << m_cRef+1 << endl;

returnInterlockedIncrement(&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 constIID IID_IX =

{0x32bb8320,0xb41b, 0x11cf,

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

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

static constIID IID_IY =

{0x32bb8321,0xb41b, 0x11cf,

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

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

static constIID IID_IZ =

{0x32bb8322,0xb41b, 0x11cf,

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

//

// Клиент

//

int main()

{

HRESULT hr;

trace("Client:Polychit' ykazatel IUnknown");