Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Алгоритм взаимодействия клиента с внутрипроцессным сервером
Глобальная функция 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, если ошибка не возникает, а в противном случае содержит код ошибки.
Любой сервер регистрируется в реестре 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; просмотров: 390. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |