распределенной среде, где задержка, вызванная передачей и приемом пакетов информации, создает огромные проблемы при циклических вызовах метода. В силу этих двух факторов при передаче типов данных с переменной длиной из реализации метода в вызывающую программу через [out]-параметр правильно организованный интерфейс СОМ предписывает реализации метода выделить пространство для результата, используя СОМ-распределитель памяти задачи. Это необходимо, поскольку фактический размер результата может быть известен только внутри реализации метода. Этот динамически выделенный буфер возвращается программе, вызвавшей метод, и после того, как буфер уже не нужен, вызывающая программа должна освободить этот буфер распределителем памяти задачи в вызываемом процессе. Чтобы выразить эту идиому для строкового параметра, приведем следующий корректно работающий код IDL:
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, синтаксис: