Как вернуть локальный CComSafeArray в выходной параметр LPSAFEARRAY?

StackOverflow https://stackoverflow.com/questions/1778491

  •  21-09-2019
  •  | 
  •  

Вопрос

У меня есть 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автор рассматривал ценностную семантику как главную цель;Прикрепление / отсоединение может быть просто "бонусной" функцией.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top