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 этого компонента.

Задание №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;

virtual ULONG __stdcall Release() = 0;

};

AddRef и Release реализуют и технику управления памятью, известную как подсчет ссылок (reference counting).

Подсчет ссылок — простой и быстрый способ, позволяющий компонентам самим удалять себя. Компонент СОМ поддерживает счетчик ссылок. Когда клиент получает некоторый интерфейс, значение этого счетчика увеличивается на единицу. Когда клиент заканчивает работу с интерфейсом, значение на единицу уменьшается. Когда оно доходит до нуля, компонент удаляет себя из памяти. Клиент также увеличивает счетчик ссылок, когда создает новую ссылку на уже имеющийся у него интерфейс. Как Вы, вероятно, догадались, увеличивается счетчик вызовом AddRef, а уменьшается — вызовом Release.

Для того, чтобы пользоваться подсчетом ссылок, необходимо знать лишь три простых правила:

1. Вызывайте AddRef перед возвратом. Функции, возвращающие интерфейсы, перед возвратом всегда

должны вызывать AddRef для соответствующего указателя. Это также относится к QueryInterface и функции CreateInstance. Таким образом, Вам не нужно вызывать AddRef в своей программе после получения (от функции) указателя на интерфейс.


Информация о работе «Распределенная обработка данных»
Раздел: Информатика, программирование
Количество знаков с пробелами: 22503
Количество таблиц: 0
Количество изображений: 3

Похожие работы

Скачать
28863
0
0

... ЭВМ. Особенностью этого способа является отделение технологически и по времени процедуры обработки от процедур сбора, подготовки и ввода данных.   1.3 Комплекс технических средств обработки информации Комплекс технических средств обработки информации – это совокупность автономных устройств сбора, накопления, передачи, обработки и представления информации, а также средств оргтехники, управления ...

Скачать
192976
8
10

... в пенсионный фонд (1% от зарплаты) 1345 Затраты на эксплуатацию оборудования (амортизацию) 976000 ИТОГО: 1207213 Заключение За время работы над дипломным проектом по теме «Организация удаленного доступа к распределенным базам данных» были изучены теоретические основы построения распределенных информационных систем с возможностью оперативного удаленного доступа к данным. ...

Скачать
26696
11
0

... мобильности означает сравнительную простоту переноса программной системы в широком спектре аппаратно-программных средств, соответствующих стандартам. Интероперабельность означает упрощения комплексирования новых программных систем на основе использования готовых компонентов со стандартными интерфейсами. Преимуществом для пользователей является то, что они могут постепенно заменять компоненты ...

Скачать
158931
0
1

... дискретного программирование для решения задач проектирование систем обработки данных. -  Сформулированы задачи диссертационного исследования. 2. БЛОЧНО-СИММЕТРИЧНЫЕ МОДЕЛИ И МЕТОДЫ ПРОЕКТИРОВАНИЯ СИСТЕМ ОБРАБОТКИ ДАННЫХ В данном разделе рассматриваются общая постановка блочно-симметричной задачи дискретного программирования, её особенности и свойства. Разработан общий подход решения задач ...

0 комментариев


Наверх