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

ОглавлениеДобавить в закладки К обложке

HRESULT GetString([out, retval] BSTR *pbstr);

При реализации метода потребуется создать новую BSTR-строку для возврата вызывающему объекту:

STDMETHODIMP MyClass::GetString(BSTR *pbstr)

{

*pbstr = SysAllocString(OLESTR(«Coodbye!»)) ;

return S_OK;

}

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

extern OLECHAR g_wsz[];

BSTR bstr = 0;

HRESULT hr = p->GetString(&bstr);

if (SUCCEEDED(hr))

{

wcscpy(g_wsz, bstr); SysFreeString(bstr);

}

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

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)


Логин
Пароль
Запомнить меня