HRESULT Method29([out, string] OLECHAR **ppwsz);
из которого следует такая реализация со стороны сервера:
HRESULT CFoo::Method29(OLECHAR **ppwsz)
{
const OLECHAR wsz[] = OLESTR(«Goodbye»);
int cb = (wcslen(wsz) + 1) * sizeof(OLECHAR);
*ppwsz = (OLECHAR*)CoTaskMemAlloc(cb);
if (*ppwsz == 0) return E_OUTOFMEMORY;
wcscpy(*ppwsz, wsz);
return S_OK;
}
Для правильного использования этого метода необходим такой код со стороны клиента:
void f(IFoo *pFoo)
{
OLECHAR *pwsz = 0;
if SUCCEEDED(pFoo->Method29(&pwsz)) {
DisplayString(pwsz);
CoTaskMemFree(pwsz);
}
}
Хотя, с одной стороны, применение этой технологии может привести к избыточному копированию памяти, с другой стороны, уменьшается время на прием-передачу и гарантируется, что могут быть возвращены строки любой длины, причем вызывающей программе не требуется связывать дополнительное пространство буфера в ожидании сколь угодно больших строк.
Синтаксис массива, приведенный в этом разделе, является совершенно разумным для программистов на С и C++. К сожалению, в то время, когда пишется этот текст, Visual Basic не способен работать ни с какими массивами переменной длины и может воспринимать только массивы фиксированной длины. Для того чтобы позволить Visual Basic посылать и получать массивы переменной длины, файлы СОМ IDL определяют среди прочих составной тип, именуемый SAFEARRAY. SAFEARRAY – это довольно редко используемая структура данных, которая позволяет передавать в качестве параметров многомерные массивы, совместимые с типом VARIANT. Для определения размеров массива SAFEARRAY в СОМ предусмотрен тип данных SAFEARRAYBOUND:
typedef struct tagSAFEARRAYBOUND {
ULONG cElements;
// size_is for dimension
// size_is для размерности
LONG lLbound;
// min index for dimension (usually 0)
// минимальный индекс для размерности (обычно 0)
} SAFEARRAYBOUND;
Тип данных SAFEARRAY внутри использует совместимый массив типа SAFEARRAYBOUND, чтобы придать некоторую форму содержимому массива:
typedef struct tagSAFEARRAY {
USHORT cDims;
// # of dimensions
// число измерений
USHORT fFeatures;
// flags describing contents
// флаги, описывающие содержимое
ULONG cbElements;
// # of bytes per element
// число байтов на элемент
ULONG cLocks;
// used to track memory usage
// применяется для слежения за использованием памяти
void* pvData;
// actual elements
// фактические элементы
[size_is(cDims)] SAFEARRAYBOUND rgsabound[]
} SAFEARRAY;
Приведенный выше IDL в действительности не используется для описания сетевого формата массивов SAFEARRAY, однако он используется для их программного описания.
Чтобы обеспечить пользователю максимальную гибкость в вопросах управления памятью, в СОМ определены следующие флаги, которые могут использоваться с полем fFeatures:
FADF_AUTO
/* array is allocated on the stack */
/* массив размещен в стеке */
FADF_STATIC
/* array is statically allocated */
/* массив размещен статически */
FADF_EMBEDDEO
/* array is embedded in a structure */
/* массив вложен в структуру */
FADF_FIXEDSIZE
/* may not be resized or reallocated */
/* не может изменить размеры или быть перемещен*/
FADF_BSTR
/* an array of BSTRs */
/* массив из BSTR */
FADF_UNKNOWN
/* an array of IUnknown* */
/* массив из IUnknown* */
FADF_DISPATCH
/* an array of IDispatch* */
/* массив из IDispatch* */
FADF_VARIANT
/* an array of VARIANTS */
/* массив из VARIANTS */
Для предоставления SAFEARRAY возможности определять типы данных своих элементов, компилятор IDL распознает специальный, специфический для SAFEARRAY, синтаксис:
HRESULT Method([in] SAFEARRAY(type) *ppsa);
где type – тип элемента в SAFEARRAY. Соответствующий прототип данного метода в C++ выглядел бы примерно так:
HRESULT Method(SAFEARRAY **psa);
Отметим, что в определении IDL используется только один уровень косвенности; в то же время в соответствующем определении C++ используются два уровня косвенности. Рассмотрим следующее определение на IDL, задающее массив типа SAFEARRAY из коротких целых чисел:
HRESULT Method([in] SAFEARRAY(short) *psa);
Соответствующее определение на Visual Basic выглядело бы таким образом:
Sub Method(ByVal psa As Integer())
Отметим, что в варианте на Visual Basic не указано явно размерностей массива. Напомним, однако, что Visual Basic поддерживает массивы с фиксированной длиной.
Тип данных SAFEARRAY поддерживается весьма богатым набором API-функций, которые позволяют изменять размерность массивов и производить обход их содержимого переносимым образом. Для доступа к элементам типа SAFEARRAY СОМ предусматривает следующие вызовы API-функций:
// get a pointer to the actual array elements
// получаем указатель на фактически элементы массива
HRESULT SafeArrayAccessData([in] SAFEARRAY *psa, [out] void ** ppv);
// release pointer returned by SafeArrayAccessData
// освобождаем указатель, возвращенный функцией SafeArrayAccessData
HRESULT SafeArrayUnaccessData([in] SAFEARRAY *psa);
// Get number of dimensions
// Получаем количество измерений
ULONG SafeArrayGetDim([in] SAFEARRAY *psa);
// Get upper bound of a dimension
Читать дальше