Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 8
На сайте нет зарегистрированных пользователей

Пользователей: 13,372
новичок: vausoz
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

База данных - рабочее место кассира на Delphi + бд Access
База данных междугородних телефонных разговоров на Delphi
Моделирование процесса обработки заданий на вычислительном центре на GP...

Двоичная композиция



Композиция и отделяемые интерфейсы – это две технологии на уровне исходного кода, предназначенные для реализации объектов СОМ на C++. Обе эти технологии требуют, чтобы разработчик объекта имел определения для каждого класса композита или отделяемого интерфейса в исходном коде C++, для возможности обработать подобъект, прежде чем возвратить его посредством QueryInterface . Для ряда ситуаций это очень разумно. В некоторых случаях, однако, было бы удобнее упаковать многократно используемую реализацию одного или большего числа интерфейсов в двоичный компонент, который мог бы обрабатываться через границы DLL, не нуждаясь в исходном коде подкомпонента. Это позволило бы более широкой аудитории повторно использовать подкомпонент, избегая слишком тесной связи с ним, как в случае повторного использования на уровне исходного кода (этот случай описан в главе 1). Однако если компонент повторного использования представляет собой двоичный композит или отделяемый интерфейс, то он должен участвовать в общей идентификации объекта.
Для полного охвата проблем, относящихся к унифицированию идентификации через границы компонентов, рассмотрим следующую простую реализацию ICar :
class Car : public ICar
{
LONG m_cRef; Car(void) : m_cRef(0) {} STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP GetMaxSpeed(long *pn);
STDMETHODIMP Brake(void); };
STDMETHODIMP Car::QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown) *ppv = static_cast(this);
else if (riid == IID_IVehicle) *ppv = static_cast(this);
else if (riid == IID_ICar) *ppv = static_cast(this);
else return (*ppv = 0), E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
// car class object's IClassFactory::CreateInstance
// интерфейс IClassFactory::CreateInstance
// объекта класса car
STDMETHODIMP CarClass::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
{
Car *pCar = new Car;
if (*pCar) return (*ppv = 0), E_OUTOFMEMORY;
pCar->AddRef();
HRESULT hr = pCar->QueryInterface(riid, ppv);
pCar->Release(); return hr;
}



Этот класс просто использует фактические реализации QueryInterface , AddRef и Release .
Рассмотрим второй класс C++, который пытается использовать реализацию Car как двоичный композит:
class CarBoat : public IBoat
{
LONG m_cRef;
Unknown *m_pUnkCar;
CarBoat(void);
virtual ~CarBoat(void);
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP GetMaxSpeed(long *pn);
STDMETHODIMP Sink(void);
};



Для эмуляции композиции разработчику пришлось бы создать подобъект Car , а деструктору – освободить указатель на подобъект:
CarBoat::CarBoat (void) : m_cRef(0)
{
HRESULT hr = CoCreateInstance(CLSID_Car, 0, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar);
assert(SUCCEEDED(hr));
}
CarBoat::~CarBoat(void)
{
if (m_pUnkCar) m_pUnkCar->Release();
}
Интересная проблема возникает в реализации QueryInterface :
STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown) *ppv = static_cast(this);
else if (riid == IID_IVehicle) *ppv = static_cast(this);
else if (riid == IID_IBoat) *ppv = static_cast(this);
else if (riid == IID_ICar)
// forward request…
// переадресовываем запрос…
return m_pUnkCar->QueryInterface(riid, ppv);
else return (*ppv = 0), E_NOINTERFACE; ((IUnknown*)*ppv)->AddRef();
return S_OK;
}



Поскольку объект Car не имеет понятия о том, что он является частью идентификационной единицы ( identity ) другого объекта, то он будет причиной неуспеха любых запросов QueryInterface для IBoat . Это означает, что
QI(IBoat)->ICar



пройдет успешно, а запрос
QI(QI(IBoat)->ICar)->IBoat



