Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Учебное пособие 1877

.pdf
Скачиваний:
5
Добавлен:
30.04.2022
Размер:
2.61 Mб
Скачать

2.3.6. Библиотеки

COM-объекты помещаются в библиотеки. Чаще всего это файл с расширением DLL, но иногда библиотеки помещаются в EXEили OCX-модули. Расширение OCX всего лишь говорит о том, что в библиотеке находится элементы управления ActiveX, по существу это тоже DLL. EXE-формат (исполняемый файл) используется в двух случаях: 1) когда надо создать отдельный COM-сервер, не требующий при своей работе наличия MTS или COM+, 2) когда создается настольное Windows-приложение, которое должно поддерживать Automation (выставлять некоторую объектную модель, доступную из других приложений).

Так вот, кроме того, что библиотека должна быть помещена в какой-нибудь исполняемый файл, она еще должна быть специальным образом описана и зарегистрирована на компьютере, где ее предполагается использовать. В MIDL такое описание выглядит так:

[

uuid(96479D03-B2D5-11D3-AE78-004095E1F072), version(1.0),

helpstring("Stack Type Library v 1.0")

]

library StackLib

{

[

uuid(95F3208B-F9AC-11d3-A6AD-0050BAC0EF0F), helpstring("Iauaeo Stack")

]

coclass Stack

{

[default] interface IStack;

};

}

101

В теле библиотеки содержится описание входящих в нее объектов. На основании такого описания MIDL генерирует библиотеку типов. Как и другие объекты в COM, библиотеки должны иметь свой уникальный идентификатор (GUID). В применении к библиотеке он называется LibID. В случае DLL библиотека типов прилинковывается к DLL, а в случае с EXE обычно поставляется отдельно в файле с расширением TLB или OLB. Как бы там ни было, библиотека типов регистрируется в системе, и с ее помощью можно получать информацию о любом элементе библиотеки. С помощью библиотеки типов можно даже сгенерировать MIDL-описание для всех элементов библиотеки. В поставку MS Visual Studio входит утилита «OLE View», позволяющая просматривать библиотеки типов и получать MIDL-описание.

2.4. Создание простого COM-объекта

Создавать COM-объекты очень просто. Однако для создания проекта COM-библиотеки на C++ нужно написать довольно много одинакового (повторяющегося из проекта в проект и занудного) кода. Чтобы не делать этого каждый раз, лучше всего воспользоваться библиотекой ATL (о ней уже говорилось ранее) и соответствующими визардами (речь идет про Microsoft VC и Borland C++ Builder). На VB вообще надо только выбрать тип проекта «ActiveX DLL». При этом VB создаст класс. Любой метод или свойство этого класса, не помеченный как Private, будет являться методом или свойством COM-объекта. Пример, который далее будет реализован на C++, на VB будет выглядеть так:

Public Function Summa(ByVal P1 As Long, ByVal P2 As Long)

Summa = P1 + P2

End Function

ВC++ (и на VC и на C++ Builder) надо создать проект.

ВVC надо выбрать меню «File\New» и в появившемся визарде на закладке «Projects» вбить имя проекта, путь к нему, и

102

нажать Enter. Назовем проект «VCTest1». На следующей странице достаточно еще раз нажать Enter, так как ее установки полностью нас удовлетворяют. Появится окно, перечисляющее, какие файлы будут созданы (рис. 2.39). Это последний шанс отменить создание проекта. Еще раз нажмем

Enter.

Рис. 2.39. Создать проект

Итак, что же создает этот визард?

VCTest1.dsp – DLL-проект VC.

VCTest1.cpp и VCTest1.h – файлы библиотеки. Они отвечают за саморегистрацию библиотеки и за создание объектов.

VCTest1.idl – IDL-описание нашей библиотеки. Пока что этот файл содержит пустое описание

библиотеки типов.

VCTest1ps.mk – make-файл, создающий DLL,

содержащую proxy и stub для интерфейсов, входящих в нашу библиотеку. Если библиотека будет отвечать требованиям Automation, то DLL, создаваемая этим make-файлом, да и сам make-файл нам никогда не понадобятся. Иначе для

103

маршалинга придется использовать proxy/stub DLL. При создании проекта можно заставить ATL-визард объединять proxy/stub с основной DLL-библиотекой.

Если скомпилировать проект, получится VCTest1.dll, не содержащая ни одного объекта. Поэтому вместо компиляции добавим COM-объект.

Для этого из меню Insert нужно выбрать пункт «New ATL Object». Появится «ATL Object Wizard». Надо выбрать «Objects\Simple Objects» и нажать кнопку «Next >».

На этом шаге визард попросит задать имя объекта. Сделать это можно в поле «Short Name». Введем в него строку

«VCTestObj» (см. рис. 2.40).

Рис. 2.40. Задаем имя объекта

Остальные параметры можно оставить по умолчанию, так что нажмем Enter. При этом к проекту добавятся три файла:

104

-VCTestObj.h – содержащий описание C++-объекта (CVCTestObj), являющегося реализацией нашего COMобъекта;

-VCTestObj.cpp – сейчас он пуст (в будущем в него будет добавляться код для объекта CVCTestObj);

-VCTestObj.rgs – файл, содержащий описание – информацию, которую надо занести в реестр.

