6

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

4

5 回答 5

10

First, you might not actually have to do anything at all, if all you need to do is read the contents. A BSTR type is a pointer to a null-terminated wchar_t array already. In fact, if you check the headers, you will find that BSTR is essentially defined as:

typedef BSTR wchar_t*;

So, the compiler can't distinguish between them, even though they have different semantics.

There is are two important caveat.

  1. BSTRs are supposed to be immutable. You should never change the contents of a BSTR after it has been initialized. If you "change it", you have to create a new one assign the new pointer and release the old one (if you own it).
    [UPDATE: this is not true; sorry! You can modify BSTRs in place; I very rarely have had the need.]

  2. BSTRs are allowed to contain embedded null characters, whereas traditional C/C++ strings are not.

If you have a fair amount of control of the source of the BSTR, and can guarantee that the BSTR does not have embedded NULLs, you can read from the BSTR as if it was a wchar_t and use conventional string methods (wcscpy, etc) to access it. If not, your life gets harder. You will have to always manipulate your data as either more BSTRs, or as a dynamically-allocated array of wchar_t. Most string-related functions will not work correctly.

Let's assume you control your data, or don't worry about NULLs. Let's assume also that you really need to make a copy and can't just read the existing BSTR directly. In that case, you can do something like this:

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

If you are using class wrappers for your BSTR, the wrapper should have a way to call SysStringLen() for you. For example:

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

UPDATE: This is a good article on the subject by someone far more knowledgeable than me:
"Eric [Lippert]'s Complete Guide To BSTR Semantics"

UPDATE: Replaced strcpy() with wcscpy() in example

于 2008-09-16T15:59:55.610 回答
5

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

于 2008-09-16T13:10:07.407 回答
4

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

这意味着您可以将 aBSTR安全地传递给任何期望 a 的函数wchar_t

在 Visual Studio 2008 中,您可能会遇到编译器错误,因为BSTR它被定义为指向 的指针unsigned short,而wchar_t它是本机类型。您可以强制转换或关闭wchar_t/Zc:wchar_t.

于 2008-09-16T14:16:21.490 回答
3

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

于 2008-09-16T14:25:07.150 回答
0

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

于 2008-09-16T13:12:59.273 回答