遍历 BSTR 的 VARIANT/SAFEARRAY 以在 C++ 中分配值并打印到控制台

Posted

技术标签:

【中文标题】遍历 BSTR 的 VARIANT/SAFEARRAY 以在 C++ 中分配值并打印到控制台【英文标题】:Iterating through a VARIANT/SAFEARRAY of BSTR to Assign Values and Print to Console in C++ 【发布时间】:2014-07-28 21:08:48 【问题描述】:

我正在尝试用值“test”填充 BSTR 类型的 10 个索引的 SAFEARRAY,并在分配 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;

【问题讨论】:

必须使用原始SAFEARRAY 吗? CComSafeArray 提供了一个更易于使用的包装器。 您应该使用 SafeArrayPutElement 将元素放入 SAFEARRAY BSTR *theArray = new BSTR[10]; 可以简化为BSTR theArray[10]; 【参考方案1】:

您没有正确填写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;
    

【讨论】:

【参考方案2】:

&amp;srcArray[i] 不会做你认为的那样。 srcArray 是单个 BSTR,它是 WCHAR* 的 typedef。它不是BSTRs 的数组。 srcArray[i] 指的是theArray[0] 中的第i 个字符,&amp;srcArray[i] 是该字符的地址。这就是你得到“test”、“est”等的方式。

fillVariantBSTR* 作为其第二个参数,并传递theArray,而不是*theArray

在不相关的注释中,您的程序泄漏了一堆BSTRs 和一个SAFEARRAY

【讨论】:

以上是关于遍历 BSTR 的 VARIANT/SAFEARRAY 以在 C++ 中分配值并打印到控制台的主要内容,如果未能解决你的问题,请参考以下文章

使用赋值运算符将 BSTR 初始化为另一个 BSTR

_bstr_t和_variant_t是怎样定义的

释放从 char* 创建的 _bstr_t

_bstr_t 到 UTF-8 可能吗?

BSTR详解

BSTR详解