В IDL-файл при этом добавилось описание нового объекта и нового интерфейса. Осталось добавить метод, и можно компилировать проект. Для этого следует переключиться на закладку «ClassView» в окне «Workspace», щелкнуть правой кнопкой мыши по имени интерфейса (IVCTestObj) и в контекстном меню выбрать пункт «Add Method» (см. рис. 2.41).

Рис. 2.41. Добавление метода В появившемся диалоге надо ввести имя метода и

описание его параметров, как это показано на рис. 2.42.

105

После нажатия Enter в описании интерфейса (файл

VCTest1.idl) и в описании объекта C++ (файлы VCTestObj.h и VCTestObj.cpp) добавится описание нового метода. Осталось перейти к новому методу и внести необходимый код:

*piResult = iP1 + iP2;

Рис. 2.42. Ввод имени метода и описания параметров

Перейти к нужному методу можно, выбрав его на закладке «ClassView». Результат этих действий показан на рис. 2.43.

106

Рис. 2.43. ClassView

Теперь можно собрать проект, нажав кнопку F7. При сборке проекта происходит автоматическая регистрация библиотеки. Так что после завершения можно сразу приступать к тестированию проекта.

Единственное, что необычно в приведенном примере – это то, что результат возвращается через параметр, а не как возвращаемое значение функции. Это вызвано тем, что возвращаемое значение в методах COM-объекта зарезервировано для возврата кода ошибки.

2.4.1. Установление связи с удаленным объектом

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

107

#include "stdafx.h" #include <stdio.h> #include <conio.h> #include "objbase.h"

#include "..\VCTest1.h" #include "..\VCTest1_i.c"

int main(int argc, char* argv[])

{

//Инициализируем COM CoInitialize(NULL); IVCTestObj * pIVCTestObj;

//Создаем объект - VCTestObj

HRESULT hr = CoCreateInstance(CLSID_VCTestObj, NULL, CLSCTX_SERVER,

IID_IVCTestObj, (void**)&pIVCTestObj); if(SUCCEEDED(hr))

{

// Если объект создан...

int iP1 = 1, iP2 = 2, iResult = 0;

// Вызываем метод COM-объекта...

hr = pIVCTestObj->Summa(iP1, iP2, &iResult); // Освобождаем ссылку на COM-объект...

pIVCTestObj->Release();

printf("Call 'Summa(%d, %d)' return %d.\n", iP1, iP2, iResult);

}

printf( "\n\nError code: 0x%08x\n\n" "Press eny key to continue...\n", hr);

_getch(); // Ожидаем ввода символа (для удобства отладки)

CoUninitialize(); // Деинициализируем COM return 0;

}

108

В этом примере, CLSID объекта, IID и описание интерфейса берутся из сгенерированных компилятором MIDL для первого проекта (см. «Создание простого COM-объекта»)

файлов (VCTest1.h и VCTest1_i.c) (рис. 2.44).

Рис. 2.44

Такой способ удобно применять, если и объект и вызывающее его приложение созданы на C++ и доступны описания в текстовом виде. Если же вам доступна только бинарная библиотека, то можно воспользоваться расширением C++ – директивой «#import». Это расширение сделано Microsoft. Если я не ошибаюсь, оно доступно начиная с пятой версии VC. Чтобы получить результат, аналогичный включению файлов VCTest1.h и VCTest1_i.c, надо использовать следующий синтаксис:

#import "..\Debug\VCTest1.dll" \ no_implementation no_namespace \ named_guids raw_interfaces_only

109

С помощью директивы «#import» также можно создать классы-обертки, позволяющие упростить работу с включенными в библиотеку компонентами. Подробнее об этой директиве можно узнать в документации по VC.

В C++ Builder тоже реализована поддержка «#import», но, к сожалению, криво. В документации предлагается для взаимодействия с COM-объектами пользоваться импортом библиотек типов. Для этого нужно в меню «Project» выбрать пункт «Import Type Library», найти в списке необходимую библиотеку типов и нажать кнопку «Install». При этом создаются файлы описания и классы-обертки. После перекомпиляции пакеджа (в который происходит импорт) в палитре компонентов, на закладке «ActiveX» появятся новые компоненты, в нашем случае один «VCTestObj». Если поместить один из них на форму, то с его помощью можно будет производить вызовы методов COM-объекта. Вот как выглядит вызов метода нашего тестового объекта:

VCTestObj1->Connect();

ShowMessage("Summa(1, 2) = " + String(VCTestObj1- >Summa(1, 2)));

VCTestObj1->Disconnect();

Метод Connect создает экземпляр объекта, а Disconnect освобождает ссылку (вызовом Release). Таким образом, объект создается и, после вызова метода Summa, уничтожается. Если надо обеспечить жизнь объекта на протяжении всей жизни формы, то можно вместо вызова Connect установить свойство AutoConnect в True во время разработки. Это приведет к тому, что COM-объект создастся при загрузке формы. Метод Disconnect в этом случае тоже можно проигнорировать, при уничтожении формы ссылка на COM-объект будет освобождена автоматически.

Этот механизм C++ Builder позаимствовал у Delphi. Сравните код Delphi с приведенным ранее.

VCTestObj1.Connect();

110