потерпит неудачу, так как полученная QueryInterface будет несимметричной. Вдобавок запросы QueryInterface о IUnknown через интерфейсные указатели ICar и IBoat вернут различные значения, а это означает, что будет идентифицировано два различных объекта. Из подобных нарушений протокола IUnknown следует, что объекты CarBoat попросту не являются действительными объектами СОМ.
Идея составления объекта из двоичных композитов звучит красиво. Действительно, Спецификация СОМ четко и подробно указывает, как реализовать эту идею в стандартной и предсказуемой манере. Технология выставления клиенту двоичного подкомпонента непосредственно через QueryInterface называется СОМ-агрегированием . СОМ-агрегирование является лишь набором правил, определяющих отношения между внешним объектом (агрегирующим) и внутренним (агрегируемым). СОМ-агрегирование – это просто набор правил IUnknown , позволяющих более чем одному двоичному компоненту фигурировать в качестве идентификационной единицы ( identity ) СОМ.
Агрегирование СОМ несомненно является главной движущей силой для повторного использования в СОМ. Намного проще приписывать объекту значения и использовать его методы в реализации методов других объектов. Только в редких случаях кто-то захочет выставлять интерфейсы другого объекта непосредственно клиенту как часть той же самой идентификационной единицы. Рассмотрим следующий сценарий:
class Handlebar : public IHandlebar { … };
class Wheel : public IWheel {};
class Bicycle : public IBicycle
{
IHandlebar * m_pHandlebar;
IWheel *m_pFrontWheel;
IWheel *m_pBackWheel;
}



Было бы опрометчиво для класса Вicycle объявлять интерфейсы IHandlebar (велосипедный руль) или IWheel (колесо) в собственном методе QueryInterface . QueryInterface зарезервирован для выражения отношений «является» (is-a), а велосипед (bicycle) очевидно не является колесом (wheel) или рулем (handlebar). Если разработчик Bicycle хотел бы обеспечить прямой доступ к этим сторонам объекта, то интерфейс IBicycle должен был бы иметь для этой цели аксессоры определенных свойств:
[object, uuid(753A8A60-A7FF-11d0-8C30-0080C73925BA)] interface IBicycle : IVehicle
{
HRESULT GetHandlebar([out,retval] IHandlebar **pph);
HRESULT GetWheels([out] IWheel **ppwFront, [out] IWheel **ppwBack);
}



Реализация Bicycle могла бы тогда просто возвращать указатели на свои подобъекты:
STDMETHODIMP Bicycle::GetHandlebar(IHandlebar **pph)
{
if (*pph = m_pHandlebar) (*pph)->AddRef();
return S_OK;
}
STDMETHODIMP Bicycle::GetWheels(IWheel **ppwFront, IWheel **ppwBack)
{
if (*ppwFront = m_pFrontWheel) (*ppwFront)->AddRef();
if (*ppwBack = m_pBackWheel) (*ppwBack)->AddRef();
return S_OK;
}



При использовании данной технологии клиент по-прежнему получает прямой доступ к подобъектам. Однако поскольку указатели получены через явные методы, а не через QueryInterface , то между различными компонентами не существует никаких идентификационных отношений.
Несмотря на этот пример, все же остаются сценарии, где желательно обеспечить реализацию интерфейса, которая могла бы быть внедрена в идентификационную единицу другого объекта. Чтобы осуществить это, в СОМ-агрегировании требуется, чтобы внутренний объект (агрегируемый) уведомлялся во время его создания, что он создается как часть идентификационной единицы другого объекта. Это означает, что создающая функция (creation function), обычно используемая для создания объекта, требует один дополнительный параметр: указатель IUnknown на идентификационную единицу, которой агрегирующий объект должен передать функции в ее методы QueryInterface , AddRef и Release . Покажем определение метода CreateInstance интерфейса IClassFactory :
HRESULT CreateInstance([in] Unknown *pUnkOuter, [in] REFIID riid, [out, iid_is(riid)] void **ppv);



Этот метод (и соответствующие API-функции CoCreateInstanceEx и CoCreateInstance ) перегружен с целью поддержки создания автономных ( stand-alone ) объектов и агрегатов. Если вызывающий объект передает нулевой указатель и качестве первого параметра CreateInstance ( pUnkOuter ), то результирующий объект будет автономной идентификационной единицей самого себя. Если же вызывающий объект передает в качестве первого параметра ненулевой указатель, то результирующий объект будет агрегатом с идентификационной единицей, ссылка на которую содержится в pUnkOuter . В случае агрегации агрегат должен переадресовывать все запросы QueryInterface , AddRef и Release непосредственно и безусловно на pUnkOuter . Это необходимо для обеспечения идентификации объекта.
Имея прототип функции, приведенный выше, класс CarBoat после небольшой модификации будет удовлетворять правилам агрегации:
CarBoat::CarBoat(void) : m_cRef(0)
{
// need to pass identity of self to Create routine
// to notify car object it 1s an aggregate
// нужно передать свою идентификацию подпрограмме
// Create для уведомления объекта car, что он – агрегат
HRESULT hr = CoCreateInstance(CLSID_Car, this, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkCar);
assert(SUCCEEDED(hr));
}



