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

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

请先 登录 后评论

5 个回答

moonshadow

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

请先 登录 后评论
titanae

使用ATL和CStringT然后你就可以使用赋值操作符了。或者你可以使用USES_CONVERSION宏,它们使用堆分配,所以你会确保你不会泄漏内存。

请先 登录 后评论
Mike Dimmick

没有任何转换的必要。一个 BSTR 指针指向字符串的第一个字符,并且以空结尾。长度存储在内存中的第一个字符之前。 BSTRs总是Unicode (UTF-16/UCS-2)。有一个阶段被称为“ANSI BSTR”——在遗留api中有一些引用——但在当前的开发中你可以忽略这些。

这意味着你可以通过a BSTR 可以安全地执行任何功能 wchar_t

在Visual Studio 2008中,你可能会得到一个编译错误,因为 BSTR 定义为指向 unsigned short,而 wchar_t 是原生类型。您可以强制施放或关闭 wchar_t 遵守 /Zc:wchar_t

请先 登录 后评论
Nemanja Trifunovic

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

请先 登录 后评论
Euro Micelli

首先,如果您所需要做的只是阅读内容,那么实际上您可能根本不需要做任何事情。BSTR类型已经是一个指向以空结尾的wchar_t数组的指针。事实上,如果你检查头文件,你会发现BSTR本质上被定义为:

typedef BSTR wchar_t*;

所以,编译器不能区分它们,即使它们有不同的语义。

这里有两个重要的警告。

  1. bstr应该是不可变的。在BSTR已经初始化之后,您不应该更改它的内容。如果你“改变它”,你必须创建一个新的分配新的指针和释放旧的(如果你拥有它)。
    [更新:这不是真的;对不起!你可以就地修改BSTRs;我很少有这种需要。]

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

如果您对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()。例如:

3.

更新:这是一篇关于这个主题的好文章,作者比我知识渊博得多:
Eric [Lippert]的BSTR语义完整指南

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

请先 登录 后评论