你如何有效地将BSTR复制到wchar_t []?

时间:2008-09-16 13:06:09

标签: c++ com wchar-t bstr

我有一个BSTR对象,我想将其转换为复制到wchar__t对象。棘手的是BSTR对象的长度可能是几千字节到几百千字节。有没有一种有效的方法来复制数据?我知道我可以声明一个wchar_t数组,并总是分配它需要保存的最大可能数据。但是,这意味着为可能只需要几千字节的内容分配数百KB的数据。有什么建议吗?

5 个答案:

答案 0 :(得分:8)

首先,如果您需要做的只是阅读内容,您可能根本不需要做任何事情。 BSTR类型是指向以null结尾的wchar_t数组的指针。实际上,如果检查标题,您会发现BSTR基本上定义为:

typedef BSTR wchar_t*;

因此,编译器无法区分它们,即使它们具有不同的语义。

有两个重要的警告。

  1. BSTR应该是不可变的。在初始化之后,您永远不应该更改BSTR的内容。如果你“改变它”,你必须创建一个新指针并分配旧指针(如果你拥有它)。
    [更新:这不是真的;抱歉!您可以在适当的位置修改BSTR;我很少有需要。]

  2. 允许BSTR包含嵌入的空字符,而传统的C / C ++字符串则不包含。

  3. 如果您对BSTR的源有相当大的控制权,并且可以保证BSTR没有嵌入的NULL,那么您可以从BSTR读取,就好像它是一个wchar_t并使用传统的字符串方法(wcscpy,等)访问它。如果没有,你的生活就会变得更难。您必须始终将数据操作为更多BSTR,或者作为动态分配的wchar_t数组。大多数与字符串相关的函数都无法正常工作。

    我们假设您控制数据,或者不担心NULL。我们还假设您确实需要制作副本,而不能直接读取现有的BSTR。在这种情况下,你可以这样做:

    UINT length = SysStringLen(myBstr);        // Ask COM for the size of the BSTR
    wchar_t *myString = new wchar_t[lenght+1]; // Note: SysStringLen doesn't 
                                               // include the space needed for the NULL
    
    wcscpy(myString, myBstr);                  // Or your favorite safer string function
    
    // ...
    
    delete myString; // Done
    

    如果你正在为你的BSTR使用类包装器,那么包装器应该有办法为你调用SysStringLen()。例如:

    CComBString    use .Length();
    _bstr_t        use .length();
    

    更新:这是一篇关于这个主题的好文章,其中有一位比我知识渊博的人:
    "Eric [Lippert]'s Complete Guide To BSTR Semantics"

    更新:在示例中用wcscpy()替换了strcpy()

答案 1 :(得分:5)

BSTR对象包含长度前缀,因此找出长度很便宜。找出长度,分配一个足够大的新数组来保存结果,进行处理,并记住在完成后释放它。

答案 2 :(得分:4)

永远不需要转换。 BSTR指针指向字符串的第一个字符,它以空值终止。长度存储在内存中的第一个字符之前。 BSTR始终是Unicode(UTF-16 / UCS-2)。在一个阶段有一个称为“ANSI BSTR”的东西 - 遗留API中有一些参考 - 但你可以在当前的开发中忽略它们。

这意味着您可以安全地将BSTR传递给期望wchar_t的任何功能。

在Visual Studio 2008中,您可能会收到编译器错误,因为BSTR被定义为指向unsigned short的指针,而wchar_t是本机类型。您可以投放或关闭wchar_t符合/Zc:wchar_t

答案 3 :(得分:3)

要记住的一件事是BSTR字符串可以并且经常包含嵌入的空值。 null并不意味着字符串的结尾。

答案 4 :(得分:0)

使用ATL和CStringT然后你可以使用赋值运算符。或者您可以使用USES_CONVERSION宏,这些宏使用堆分配,因此您将确保不会泄漏内存。