Итерация через VARIANT/SAFEARRAY BSTR для присвоения значений и печати на консоль в C++

Я пытаюсь заполнить SAFEARRAY из 10 индексов типа BSTR со значением «тест» и распечатать для консоли значение каждого индекса SAFEARRAY после того, как он был назначен для проверки правильности. Я запустил отладчик и получил следующие значения для первых 5 индексов (мой SAFEARRAY называется sa). Каким-то образом я неправильно повторяю SAFEARRAY или использую неправильные типы, каждый индекс должен быть «тестовым». Любые советы о том, что я делаю неправильно?

sa[0] = "test"
sa[1] = "est"
sa[2] = "st"
sa[3] = "t"
sa[4] = ""

....

#include <iostream>
#include <string>
#include <Windows.h>
#include <atlbase.h>
#include <comutil.h>
#include <string.h>
#include <stdio.h>

using namespace std;

void fillVariant(VARIANT& varIn, BSTR &srcArray);

int main()
{

    BSTR *theArray = new BSTR[10];
    for(int i = 0 ; i < 10; i++)
    {

        theArray[i] = SysAllocString(L"test");
    }

    VARIANT variantArray;
    fillVariant(variantArray, *theArray);


    return 0;
}

void fillVariant(VARIANT& varIn, BSTR &srcArray)
{
    VARIANT *variantArray = &varIn;
    VariantInit(variantArray);
    variantArray->vt = VT_ARRAY|VT_BSTR;

    SAFEARRAY* sa;
    SAFEARRAYBOUND aDim[1]; 
    aDim[0].lLbound = 0; 
    aDim[0].cElements = 10;

    sa = SafeArrayCreate(VT_BSTR, 1, aDim);

    BSTR* dwArray = NULL;
    SafeArrayAccessData(sa, (void**)&dwArray);

    for(int i = 0; i < 10; i++)
    {
        dwArray[i] = &srcArray[i];

        BSTR tmp = (BSTR) dwArray[i];
        std::wstring ws(tmp);
        //std::wstring ws(*dwArray[i], SysStringLen(dwArray[i]));
        std::wcout << ws << endl;

    }
    SafeArrayUnaccessData(sa);
    variantArray->parray = sa;
}

person shane01101    schedule 28.07.2014    source источник
comment
Должны ли вы использовать сырой SAFEARRAY? CComSafeArray предоставляет оболочку, которую гораздо проще использовать.   -  person lcs    schedule 29.07.2014
comment
Вы должны использовать SafeArrayPutElement, чтобы поместить элемент в SAFEARRAY.   -  person Matt    schedule 29.07.2014
comment
BSTR *theArray = new BSTR[10]; можно упростить до BSTR theArray[10];   -  person M.M    schedule 29.07.2014


Ответы (2)


Вы неправильно заполняете VARIANT. Попробуйте это вместо этого:

#include <iostream>
#include <string>
#include <Windows.h>
#include <atlbase.h>
#include <comutil.h>
#include <string.h>
#include <stdio.h>

using namespace std;

void fillVariant(VARIANT& varIn, BSTR *srcArray, int srcArrayLen);

int main()
{
    BSTR *theArray = new BSTR[10];
    for(int i = 0 ; i < 10; i++)
    {
        theArray[i] = SysAllocString(L"test");
    }

    VARIANT variantArray;
    fillVariant(variantArray, theArray, 10);

    // don't forget to free memory when done!
    // note: the VARIANT owns the BSTRs, so DON'T free them!
    VariantClear(&variantArray);
    delete[] theArray;

    return 0;
}

void fillVariant(VARIANT& varIn, BSTR *srcArray, int srcArrayLen)
{
    VARIANT *variantArray = &varIn;
    VariantInit(variantArray);

    SAFEARRAYBOUND aDim[1]; 
    aDim[0].lLbound = 0; 
    aDim[0].cElements = srcArrayLen;

    SAFEARRAY* sa = SafeArrayCreate(VT_BSTR, 1, aDim);
    if (sa)
    {    
        BSTR* dwArray = NULL;
        SafeArrayAccessData(sa, (void**)&dwArray);

        for(int i = 0; i < srcArrayLen; i++)
        {
            // note: passing ownership, NOT making a copy
            dwArray[i] = srcArray[i];

            //std::wstring ws(dwArray[i], SysStringLen(dwArray[i]));
            std::wcout << dwArray[i] << endl;
        }

        SafeArrayUnaccessData(sa);

        variantArray->vt = VT_ARRAY|VT_BSTR;
        variantArray->parray = sa;
    }
}

В качестве альтернативы:

#include <iostream>
#include <string>
#include <Windows.h>
#include <atlbase.h>
#include <comutil.h>
#include <string.h>
#include <stdio.h>

using namespace std;

void fillVariant(VARIANT& varIn, BSTR *srcArray, int srcArrayLen);

int main()
{
    BSTR *theArray = new BSTR[10];
    for(int i = 0 ; i < 10; i++)
    {
        theArray[i] = SysAllocString(L"test");
    }

    VARIANT variantArray;
    fillVariant(variantArray, theArray, 10);

    // don't forget to free memory when done!

    VariantClear(&variantArray);

    // note: the VARIANT DOES NOT own the BSTRs, so DO free them!
    for(int i = 0 ; i < 10; i++)
    {
        SysFreeString(theArray[i]);
    }
    delete[] theArray;

    return 0;
}

void fillVariant(VARIANT& varIn, BSTR *srcArray, int srcArrayLen)
{
    VARIANT *variantArray = &varIn;
    VariantInit(variantArray);

    SAFEARRAYBOUND aDim[1]; 
    aDim[0].lLbound = 0; 
    aDim[0].cElements = srcArrayLen;

    SAFEARRAY* sa = SafeArrayCreate(VT_BSTR, 1, aDim);
    if (sa)
    {    
        for(LONG i = 0; i < srcArrayLen; i++)
        {
            // note: makes a copy, DOES NOT pass ownership!
            SafeArrayPutElement(sa, &i, srcArray[i]);

            //std::wstring ws(srcArray[i], SysStringLen(srcArray[i]));
            std::wcout << srcArray[i] << endl;
        }

        variantArray->vt = VT_ARRAY|VT_BSTR;
        variantArray->parray = sa;
    }
}
person Remy Lebeau    schedule 28.07.2014

&srcArray[i] делает не то, что вы думаете. srcArray — это один BSTR, который является определением типа для WCHAR*. Это не массив из BSTRs. srcArray[i] относится к i символу в theArray[0], а &srcArray[i] — это адрес этого символа. Вот как вы получили «тест», «эст» и так далее.

Пусть fillVariant принимает BSTR* в качестве второго параметра и передает theArray, а не *theArray.

Кстати говоря, ваша программа пропускает кучу BSTRs и SAFEARRAY.

person Igor Tandetnik    schedule 28.07.2014