Реализация CarBoat QueryInterface просто переадресовывает запрос ICar внутреннему агрегату:
STDMETHODIMP CarBoat::QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown) *ppv = static_cast(this);
else if (riid == IID_ICar)
// forward request…
// переадресовываем запрос…
return m_pUnkCar->QueryInterface(riid, ppv);
else if (riid == IID_IBoat)
:
:
:



Теоретически это должно работать, так как агрегат будет всегда переадресовывать любые последующие запросы QueryInterface обратно главному объекту, проводя таким образом идентификацию объекта.
В предыдущем сценарии метод CreateInstance класса Car возвращает внешнему объекту указатель интерфейса, наследующего IUnknown . Если бы этот интерфейсный указатель должен был просто делегировать вызовы функций интерфейсу IUnknown внешнего объекта, то невозможно было бы: 1) уведомить агрегат, что он больше не нужен; 2) запросить интерфейсные указатели при выделении их клиентам главного объекта. На деле результатом приведенной выше реализации QueryInterface будет бесконечный цикл, поскольку внешний объект делегирует функции внутреннему, который делегирует их обратно внешнему.
Для решения этой проблемы необходимо сделать так, чтобы начальный интерфейсный указатель, который возвращается внешнему объекту, не делегировал вызовы реализации IUnknown внешнего объекта. Это означает, что объекты, поддерживающие СОМ– агрегирование, должны иметь две реализации IUnknown . Делегирующая, то есть передающая функции, реализация переадресовывает все запросы QueryInterface , AddRef и Release внешней реализации. Это и есть реализация по умолчанию, на которую ссылаются таблицы vtbl всех объектов, и это именно та версия, которую видят внешние клиенты. Объект должен также иметь неделегирующую реализацию IUnknown , которая выставляется только агрегирующему внешнему объекту.
Имеется несколько возможностей обеспечить две различные реализации IUnknown от одного объекта. Самый прямой путь [1] – это использование композиции и элемента данных для реализации неделегирующих методов IUnknown . Ниже показана реализация Car , поддающаяся агрегации:
Опубликовал Kest July 13 2009 10:33:52 · 0 Комментариев · 8435 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Страница 1 из 2 1 2 >
Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
TrayIcon
WordReport
Упорядоченный дин...
PHP 5 в подлинник...
Delphi на примерах
Проигрыватель Mp3
Error mod
Allsubmitter 4.7 ...
Форма в форме
SODA [Исходник на...
Панель случайной ...
Аватары в комме...
Сложный калькулятор
Доступа к БД Fire...
PBEditPack
Формирование отче...
AUTOWEB
SearchAndReplace
Billenium Effects...
XPATComponents

Топ загрузок
Приложение Клие... 100800
Delphi 7 Enterp... 98063
Converter AMR<-... 20302
GPSS World Stud... 17067
Borland C++Buil... 14261
Borland Delphi ... 10388
Turbo Pascal fo... 7398
Калькулятор [Ис... 6093
Visual Studio 2... 5241
Microsoft SQL S... 3676
Случайные статьи
Прикольные фотогра...
Скорость передачи ...
Обсуждение структу...
Воспроизведение ме...
PM Casino онлайн
При строгом соблюд...
Поднятие тИЦ и PR
Особенности команд...
Краткое введение в...
Выpазить чеpез K и...
Добавить объект P...
Запись видео на ф...
Процедура Ellipse ...
Процедуры обработк...
Каждый DNS-сервер ...
ИЗМЕНЕНИЕ МАРШРУТО...
Поиск с помощью яз...
Комбинации клавиш
Windows 2000
Символы и специаль...
Особенности слота ...
Pointer variable e...
Коммутация блоков ...
Интервалы между сл...
Стандарт POSIX
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?