Категории
Самые читаемые
ChitatKnigi.com » 🟢Компьютеры и Интернет » Программирование » Сущность технологии СОМ. Библиотека программиста - Дональд Бокс

Сущность технологии СОМ. Библиотека программиста - Дональд Бокс

Читать онлайн Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
1 ... 18 19 20 21 22 23 24 25 26 ... 95
Перейти на страницу:

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать

wcscpy(g_wsz, bstr);

должен быть защищен от возможных нулевых указателей:

wcscpy (g_wsz, bstr ? bstr : OLESTR(""));

Для упрощения использования BSTR в заголовочном файле ustring.h содержится простая встраиваемая функция:

intline OLECHAR *SAFEBSTR(BSTR b)

{

return b ? b : OLESTR("");

}

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

Простые типы, показанные на рис. 2.6, могут компоноваться вместе с применением структур языка С. IDL подчиняется правилам С для пространства имен тегов (tag namespace). Это означает, что большинство IDL-определений интерфейсов либо используют операторы определения типа (typedef):

typedef struct tagCOLOR

{

double red;

double green;

double blue;

} COLOR;

HRESULT SetColor([in] const COLOR *pColor);

либо должны использовать ключевое слово struct для квалификации имени тега:

struct COLOR { double red; double green; double blue; };

HRESULT SetColor([in] const struct COLOR *pColor);

Первый вариант предпочтительней. Простые структуры, подобные приведенной выше, можно использовать как из Visual Basic, так и из Java. Однако в то время, когда пишется эта книга, текущая версия Visual Basic может обращаться только к интерфейсам, использующим структуры, но она не может быть использована для реализации интерфейсов, в которых структуры являются параметрами методов.

IDL и СОМ поддерживают также объединения (unions). Для обеспечения однозначной интерпретации объединения IDL требует, чтобы в этом объединении имелся дискриминатор (discriminator), который показывал бы, какой именно член объединения используется в данный момент. Этот дискриминатор должен быть целого типа (integral type) и должен появляться на том же логическом уровне, что и само объединение. Если объединение объявлено вне области действия структуры, то оно считается неинкапсулированным (nonencapsulated):

union NUMBER

{

[case(1)] long i;

[case(2)] float f;

};

Атрибут [case] применен для установления соответствия каждого члена объединения своему дискриминатору. Для того чтобы связать дискриминатор с неинкапсулированным объединением, необходимо применить атрибут [switch_is]:

HRESULT Add([in, switch_is(t)] union NUMBER *pn, [in] short t);

Если объединение заключено вместе со своим дискриминатором в окружающую структуру, то этот составной тип (aggregate type) называется инкапсулированным, или размеченным объединением (discriminated union):

struct UNUMBER

{ short t; [switch_is(t)]

union VALUE

{

[case(1)] long i;

[case(2)] float f;

};

};

СОМ предписывает для использования с Visual Basic одно общее размеченное объединение. Это объединение называется VARIANT[4] и может хранить объекты или ссылки на подмножество базовых типов, поддерживаемых IDL. Каждому из поддерживаемых типов присвоено соответствующее значение дискриминатора:

VT_EMPTY nothing

VT_NULL SQL style Null

VT_I2 short

VT_I4 long

VT_R4 float

VT_R8 double

VT_CY CY (64-bit currency)

VT_DATE DATE (double)

VT_BSTR BSTR

VT_DISPATCH IDispatch *

VT_ERROR HRESULT

VT_BOOL VARIANT_BOOL (True=-1, False=0)

VT_VARIANT VARIANT *

VT_UNKNOWN IUnknown *

VT_DECIMAL 16 byte fixed point

VT_UI1 opaque byte

Следующие два флага можно использовать в сочетании с вышеприведенными тегами, чтобы указать, что данный вариант (variant) содержит ссылку или массив данного типа:

VT_ARRAY Указывает, что вариант содержит массив SAFEARRAY

VT_BYREF Указывает, что вариант является ссылкой

СОМ предлагает несколько API-функций для управления VARIANT:

// initialize a variant to empty

// обнуляем вариант

void VariantInit(VARIANTARG * pvarg);

// release any resources held in a variant

// освобождаем все ресурсы, используемые в варианте

HRESULT VariantClear(VARIANTARG * pvarg);

// deep-copy one variant to another

// полностью копируем один вариант в другой

HRESULT VariantCopy(VARIANTARG * plhs, VARIANTARG * prhs);

// dereference and deep-copy one variant into another

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

HRESULT VariantCopyInd(VARIANT * plhs, VARIANTARG * prhs);

// convert a variant to a designated type

// преобразуем вариант к указанному типу

HRESULT VariantChangeType(VARIANTARG * plhs, VARIANTARG * prhs, USHORT wFlags, VARTYPE vtlhs);

// convert a variant to a designated type

// преобразуем вариант к указанному типу (с явным указанием кода локализации)

HRESULT VariantChangeTypeEx(VARIANTARG * plhs, VARIANTARG * prhs, LCID lcid, USHORT wFlags, VARTYPE vtlhs);

Эти функции значительно упрощают управление VARIANT'ами. Чтобы понять, как используются эти API-функции, рассмотрим метод, принимающий VARIANT в качестве [in]-параметра:

HRESULT UseIt([in] VARIANT var);

Следующий фрагмент кода демонстрирует, как передать в этот метод целое число:

VARIANT var;

VariantInit(&var);

// initialize VARIANT

// инициализируем VARIANT

V_VT(&var) = VT_I4;

// set discriminator

// устанавливаем дискриминатор

