Студопедия

КАТЕГОРИИ:

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

Алгоритм взаимодействия клиента с внутрипроцессным сервером




Глобальная функция CoGetClassObject (префикс «Со» обозначает"компонентный объект") вызывается клиентским процессом и предназначена для загрузки сервера в память и получения интерфейса фабрики классов:

STDAPI CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext,

COSERVERINFO* pServerInfo, REFIID riid, LPVOID* ppvObj)

 

Указатель на интерфейс фабрики классов возвращается в параметре ppvObj, параметр pServerInfo является указателем на компьютер, на котором будет создан СОМ объект (если компьютер локальный, то pServerInfo==NULL). Типы REFCLSID и REFIID представляют собой 128-битные глобально уникальные идентификаторы (GUID) для классов COM и интерфейсов. STDAPI означает, что функция возвращает 32-разрядное значение типа HRESULT .

Стандартные идентификаторы GUID (например те, что создала Microsoft) определяются в библиотеках Windows, которые динамически подключаются к нашей программе. Нам необходимо только определить идентификаторы GUID для пользовательских классов и интерфейсов.

Если параметр dwClsContext==CLSCTX_INPROC_SERVER, COM будет искать DLL или ОСХ, в которой находится сервер. Если параметр dwClsContext==CLSCTX_LOCAL_SERVER, COM будет искать EXE. Эти флаги могут быть объединены с помощью операции ИЛИ, чтобы определить загрузку DLL, если DLL доступна, или EXE, если DLL не доступна. Например, внутрипроцессные серверы быстрее, потому что потому что располагаются в том же адресном пространстве, что и клиентский процесс. Взаимодействие с EXE серверами значительно медленнее, потому что межпроцессные вызовы функций связаны с копированием данных, а также с переключениями контекста между потоками. Возвращаемое значение HRESULT равно NOERROR, если ошибка не возникает, а в противном случае содержит код ошибки.

Замечание.Еще одна функция COM  – CoCreateInstance, сочетает в себе функциональность CoGetClassObject и IClassFactory::CreateInstance.

Любой сервер регистрируется в реестре Windows при первом запуске, построении (build) в среде MVS или с помощью отдельной команды. Объекты фабрики классов для локальных или удаленных серверов (внепроцессных) также должны быть зарегистрированы в памяти из собственного процесса серверов. В данном случае слово регистрация не относится к реестру. Объекты внепроцессных компонентов регистрируются на этапе выполнения с помощью вызова функции COM CoRegisterClassObject и информация о регистрации сохраняется в памяти DLL- библиотек Windows. Если классов зарегистрирована в режиме, который разрешает использовать один экземпляр модуля компонента для создания нескольких объектов COM, COM может использовать существующий процесс, когда клиент вызывает CoGetClassObject.

 

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

 

Взаимодействие клиента с внутрипроцекссным компонентом, в отличие от ЕХЕ компонента, проще. Опишем это взаимодействие с использованием псевдокода, так как в реальных программах многие детали скрываются за вызовами функций Windows и СОМ.

 

Клиент                        CLSID clsid;

                                     IClassFactory* pClf;

                                     IUnknown* pUnk;

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

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

 

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

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

 

Клиент                        CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL,

                                     IID_IClassFactory, (void**) &pClf );

 

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

                                     if (DLL еще не загружена)

                                     {

                                     COM получает имя DLL из реестра

                                     COM загружает DLL в адресное пространство клиентского процесса

                                     }

 

Компонент DLL        if (компонент уже загружен)

{

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

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

                                     }

 

COM                            COM вызывает экспортируемую DLL функцию DllGetClassObject

и передает ей  clsid, который был ранее передан в функцию

CoGetClassObject

 

Компонент DLL        Функция DllGetClassObject возвращает IClassFactory*

 

COM                            COM возвращает IClassFactory* клиенту

 

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

 

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

через таблицу vtable компонента.

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

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

 

Клиент                        Вызывает функции СОМ объекта, тем самым получая его сервисы

 

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

pClf->Release();

                                     pUnk->Release();

 

 

Компонент DLL        Вызывает функцию Release через vtable.

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

 

Клиент                    Вызывает CoFreeUnusedLibraries();

 

COM                            COM вызывает функцию DllCanUnloadNow сервера

 

Компонент DLL        Функция DllCanUnloadNow возвращает TRUE, все объекты DLL

уничтожены

 

Клиент                        CoUninitialize(); // COM выгружает DLL, если DllCanUnloadNow

                                     возвратила TRUE

 

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

 

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

 

Компонент DLL        Windows выгружает DLL, если она все еще загружена и никакие

другие процессы ее не используют

 

Отметим некоторые важные моменты.

Во-первых, экспортируемая библиотекой DLL функция DllGetClassObject вызывается в ответ на вызов клиентом функции CoGetClassObject. Во-вторых, возвращенный адрес интерфейса фабрики классов является фактическим физическим адресом указателя на vtable фабрики классов. В-третьих, когда клиент вызывает CreateInstance или любую другую функцию интерфейса, вызов является непосредственным, т.е. через vtable.

Связь COM между клиентским процессом и DLL компонента является весьма эффективной, такой же, как и вызов виртуальной функции в том же процессе, плюс полная проверка параметров и типов во время компиляции. Единственным недостатком по сравнению с использованием обычной DLL является дополнительное время, затрачиваемое на поиск идентификатора класса в реестре, когда DLL загружается впервые.

 










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

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