我们如何有效地将BSTR复制到wchar_t []?
我有一个BSTR对象,我想将其转换为复制到wchar__t对象。棘手的事情是BSTR对象的长度可能在几千字节到几百千字节之间。有没有一种有效的方式来复制数据?我知道我可以声明一个wchar_t数组并始终分配它可能需要保存的最大可能数据。但是,这将意味着为可能只需要几千字节的数据分配几百千字节的数据。有什么建议?
解决方案
回答
BSTR对象包含一个长度前缀,因此找出长度很便宜。找出长度,分配一个足够大的新数组以容纳结果,对其进行处理,并记住在完成操作后将其释放。
回答
使用ATL和CStringT,则可以只使用赋值运算符。或者,我们可以使用USES_CONVERSION宏,这些宏使用堆分配,因此可以确保不会泄漏内存。
回答
永远不需要转换。 " BSTR"指针指向字符串的第一个字符,并且以空字符结尾。该长度存储在内存中第一个字符之前。 BSTR始终是Unicode(UTF-16 / UCS-2)。在某个阶段,有一种称为" ANSI BSTR"的东西,在旧版API中有一些引用,但是在当前开发中我们可以忽略这些引用。
这意味着我们可以将BSTR安全地传递给任何需要wchar_t的函数。
在Visual Studio 2008中,我们可能会遇到编译器错误,因为" BSTR"被定义为" unsigned short"的指针,而" wchar_t"是本机类型。我们可以使用/ Zc:wchar_t强制转换或者关闭wchar_t的合规性。
回答
要记住的一件事是,BSTR
字符串可以并且经常包含嵌入的null。 null并不表示字符串的结尾。
回答
首先,如果我们需要做的只是阅读目录,那么我们可能根本不需要做任何事情。 BSTR类型是已经指向以null终止的wchar_t数组的指针。实际上,如果我们检查标头,就会发现BSTR本质上定义为:
typedef BSTR wchar_t*;
因此,即使它们具有不同的语义,编译器也无法区分它们。
有两个重要警告。
- BSTR应该是不可变的。 BSTR初始化后,切勿更改其内容。如果"更改",则必须创建一个新指针,并为其分配新指针并释放旧指针(如果我们拥有它)。 [更新:这是不正确的;对不起!我们可以就地修改BSTR。我很少有需要。]
- 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()。例如:
CComBString use .Length(); _bstr_t use .length();
更新:这是一篇比我知识渊博的人写的一篇很好的文章:
" Eric [Lippert]的BSTR语义完整指南"
更新:在示例中用wcscpy()替换了strcpy()