Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

191

FADF_BSTR

Массив BSTR

FAFD_UNKNOWN

Массив IUnknown*

FADF_DISPATCH

Массив IDispatch*

FADF_VARIANT

Массив VARIANT

Это поле также описывает, как массив был выделен:

FADF_AUTO

Массив размещен в стеке

FADF_STATIC

Массив размещен статически

FADF_EMBEDDED

Массив входит в структуру

FADF_FIXEDSIZE

Размер и местоположение массива нельзя менять

Библиотека Автоматизации — OLEAUT32.DLL — включает целый ряд функций для манипулирования SAFEARRAY. Названия всех таких функций начинаются с префикса SafeArray. Поищите их сами в диалоговой справочной системе.

Мы знаем, как заполнять переменные VARIANT, которые используются для построения структуры DISPPARAMS, которая передается IDispatch::Invoke, с помощью которой мы можем вызвать диспетчерские методы и получать доступ к диспетчерским свойствам. Теперь пришла пора кратко рассмотреть библиотеки типа

— независимый от языка эквивалент заголовочных файлов C++.

Библиотеки типа

Как мы уже видели, программа на Visual Basic или С++ может управлять компонентом через disp-интерфейс, ничего не зная о типах, связанных с этим интерфейсом или его методами. Однако, если Вы можете засунуть горошину в ухо, это не означает, что так и следует поступать. Точно так же, если Вы можете писать программу на Visual Basic без информации о типах, это не означает, что так и надо делать.

Описанные в предыдущем разделе проверка и преобразование типов VARIANT на этапе выполнения требуют много времени и могут привести к скрытым ошибкам в программе. Программист может случайно перепутать местами два параметра в вызове функции, и компонент успешно преобразует их типы. Большое преимущество С++ перед С — более строгая проверка типов; она до некоторой степени обеспечивает уверенность в том, что программа работает, как предполагалось.

Нам нужен независимый от языка эквивалент заголовочных файлов С++, который подходил бы для интерпретируемых языков и сред макропрограммирования. Решение есть — библиотека типа (type library) СОМ, которая предоставляет информацию типа о компонентах, интерфейсах, методах, свойствах, аргументах и структурах. Содержимое библиотеки типа аналогично содержимому заголовочного файла С++. Библиотека типа

— это откомпилированная версия файла IDL, к которой возможен доступ из программы. Это не текст на каком-то языке, требующий синтаксического разбора, а двоичный файл. Библиотека Автоматизации предоставляет стандартные компоненты для создания и чтения таких двоичных файлов.

Без библиотеки типа возможности Visual Basic работать с компонентами ограничены disp-интерфейсами. Если же библиотека типа имеется, Visual Basic может работать с компонентом напрямую через vtbl дуального интрфейса. Доступ через vtbl быстрее, и он безопаснее с точки зрения приведения типа.

Да, пока не забыл, — библиотека типа может также содержать строки справочной информации для всех содержащихся в ней компонентов, интерфейсов и функций. С помощью средства просмотра объектов, подобного имеющемуся в Visual Basic, программист может легко получить подсказку о любом свойстве или методе. Не правда ли, замечательно?

Создание библиотеки типа

Библиотеку типа создает функция CreateTypeLib из библиотеки Автоматизации. CreateTypeLib возвращает интерфейс IcreateTypeLib, который можно использовать для занесения в библиотеку различной информации. Вряд ли Вам когда-нибудь потребуется использовать этот интерфейс; вместо него можно пользоваться IDL и компилятором MIDL. В гл. 10 мы использовали IDL и компилятор MIDL для генерации кода DLL заместителя/заглушки, но они подходят и для генерации библиотек типа.

ODL и MkTypLib

В «старые» времена компилятор MIDL нельзя было использовать для генерации библиотек типа. Вместо описания библиотек на IDL приходилось использовать другой язык — ODL. ODL компилировался в библиотеку типа с помощью программы MkTypLib. ODL был похож на IDL, но отличий было достаточно,

192

чтобы затруднить их совместное использование. Поддержка двух файлов, содержащих одну и ту же информацию, — также напрасный расход времени. К счастью, IDL и MIDL при разработке Windows NT 4.0 были расширены для поддержки создания библиотек типа. Теперь ODL и MkTypLib стали не нужны и более не используются.

Оператор library

Основа создания библиотеки типа при помощи IDL — оператор library. Все, что находится внутри блока кода, ограниченного фигурными скобками, которые следуют за ключевым словом library, будет компилироваться в библиотеку типа. Файл IDL из примера гл. 11 показан в листинге 11-1. как видите, у библиотеки типа есть свои