V_I4(&var) = 100;

// set union

// устанавливаем объединение

HRESULT hr = pItf->UseIt(var);

// use VARIANT

// используем VARIANT

VariantClear(&var);

// free any resources in VARIANT

// освобождаем все ресурсы VARIANT

Отметим, что этот фрагмент кода использует макросы стандартного аксессора (accessor) для доступа к элементам данных VARIANT. Две следующие строки

V_VT(&var) = VT_I4;

V_I4(&var) = 100;

эквивалентны коду, который обращается к самим элементам данных:

var.vt = VT_I4;

var.lVal = 100;

Первый вариант предпочтительнее, так как он может компилироваться на С-трансляторах, которые не поддерживают неименованных объединений.

Ниже приведен пример того, как с помощью приведенной выше технологии реализация метода использует параметр VARIANT в качестве строки:

STDMETHODIMP MyClass::UseIt( /*[in] */ VARIANT var)

{

// declare and init a second VARIANT

// объявляем и инициализируем второй VARIANT

VARIANT var2;

VariantInit(&var2);

// convert var to a BSTR and store it in var2

// преобразуем переменную в BSTR и заносим ее в var2

HRESULT hr = VariantChangeType(&var2, &var, 0, VT_BSTR);

// use the string

// используем строку

if (SUCCEEDED(hr))

{

ustrcpy(m_szSomeDataMember, SAFEBSTR(V_BSTR(&var2)));

// free any resources held by var2

// освобождаем все ресурсы, поддерживаемые var2

VariantClear(&var2);

}

return hr;

}

Отметим, что API-процедура VariantChangeType способна осуществлять сложное преобразование любого переданного клиентом типа из VARIANT в нужный тип (в данном случае BSTR).

Один из последних типов данных, который вызывает дискуссию, – это интерфейс СОМ. Интерфейсы СОМ могут быть переданы в качестве параметров метода одним из двух способов. Если тип интерфейсного указателя известен на этапе проектирования, то тип интерфейса может быть объявлен статически:

HRESULT GetObject([out] IDog **ppDog);

Если же тип на этапе проектирования неизвестен, то разработчик интерфейса может дать пользователю возможность задать тип на этапе выполнения. Для поддержки динамически типизируемых интерфейсов в IDL имеется атрибут [iid_is]:

HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)] IUnknown **ppUnk);

Хотя эта форма будет работать вполне хорошо, следующий вариант предпочтительнее из-за его подобия с QueryInterface:

HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)] void **ppv);

Атрибут [iid_is] можно использовать как с параметрами [in], так и [out] для типов IUnknown * или void *. Для того чтобы использовать параметр интерфейса с динамически типизируемым типом, необходимо просто установить IID указателя требуемого типа:

IDog *pDog = 0; HRESULT hr = pItf->GetObject(IID_IDog, (void**)&pDog);

Соответствующая реализация для инициализации этого параметра просто использовала бы метод QueryInterface для нужного объекта:

STDMETHODIMP Class::GetObject(REFIID riid, void **ppv)

{

extern IUnknown * g_pUnkTheDog;

return g_pUnkTheDog->QueryInterface(riid, ppv);

}

Для уменьшения количества дополнительных вызовов методов между клиентом и объектом указатели интерфейса с динамически типизируемым типом должны всегда использоваться вместо указателей интерфейса со статически типизируемым типом IUnknown.

Атрибуты и свойства

Иногда бывает полезно показать, что объект имеет некие открытые свойства, которые могут быть доступны и/или которые можно модифицировать через СОМ-интерфейс. СОМ IDL позволяет аннотировать методы интерфейса с тем, чтобы данный метод либо модифицировал, либо читал именованный атрибут объекта. Рассмотрим такое определение интерфейса:

[ object, uuid(0BB3DAE1-11F4-11d1-8C84-0080C73925BA) ]

interface ICollie : IDog

{

// Age is a read-only property

// Age (возраст) – это свойство только для чтения

[propget] HRESULT Age([out, retval] long *pVal);

// HairCount is a read/write property

// HairCount (счетчик волос) – свойство для чтения/записи

[propget] HRESULT HairCount([out, retval] long *pVal);

[propput] HRESULT HairCount([in] long val);

// CurrentThought is a write-only property

// CurrentThought (текущая мысль) – свойство только для записи

[propput] HRESULT CurrentThought([in] BSTR val);

}

Использование атрибутов [propget] и [propput] информирует компилятор IDL, что методы, которые ему соответствуют, должны быть отображены в преобразователи свойств (property mutators) или в аксессоры на языках, явно поддерживающих свойства. Применительно к Visual Basic это означает, что элементами Age, HairCount и CurrentThought можно манипулировать, используя тот же синтаксис, как при обращении к элементам структуры:

1 ... 18 19 20 21 22 23 24 25 26 ... 95
Перейти на страницу:
Открыть боковую панель
Комментарии
Настя
Настя 08.12.2024 - 03:18
Прочла с удовольствием. Необычный сюжет с замечательной концовкой
Марина
Марина 08.12.2024 - 02:13
Не могу понять, где продолжение... Очень интересная история, хочется прочесть далее
Мприна
Мприна 08.12.2024 - 01:05
Эх, а где же продолжение?
Анна
Анна 07.12.2024 - 00:27
Какая прелестная история! Кратко, ярко, захватывающе.
Любава
Любава 25.11.2024 - 01:44
Редко встретишь большое количество эротических сцен в одной истории. Здесь достаточно 🔥 Прочла с огромным удовольствием 😈