Вторник, 30.04.2024, 11:17
Распределенная обработка данных
Здравствуйте Гость | RSS
Главная страница Динамическая компоновка Регистрация Вход
Меню сайта

Считалка

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа

§ 11. Динамическая компоновка.

        

§ 11.1.  Хранение компонентов.

 

         После реализации компонента на том или ином языке программирования (в нашем случае С++) он должен выполняться как процесс в определенной операционной системе. СОМ-компоненты охраняться либо в исполняемых файлах (EXE), либо в файлах динамически загруженных библиотек Windows (DLL), либо в тех и других. Каждый вариант хранения имеет свои преимущества, и разработчик компонентов должен реализовывать определенные функции различным образом в зависимости от выбранного им способа размещения компонентов.

         1) термин локальный сервер  используется для описания компонентов, которые храниться в исполняемых файлах. Такие файлы, помимо СОМ-компонентов, могут содержать  и другие функции. Например, Microsoft Word является локальным сервером. Он не только обеспечивает возможности обработки текстов, но также представляет множество СОМ-компонентов, к которым имеют доступ другие приложения.

         2) Внутризадачный сервер представляет собой DLL-файл Windows. Выполнение этого компонента происходит в контексте вызывающего процесса и процесс клиента имеет прямой доступ к любому DLL-компоненту.  Понятие внутризадачности сервера приобретает особую значимость при рассмотрении пользовательских СОМ-интерфейсов и процессов транспортировки.

         3) Удаленный сервер   представляет собой компонент, загружаемый и выполняемый на удаленном компьютере. Обычно удаленный сервер строится как исполняемый файл, однако это не является обязательным требованием. Доступ к компонентам. Хранящимся только в DLL-файлах, может осуществляться и в удаленном режиме. В таких случаях модель СОМ создает суррогатный процесс, в котором могут выполняться удаленные DLL-файлы.

         Одним из преимуществ СОМ является независимость клиента (пользователя компонента) от местонахождения компонента, исходя СОМ-серверы могут быть реализованы в трех различных конфигурациях, клиенту при этом не требуется знать, каким образом реализован или где находятся необходимые серверы. Он создает экземпляр компонента, а расположение и запуск возлагаются на средства СОМ. Таким образом, многосвязность является неотъемлемыми свойством СОМ-компонентов.

         Наиболее эффективными являются внутризадачные серверы поскольку они выполняются в адресном пространстве клиента, и, кроме того, не требуется никаких дополнительных средств для передачи параметров методам компонента.

§ 11.2. Создание компонента.

 

         Для динамической компоновки необходимы отдельный файлы для клиента и компонента. Клиент создает компонент, содержащийся в DLL, то есть компонент динамически компонуется с клиентом. Прежде чем запросить указатель на интерфейс, клиент должен загрузить DLL в свой процесс и создать компонент. В предыдущей задаче функция CreateInstance создавала компонент и возвращала  указатель на интерфейс IUnknown. CreateInstance – единственная функция в DLL, с которой клиент должен быть скомпонован явно. [Ко всем прочим функциям компонента клиент может получить доступ через указатель на интерфейс]. Чтобы клиент мог вызывать функцию CreateInstance, ее надо экспортировать.

 

         § 11.2.1. Экспорт функции из DLL.

 

         Для экспорта функции, CreateInstance, которая находится в файле компонента  CMPNT1.CPP, необходимо:

         1) отметить ее как extern "C”, то есть обеспечить использование компоновки;

         2) сообщить компоновщику, что функция экспортируется . Для этого надо создать файл DEF.

 

         Пример DEF-файла для CMPNT1.DLL:

[его можно скопировать из примера и изменить несколько строк]

         ;

         ; файл определения модуля для Cmpnt1

         ;

         LIBRARY Cmpnt1.dll

         DISCRIPTION ‘2004 г. III курс

         EXPORTS

                   CreateInstance @1 PRIVATE

 

         § 11.2.2. Загрузка DLL.

 

         Файлы клиента CREATE.H и CREATE.CPP реализуют функцию [CALLCreateInstance], которая принимает имя DLL и вызывает экспортированную функцию с именем CreateInstance. Используя функции Win32 LoadLibrary и GetProcAddres клиент может динамически компоноваться с компонентом

 

         // Create.cpp

         #include <iostream.h>

    #include <unknwn.h>    // объявляет IUnknown

         #include <Create.h>

