Как вернуть локальный CComSafeArray в выходной параметр LPSAFEARRAY?
Вопрос
У меня есть COM-функция, которая должна возвращать SafeArray через LPSAFEARRAY*
параметр out.Функция создает SafeArray, используя ATL CComSafeArray
класс шаблона.Моя наивная реализация использует CComSafeArray<T>::Detach()
для того, чтобы перенести право собственности из локальной переменной в выходной параметр:
void foo(LPSAFEARRAY* psa)
{
CComSafeArray<VARIANT> ret;
ret.Add(CComVariant(42));
*psa = ret.Detach();
}
int main()
{
CComSafeArray<VARIANT> sa;
foo(sa.GetSafeArrayPtr());
std::cout << sa[0].lVal << std::endl;
}
Проблема в том, что CComSafeArray::Detach()
выполняет Unlock
операция, так что, когда новый владелец SafeArray (основной sa
в этом случае) уничтожается, блокировка не равна нулю и Destroy
не удается разблокировать SafeArray с помощью E_UNEXPECTED
(это приводит к утечке памяти, поскольку SafeArray не освобожден).
Каков правильный способ передачи права собственности между CComSafeArrays и CComSafeArrays через границу метода COM?
Редактировать: Из единственного ответа пока кажется, что ошибка на стороне клиента (main
) и не со стороны сервера (foo
), но мне трудно поверить, что CComSafeArray
не был разработан для этого тривиального варианта использования, должен быть элегантный способ получить SafeArray из COM-метода в CComSafeArray
.
Решение
Проблема в том, что вы устанавливаете прием CComSafeArray
внутренний указатель напрямую.Используйте Attach()
способ присоединения существующего SAFEARRAY
к a CComSafeArray
:
LPSAFEARRAY ar;
foo(&ar);
CComSafeArray<VARIANT> sa;
sa.Attach(ar);
Другие советы
Просто чтобы подтвердить, что отмеченный ответ правильный.Оболочки RAII не могут работать через границы COM.
Опубликованная реализация метода неверна, вы не можете предположить, что вызывающий объект собирается предоставить действительный SAFEARRAY.Просто [out] не является допустимым атрибутом в автоматизации, он должен быть либо [out, retval], либо [in, out].Если это [out, retval], на что это похоже, то метод должен создать новый массив с нуля.Если это [in,out], то метод должен уничтожить переданный массив, если он не соответствует ожидаемому типу массива, и создать новый.
Я бы предположил, что у where не было намерения допускать такой вариант использования.Вероятно, это был не тот разработчик , который написал CComVariant
& CComPtr
:)
Я верю, что CComSafeArray
автор рассматривал ценностную семантику как главную цель;Прикрепление / отсоединение может быть просто "бонусной" функцией.