GUID, версия и helpstring.

SERVER.IDL

//

// Server.idl – Исходный файл IDL для Server.dll

//

//Этот файл будет обрабатываться компилятором MIDL для

//генерации библиотеки типа (Server.tlb) кода маршалинга.

//

// Интерфейс IX

[

object,

uuid(32BB8326-B41B-11CF-A6BB-0080C7B2D682), helpstring("Интерфейс IX"),

pointer_default(unique), dual,

oleautomation

]

interface IX : IDispatch

{

import "oaidl.idl";

HRESULT Fx();

HRESULT FxStringIn([in] BSTR bstrIn);

HRESULT FxStringOut([out, retval] BSTR* pbstrOut); HRESULT FxFakeError();

};

//

// Описание компонента и библиотеки типа

//

[

uuid(D3011EE1-B997-11CF-A6BB-0080C7B2D682),

version(1.0),

helpstring("Основы COM, Глава 11 1.0 Библиотека типа")

]

library ServerLib

{

importlib("stdole32.tlb");

// Компонент

[

uuid(0C092C2C-882C-11CF-A6BB-0080C7B2D682), helpstring("Класс компонента")

]

coclass Component

{

[default] interface IX;

};

};

Листинг 11-1 Файл IDL, используемый для генерации библиотеки SERVER.TLB

Оператор coclass определяет компонент; в данном случае это Component с единственным интерфейсом IX. Компилятор MIDL сгенерирует библиотеку типа, содержащую Component и IX. Component добавляется к библиотеке типа, так как оператор coclass находится внутри оператора library. Интерфейс IX включается в библиотеку потому, что на него есть ссылка внутри оператора library.

193

Когда компилятор MIDL встречает в файле IDL оператор library, он автоматически генерирует библиотеку типа. В гл. 10 Вы видели, что компилятор MIDL генерировал библиотеку типа SERVER.TLB, даже когда она не была нам нужна.

Распространение библиотек типа

После генерации библиотеки типа Вы можете либо поставлять ее в виде отдельного файла, либо включить ее в Ваш EXE или DLL как ресурс. Большинство разработчиков предпочитает второй вариант, поскольку он упрощает установку приложения.

Использование библиотек типа

Первый шаг при использовании библиотек типа — ее загрузка. Для этого имеется несколько функций. Первая, которую следует попробовать, — LoadRegTypeLib, пытающаяся загрузить библиотеку по информации из Реестра Windows. Если эта функция потерпела неудачу, Вам следует использовать LoadTypeLib, которая загружает библиотеку с диска по имени файла, либо LoadTypeLibFromResource, которая загружает библиотеку типа из ресурса в EXE или DLL. LoadTypeLib должна в процесса загрузки регистрировать для Вас библиотеку типа. Однако если ей задано имя полного пути, библиотека зарегистрирована не будет (см. PSS ID Number Q131055). Следовательно, после успешного вызова LoadTypeLib стоит вызвать RegisterTypeLib. Соответствующий код приведен в листинге 11-2.

Модифицированный код инициализации компонента из CMPNT.CPP

HRESULT CA::Init()

{

HRESULT hr;

// Динамически загрузить TypeInfo, если он еще не загружен if (m_pITypeInfo == NULL)

{

ITypeLib* pITypeLib = NULL;

 

hr = ::LoadRegTypeLib(LIBID_ServerLib,

// Номера версии

1, 0,

0x00,

 

&pITypeLib);

 

if (FAILED(hr))

{

// Загрузить и зарегистрировать библиотеку типа

hr = ::LoadTypeLib(wszTypeLibFullName, &pITypeLib); if(FAILED(hr))

{

trace("Вызов LoadTypeLib неудачен", hr); return hr;

}

// Убедиться, что библиотека типа зарегистрирована

hr = RegisterTypeLib(pITypeLib, wszTypeLibFullName, NULL); if(FAILED(hr))

{

trace("Вызов RegisterTypeLib неудачен", hr); return hr;

}

}

// Получить информацию типа для интерфейса объекта

hr = pITypeLib->GetTypeInfoOfGuid(IID_IX, &m_pITypeInfo); pITypeLib->Release();

if (FAILED(hr))

{

trace("Вызов GetTypeInfoOfGuid неудачен", hr); return hr;

}

}

return S_OK;

}

Листинг 11-2 Загрузка, регистрация и использование библиотеки типа

Соседние файлы в предмете Программирование на C++