代码如下所示:
class A
{
public:
std::string name;
};
A a;
CComBSTR textValue;
// some function which fills textValue
a.name = W2A(textValue);
现在,我已经使用了 CComBSTR,因此我不必释放 BString,但是 W2A 是否分配我可能需要处理的任何内存?即我应该:
char *tmp = W2A(textValue);
a.name = tmp;
// do something to deallocate tmp?
对于 W2A/A2W 宏要非常谨慎。它们是通过“alloca”(直接在堆栈上动态分配)实现的。在涉及循环/递归/长字符串的某些情况下,您将得到“stackoverflow”(不是开玩笑)。
推荐的方法是使用“新”助手模板。请参阅 ATL 和 MFC 字符串转换宏
A a;
CComBSTR textValue;
// some function which fills textValue
CW2A pszValue( textValue );
a.name = pszValue;
转换使用 128 字节的常规“堆栈中”缓冲区。如果它太小,则会自动使用堆。您可以直接使用模板类型来调整权衡
A a;
CComBSTR textValue;
// some function which fills textValue
CW2AEX<32> pszValue( textValue );
a.name = pszValue;
不用担心:您只是减少了堆栈使用量,但如果 32 字节不够,则会使用堆。正如我所说,这是一种权衡。如果您不介意,请使用
CW2A
。
无论哪种情况,都不需要清理:-)
请注意,当 pszValue 超出范围时,任何待转换的 char* 可能会指向垃圾。请务必阅读“示例 3 转换宏的错误使用”。以及上面链接中的“关于临时类实例的警告”。
如果展开
W2A
宏,您将看到它调用 wcslen()
函数来确定传入字符串的长度。它还调用 AtlW2AHelper
方法,该方法接受以 null 结尾的宽字符串作为参数。这两个函数都会有效地将转换后的字符串的长度限制为遇到的第一个 null。如果您的 BSTR 字符串中间不包含嵌入的空值,那么 W2A
应该没问题。
Microsoft 文章 ATL 和 MFC 字符串转换宏 指出:
要从 BSTR 转换,请使用 COLE2[C]DestinationType[EX],例如 COLE2T.
还指出:
对于 OLE 字符串转换,仅 COLE2T 和 CT2OLE(以及 COLE2CT、COLE2TEX、COLE2CTEX、CT2COLE、CT2OLEEX 和 CT2COLEEX)是 支持的。有关详细信息,请参阅 atlconv.h。
但是您不能真正坚持使用 OLE 字符串转换为 ANSI 的建议。当目的地类型为
T
时,例如COLE2T
,并且定义了 _UNICODE
,则转换就好像 T
是 W
(宽字符串)。 COLE2A
宏未在AtlConv.h
中定义,OLE2A
相当于此头文件中的W2A
。因此,您仍然无法转换包含嵌入空值的字符串。
请参阅堆栈溢出线程 在 C/C++ 中将 BSTR 参数转换为 ANSI 的更好代码是什么? 有关于此的更多讨论。
或者您可以循环遍历源
BSTR
中的字符,并将每个单独的 wchar_t
转换为目标 char
中相应索引位置处的 std::string
。您再次需要通过在 BSTR
上调用 SysStringLen()
来预先确定 BSTR
字符串长度。您可以通过这种方式保留字符串中间的任何嵌入空值,但您必须处理高于 255 的宽字符到 ANSI 范围内的通用字符的转换。