typedef IUnknown* (*CREATEFUNCPTR);        //функция //возвращает указатель //приведенного типа

//определим функцию CallСreateInstance для создания компонента //приводит возвращенный указатель к типу, пригодному для использования

        

IUncnown* CallСreateInstance (char*name)

    {

         //загрузить в процесс динамическую библиотеку

HIHNSTANCE hComponent = : : LoadLibrary (name);

if (nComponent == Null)

{

        cout <<”CallСreateInstance: \t

Ошибка: не могу загрузить компонент.” <<endl;

         return NULL;

}

         //получить адрес функции СreateInstance

    CREATEFUNCPTR СreateInstance

=( CREATEFUNCPTR) : : Get ProcAddress (hComponent, "СreateInstance”);

         if (СreateInstance == NULL)

         {

         cout     <<”CallСreateInstance: \t Ошибка:”

             <<”Не могу наитии функцию СreateInstance

             << endl;

         return Null;

}

         return СreateInstance ( );

}

//Для загрузки DLL CallСreateInstance вызывает функцию Win32 LoadLibrary:

HIHNSTANCE LoadLibrary (LPCTSTR lpLIbFIleName //имя файла DLL);

 

LoadLibrary принимает в качестве параметра имя файла DLL и возвращает описатель загруженной DLL. Функция Win32 GetProcAddress принимает этот описатель и имя функцииreateInstance), возвращая адрес последней.

 

FAR Proc Get ProcAddress (

HMODULE hModule,     //описатель модуля DLL

LPCSTR lpProcName    //имя функции);

         С помощью двух этих функций клиент  может загрузить DLL в свое адресное пространство и получить адрес СreateInstance. Имея этот адрес, создать компонент и получить на его IUnknown.

         DLL можно использовать для реализации компонентов, потому что DLL использует адресное пространство   приложения, с которым скомпонованы. В Windows  исполняющаяся программа называется процессом. Каждое приложение (EXE) исполняется в отдельном процессе, и у каждого  процесса имеется свое адресное пространство в 4Гбайт. Адрес в одном процессе отличен от того же адреса в другом процессе. Указатели не могут чередоваться из одного приложения в другое, поскольку они находятся в различных адресных пространствах. Указатели в двух процессах могут иметь одно и то же значение, но фактически они будут указывать на разные участки памяти.



Рис.11.1. Динамически компонуемые библиотеки размещаются в адресном пространстве процесса, содержащего приложения, с которым они скомпонованы.

 

         Поскольку DLL и EXE используют один и тот же процесс, они используют одно и то же адресное пространство. По этой причине DLL часто называют серверами внутри процесса. [серверы вне процесса]

         Итак, нам необходимо разбить программу на несколько файлов.




Рис. 11.2. Файлы клиента1 и компонента1.

 

Теперь клиент находится в файле CLIENT1.CPP. Он включает в себя файл Create.cpp (реализация CallСreateInstance и получение адреса СreateInstance). Эти два файла инкапсулируют создание компонента, находящегося в DLL. [В дальнейшем эти файлы заменяют функции, предоставляемые библиотекой COM]. Компонент теперь размещается в файле CMDNT1.CPP. Для динамической компоновки требуется файл определения модуля, в котором перечисляются функции, экспортируемые из DLL. Это файл CMPNT1.DEF. Компонент и клиент используют два общих файла. Файл IFACE.H содержит объявления для всех интерфейсов, поддерживаемых CMPNT1. Там же содержаться объявления для идентификаторов этих интерфейсов (ecxtern const IDD IDD _ X …). Определения данных идентификаторов находятся в файле CUIDS.CPP.

 

         //Create.h

         IUnknown*callСreateInstance (char*name)

         Для DLL шаблон

         прописать все используемые функции

         Собрать клиент и компонент с помощью следующих команд:

cl Client.cpp Create.cpp Guids.cpp UUID.LIB

cl /LD (LD-для динамической компоновки) Cmpnt1.cpp GUIDS.cpp UUID.LIB cmpnt1.def

UUID.LIB нужна для определения IID _ IUnknown (т.е. IID для IUnknown)
Поиск

Друзья сайта

2024