rgs[n] = n * n;
return S_OK;
}
Это позволяет вызывающей программе контролировать задание размеров буфера, а реализация метода контролирует фактическое количество переданных элементов.
Если открытый массив будет использоваться в качестве входного/выходного параметра, то следует указать переменную длину массива в каждом направлении. Если число элементов на входе может отличаться от числа элементов на выходе, то параметр переменной длины тоже должен иметь входной/выходной тип:
HRESULT Method17([in] long cMax,
[in, out] long *pcActual,
[in, out, size_is(cMax), length_is(*pcActual)] short *rgs);
что предполагает следующий код на стороне клиента:
void f(IFoo *pFoo)
{
short rgs[8];
rgs[0] = 0; rgs[1] = 1;
long cActual = 2;
pFoo->Method17(8, &cActual, rgs);
// .. process first cActual elements of rgs
// .. обрабатываем первые cActual элементов из массива rgs
}
Если число элементов на входе и на выходе одно и то же, то подойдет совместимый массив:
HRESULT Method18([in] long cElems,
[in, out, size_is(cElems)] short *rgs);
Данный метод использует эффективность совместимого массива, и его гораздо проще использовать.
Приведенные выше примеры оперировали с одномерными массивами. Рассмотрим следующий прототип на С:
void g(short **arg1);
Этот прототип может означать в С все, что угодно. Возможно, функция ожидает указатель на одно короткое целое число:
void g(short **arg1) {
// return ptr to static
// возвращаем указатель на static
static short s;
*arg1 = &s;
}
Или, возможно, функция ожидает массив из 100 коротких указателей:
void g(short **arg1)
{
// square 100 shorts by ref
// квадрат из 100 коротких целых указателей
for (int n = 0; n < 100; n++)
*(arg1[n]) *= *(arg1[n]);
}
А также, возможно, функция ожидает указатель на указатель на массив коротких целых:
void g(short **arg1)
{
// square 100 shorts
// квадрат из 100 коротких целых
for (int n = 0; n < 100; n++)
(*arg1)[n] *= (*arg1)[n];
}
Этот синтаксический кошмар разрешается в IDL использованием такого синтаксиса, который часто побуждает пользователей-новичков бежать за утешением к документации.
Атрибуты IDL [size_is] и [lengtn_is] принимают переменное количество разделенных запятой аргументов, по одному на каждый уровень косвенности. Если параметр пропущен, то считается, что соответствующий уровень косвенности является указателем на экземпляр, а не на массив. Для того чтобы показать, что параметр является указателем на указатель на одиночный экземпляр, не требуется более никаких атрибутов:
HRESULT Method19([in] short **pps);
что означает такое расположение в памяти:
pps -> *pps-> **pps
Для того чтобы показать, что параметр является указателем на массив указателей на экземпляры, нужно написать следующий код IDL:
HRESULT Method20([in, size_is(3)] short **rgps);
что в памяти будет выглядеть примерно так:
rgps -> rgps[0] -> *rgps[0]
rgps[1] -> *rgps[1]
rgps[2] -> *rgps[2]
Для того чтобы показать, что параметр является указателем на указатель на массив экземпляров, следует написать такой код на IDL:
HRESULT Method21([in, size_is(,4)] short **pprgs);
что в памяти будет выглядеть следующим образом:
pprgs -> pprgs -> (pprgs)[0]
(pprgs)[1]
(pprgs)[2]
(pprgs)[3]
Для того чтобы показать, что параметр является массивом указателей на массивы экземпляров, нужно написать следующее:
HRESULT Method22([in, size_is(3,4)] short **rgrgs);
что в памяти будет выглядеть примерно так:
rgrgs -> rgrgs[0] -> rgrgs[0][0]
rgrgs[0][1]
rgrgs[0][2]
rgrgs[0][3]
rgrgs[1] -> rgrgs[1][0]
rgrgs[1][1]
rgrgs[1][2]
rgrgs[1][3]
rgrgs[2] -> rgrgs[2][0]
rgrgs[2][1]
rgrgs[2][2]
rgrgs[2][3]
Данный синтаксис, быть может, оставляет желать лучшего, тем не менее, он обладает большей гибкостью и меньшей неоднозначностью, чем на С.
Важно отметить, что приведенный выше метод IDL задает многомерный массив; формально он представляет собой массив указателей на массив указателей на экземпляры. Это не то же самое, что