Смекни!
smekni.com

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

Содержание

 

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

virtualvoid Fx1() = 0;

virtualvoid Fx2() = 0;

};

classIY // Второй интерфейс

{

public:

virtualvoid Fy1() = 0;

virtualvoid Fy2() = 0;

};

classCA : public IX, public IY // Компонент

{

public:

// Реализацияабстрактного базового класса IX

virtualvoid Fx1() { cout << “Fx1” << endl; }

virtualvoid Fx2() { cout << “Fx2” << endl; }

//Реализация абстрактного базового класса IY

virtualvoid Fy1() { cout << “Fy1” << endl; }

virtualvoid 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"

voidtrace(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.

Задание2 №1А QueryInterface

Цельработы:

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:

InterfaceIUnknown

{

virtualHREZULT --stdcall QueryInterface( const IID&iid,

void* * ppv) = 0 ;

virtualULONG --stdcall Addref( ) = 0 ;

virtual ULONG --stdcallRelease( ) = 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 : publicIX, public IY { /*…*/ } ;

Следующий фрагмент кодареализует QueryInterface для класса, приведенного выше фрагмента кода.

HREZULT --stdcallCA:: 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 ;

returnE_NOINTERFACE ;

}

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

return S_OK ;

}

 

Текст программы:

#include"stdafx.h"

#include"iostream.h"

#include"objbase.h"

#include"conio.h"

voidtrace(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 constIID IID_IY;

extern constIID IID_IZ;

//

// Компонент

class CA :public IX, public IY

{

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

virtualHRESULT __stdcall QueryInterface(const IID& iid, void** ppv);