我有一个BSTR对象,我想将其转换为复制到wchar__t对象。棘手的是BSTR对象的长度可能是几千字节到几百千字节。有没有一种有效的方法来复制数据?我知道我可以声明一个wchar_t数组,并总是分配它需要保存的最大可能数据。但是,这意味着为可能只需要几千字节的内容分配数百KB的数据。有什么建议吗?
答案 0 :(得分:8)
首先,如果您需要做的只是阅读内容,您可能根本不需要做任何事情。 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]'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宏,这些宏使用堆分配,因此您将确保不会泄漏内存。