Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Последовательность действий при вызове клиентом локального или удаленного сервера




 

Связь COM между клиентским процессом и внепроцессным компонентом (локальным или удаленным сервером) является более сложной, чем связь с внутрипроцессным компонентом. Компонент ЕХЕ является отдельным процессом, возможно на другом компьютере. Тем не менее, разработка программы выглядит так, как будто прямая связь клиента с компонентом сцществует. COM заботится о деталях взаимодействия, которое обычно включает RPC.

Посредством RPC клиент делает вызовы специальной DLL, называемой заместителем (proxy). Заместитель посылает поток данных заглушке (stub), которая находится в DLL в процессе компонента. Когда клиент вызывает функцию компонента, заместитель связывается с заглушкой, отправив ей сообщение, которое обрабатывается скрытым окном. Механизм преобразования параметров, пересылаемых между заместителем и заглушкой в одну и другую сторону называют маршаллингом.

Если вы используете стандартные интерфейсы (те, что определены Microsoft), такие как IClassFactory и IPersist, код заместителя и заглушки, которые реализуют маршалинг, предоставляются библиотекой Oleaut32.dll. Если вы разрабатываете свои собственные интерфейсы, вы должны сами написать заместители и заглушки. К счастью, их создание сводится к определению ваших интерфейсов на языке IDL (Interface Definition Language) и компиляции кода с помощью  MIDL (Microsoft Interface Definition Language) компилятора.

Приведем псевдокод, который описывает взаимодействие между ЕХЕ клиентом и ЕХЕ компонетом. Сравните его с предыдущей версией с DLL компонентом. Заметьте, что код клиента остался прежним.

Клиент                        CLSID clsid;

                                     IClassFactory* pClf;

                                     IUnknown* pUnk;

                                     CoInitialize(NULL); // инициализация COM

                                     CLSIDFromProgID("имя_компонента", &clsid);

 

COM                            COM отыскивает в реестре идентификатор класса clsid по 

                                     "имя_компонента"

Клиент                        CoGetClassObject(clsid, CLSCTX_ LOCAL_SERVER, NULL,

                                     IID_IClassFactory, (void**) &pClf );

 

COM                            COM использует clsid для поиска компонента в памяти

                                     if (компонент ЕХЕ еще не загружен или требуется его другой

экземпляр)

                                     {

                                     COM получает имя файла с ЕХЕ компонентом из реестра.

                                 COM загружает полученный файл.

                                     }

ЕХЕ компонент        if (компонент только что загружен)

{

                                     Создаются объекты фабрика классов.

                                     Вызывается функция InitInstance (только для MFC)

CoInitialize(NULL);

                                     Для каждого объекта фабрики классов

{

CoRegisterClassObject(...);       

                                     Возвращается IClassFactory*

                                     }

                                     }

COM                            COM возвращает запрошенный клиентом указатель на интерфейс

(клиентский указатель не то же самое, что и указатель на интерфейс

компонента)

Клиент                        pClf->CreateInstance (NULL, IID_IUnknown, (void**) &pUnk);

ЕХЕ компонент        Вызывает функцию CreateInstance фабрики классов не «напрямую»,

а косвенно с помощью маршаллинга.

                                     Создает СОМ объект.

                                     Возвращает указатель на запрошенный интерфейс косвенно с

помощью маршаллинга

Клиент                   Пользуется сервисами СОМ сервера, вызывая требуемые

функции СОМ объекта через запрошенный интерфейс

 

Клиент                        pClf->Release();

                                     pUnk->Release();

 

ЕХЕ компонент        Косвенно вызывается функция ЕХЕ компонента.

                                     if (refcount == 0) {самоуничтожение объекта СОМ}

                                     if (все объекты освобождены)

                                     {

                                     компонент завершил работу корректно

}

Клиент                        CoUninitialize(); // незадолго до завершения

COM                            Вызывает Release для всех объектов, которые клиент не смог

освободить

ЕХЕ компонент        Завершается.

COM                            Освобождает ресурсы

 

Клиент                        Завершает работу

 

