Выделение VARIANT из клиента COM на C ++ - PullRequest
1 голос
/ 17 ноября 2010

Я пытаюсь маршалировать надежный массив BSTR из COM-объекта обратно в клиентское приложение C ++.

Мое определение IDL задействованной функции:

[id(5), helpstring("method GetStreams")] 
    HRESULT GetStreams( [out,retval] VARIANT* pvarStreamNames );

Вот моя реализация функции GetStreams ():

STDMETHODIMP CArchiveManager::GetStreams(VARIANT* pvarStreamNames)
{   
CComSafeArray<BSTR, VT_BSTR>    saStreamNames;
CComVariant                     varOutNames;

Stream* pNext       = NULL;
int     nNumStreams = m_Streams.NumStreams();

if( nNumStreams == 0 )
    return S_OK;

for(int x = 0; x < nNumStreams; x++)
{
    pNext = m_Streams.GetAt(x); 
    if( pNext )             
        saStreamNames.Add( pNext->StreamName() );   
}

if( saStreamNames.GetCount() > 0 )
{
    varOutNames.vt      = VT_ARRAY;
    varOutNames.parray  = saStreamNames.m_psa;

    varOutNames.Detach(pvarStreamNames);
}

return S_OK;
}

Вот как клиентская программа C ++ вызывает функцию GetStreams ():

VARIANT varStreamNames;
hr = spArchiveMgr->GetStreams( &varStreamNames );

Я прослеживаю программу, используя интерактивный отладчик, и кажется, что все работает правильно (safearray заполняется правильно и т. Д.), Пока не вернется функция GetStreams (). В этот момент я получаю сообщение «Место чтения необработанного исключения».

совет как отладить / решить эту проблему?

1 Ответ

3 голосов
/ 17 ноября 2010

Есть две проблемы.Первый -

 VARIANT varStreamNames;

- унифицирован, поэтому, когда

varOutNames.Detach(pvarStreamNames);

запускает, он вызывает VariantClear() для неинициализированной переменной, и это приводит к неопределенному поведению - ваша программа падает.

Вы должны вызвать VariantInit() на varStreamNames перед вызовом метода COM или просто использовать CComVariant тип для varStreamNames.

Второй:

CComSafeArray<BSTR, VT_BSTR>    saStreamNames;
CComVariant                     varOutNames;

varOutNames.vt      = VT_ARRAY;
varOutNames.parray  = saStreamNames.m_psa;

выполняет поверхностную копию безопасного массива - теперь и 10101 *, и varOutNames владеют безопасным массивом, и поэтому, когда saStreamNames уничтожается в конце области действия, безопасный массив освобождается.вы скопировали тот же адрес безопасного массива в pvarStreamNames, теперь у вас есть вариант с висящим указателем безопасного массива.Попытка получить доступ к этому безопасному массиву - неопределенное поведение.Вы должны использовать Detach() метод CComSafeArray, чтобы освободить владельца.

...