Как вы можете видеть, COM играет важную роль во взаимодействии клиента и компонента. COM держит в памяти список фабрик классов, которые находятся в активных EXE компонентах, но не отслеживает отдельных объектов COM. Отдельные объекты COM отвечают за обновление ссылок и для уничтожения себя через механизм AddRef / Release. COM вмешивается, когда клиент завершается. Если такой клиент использует внепроцессный компонент, COM будет "прислушиваться" к взаимодействию клиента и компонента и отслеживать количество ссылок на каждый объект. COM отключится от объектов компонента, когда клиент завершится. При определенных обстоятельствах, это вызовет освобождение объектов. Тем не менее, не полагайтесь на такой сценарий. Убедитесь, что ваша программа-клиент освобождает все свои указатели на интерфейсы перед завершением.



Интерфейсы

Указатели на интерфейсы COM объекта. Указатель на интерфейс является 32-битным указателем, который ссылается на указатель на таблицу vtable (рис.35.1). Эта таблица является массивом указателей, каждый из которых, в свою очередь, указывает на реализацию метода. Таблица vtable является общей для всех экземпляров объекта, т.е. одна для класса, но каждый из объектов имеет, естественно, свой набор данных.

 

Рис. 35.1. Связь интерфейса с методами объекта

 

 

Имеются пять видов интерфейсов:

· базовый интерфейс IUnknown;

· пользовательский (custom) интерфейс;

· диспетчерский интерфейс IDispatch;

· диспинтерфейс (dispinterface);

· двойственный интерфейс (dual interface).

 

Интерфейс IUnknown поддерживает три метода и таблица виртуальных методов vtable для объекта, поддерживающего этот интерфейс, должна иметь такой вид (последовательность методов в таблице важна):

 

IUnknown::QueryInterface
IUnknown::AddRef
IUnknown::Release

 

Подчеркнем, что в соответствии со спецификацией СОМ методы интерфейса IUnknown должны быть размещены в таблице именно в указанном порядке.

 

Когда разработчик объекта добавляет свой интерфейс IMyInterface, предоставляющий методы и свойства некоторого объекта, таблица vtable приобретает такой вид:

 

IUnknown::QueryInterface
IUnknown::AddRef
IUnknown::Release
IMyInterface::Method1
IMyInterface::Method2
другие методы IMyInterface

 

Для объекта, поддерживающего интерфейсы IUnknown и IDispatch, та же таблица приобретает вид:

 

IUnknown::QueryInterface
IUnknown::AddRef
IUnknown::Release
IDispatch::GetIDsOfNames
IDispatch::GetTypeInfo
IDispatch::GetTypeInfoCount
IDispatch::Invoke

 

Отметим, что объекты, имеющие диспетчерский интерфейс, не могут не иметь интерфейса IUnknown.

Интерфейс IDispatch, в отличие от IUnknown, предоставляет возможность позднего связывания, что необходимо при программировании на интерпретируемых языках типа Basic. IDispatch не имеет индивидуальных методов для доступа к методам и свойствам объекта автоматизации. Вместо этого он предоставляет единственный метод Invoke, предназначенный для вызова методов COM объекта.

 

Замечание. Никто не запрещает реализовать всю функциональность СОМ объекта в одном единственном методе Invoke, однако такой подход вряд ли будет оптимальным с точки зрения наглядности и удобства использования объекта. Кроме того, непонятно, как быть в этом случае при необходимости добавления нового интерфейса или модификации функциональности сервера.

 

Для вызова конкретного метода объекта необходимо, сначала, получить номер метода с помощью функции GetIDsOfNames, а затем полученный номер метода указать в вызове функции Invoke. Функция GetIDsOfNames имеет такой прототип:

HRESULT GetIDsOfNames(

REFIID riid,// зарезервировано на будущее

OLECHAR FAR* FAR* rgszNames,// указатель на список имен методов 

unsigned int cNames,//количество имен

LCID lcid,// контекст локализации, в которой надо интерпретировать имена методов        

DISPID FAR* rgDispId // номера методов        

);

 

Вызывающая программа должна передать через указатель rgszNames имя (или имена) требуемого метода, а номер (или номера) метода она получит через указатель rgDispId. Возвращаемые функцией значения – код результата выполнения операции – описаны в табл. 1.

Таблица 1










Последнее изменение этой страницы: 2018-04-12; просмотров: 362.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...