BSTR 到 std::string (std::wstring) 反之亦然
Posted
技术标签:
【中文标题】BSTR 到 std::string (std::wstring) 反之亦然【英文标题】:BSTR to std::string (std::wstring) and vice versa 【发布时间】:2011-09-11 04:31:20 【问题描述】:在 C++ 中使用 COM 时,字符串通常是 BSTR
数据类型。有人可以使用 BSTR
包装器,例如 CComBSTR
或 MS 的 CString
。但是因为我不能在 MinGW 编译器中使用 ATL 或 MFC,是否有标准代码 sn-p 将BSTR
转换为std::string
(或std::wstring
),反之亦然?
BSTR
是否还有一些类似于 CComBSTR
的非 MS 包装器?
更新
感谢所有以任何方式帮助我的人!正因为没有人解决BSTR
和std::string
之间转换的问题,所以我想在这里提供一些关于如何做到这一点的线索。
以下是我用来分别将BSTR
转换为std::string
和std::string
转换为BSTR
的函数:
std::string ConvertBSTRToMBS(BSTR bstr)
int wslen = ::SysStringLen(bstr);
return ConvertWCSToMBS((wchar_t*)bstr, wslen);
std::string ConvertWCSToMBS(const wchar_t* pstr, long wslen)
int len = ::WideCharToMultiByte(CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL);
std::string dblstr(len, '\0');
len = ::WideCharToMultiByte(CP_ACP, 0 /* no flags */,
pstr, wslen /* not necessary NULL-terminated */,
&dblstr[0], len,
NULL, NULL /* no default char */);
return dblstr;
BSTR ConvertMBSToBSTR(const std::string& str)
int wslen = ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
str.data(), str.length(),
NULL, 0);
BSTR wsdata = ::SysAllocStringLen(NULL, wslen);
::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
str.data(), str.length(),
wsdata, wslen);
return wsdata;
【问题讨论】:
您在 Windows 上使用std::string
而不是 std::wstring
是否有原因?
是的,std::wstring
也会很顺利!问题已更新,感谢您对此发表评论!
为什么windows上有wstring?
@notbad.jpeg :因为在 VC++ 中,wchar_t
是两个字节,而 Windows 的本机编码是 USC-2(或 UTF-16LE,取决于你问的是谁)。因此,wstring
是保存字符串的自然方式,无需在 Windows 上转换为本机编码。
Windows 的本机编码在 Windows 2000 中从 UCS-2 切换到 UTF-16LE。没有“取决于你问谁”。
【参考方案1】:
BSTR
到 std::wstring
:
// given BSTR bs
assert(bs != nullptr);
std::wstring ws(bs, SysStringLen(bs));
std::wstring
到 BSTR
:
// given std::wstring ws
assert(!ws.empty());
BSTR bs = SysAllocStringLen(ws.data(), ws.size());
文档参考:
std::basic_string<typename CharT>::basic_string(const CharT*, size_type)
std::basic_string<>::empty() const
std::basic_string<>::data() const
std::basic_string<>::size() const
SysStringLen()
SysAllocStringLen()
【讨论】:
如果bs
包含null,这不会失败吗?
@ildjam 如果这是一个菜鸟问题,我很抱歉,但我开始在BSTR
上执行“转到定义”(您需要以管理员身份运行 VS)和BSTR
似乎不超过wchar_t*
。另一方面,我还找到了Microsoft's documentation,正如你所说,这个构造函数可以处理嵌入的空字符。如果 BSTR
包含的只是指向 wchar_t
的指针,这个构造函数如何找到它的长度?
@HerrKaputt :因为 BSTR 是在一个特殊的堆上分配的,该堆保留了分配的长度,并允许在给定 BSTR 的情况下查询该长度。
NULL
是BSTR
的有效 状态,相当于一个空字符串。所以代码应该是std::wstring(bs ? bs : L"");
语义没有混淆。 NULL
BSTR
在语义上与空的 BSTR
相同。这很容易映射到std::wstring
。构造一个空的std::wstring
是NULL
BSTR
的唯一正确且明显的转换。【参考方案2】:
你也可以这样做
#include <comdef.h>
BSTR bs = SysAllocString("Hello");
std::wstring myString = _bstr_t(bs, false); // will take over ownership, so no need to free
如果你愿意,也可以使用 std::string
编辑:如果您的原始字符串包含多个嵌入的 \0 这种方法将不起作用。
【讨论】:
此答案不正确,如果您的字符串包含 NULL 字符,则会给出不正确的结果。 在这种情况下,这是 _bstr_t 的问题,尽管我从来没有遇到过任何问题。 目前为止只是_bstr_t
的问题,有点误导。它只是隐式转换为wchar_t*
。它从不声称它指向一个以 null 结尾的字符串。当您将该值传递给 std::wstring
构造函数时,您就会产生问题。这和std::wstring otherstring = something(); std::wstring mystring = otherstring.c_str()
一样错误。
我给出的示例没有错,但是正如您指出的那样,如果 BSTR 包含多个 \0 它将不起作用。毫不奇怪,最糟糕的情况是字符串被截断。【参考方案3】:
有一个名为_bstr_t
的c++ 类。它有有用的方法和重载运算符的集合。
例如,您可以轻松地从const wchar_t *
或const char *
分配,只需执行_bstr_t bstr = L"My string";
然后您可以将其转换回执行const wchar_t * s = bstr.operator const wchar_t *();
。您甚至可以将其转换回常规字符 const char * c = bstr.operator char *();
然后只需使用 const wchar_t *
或 const char *
来初始化新的 std::wstring
或 std::string
。
【讨论】:
好答案!std::string str = _bstr_t(theBSTR);
简单!【参考方案4】:
只需将 BSTR 直接传递给 wstring 构造函数,它与 wchar_t* 兼容:
BSTR btest = SysAllocString(L"Test");
assert(btest != NULL);
std::wstring wtest(btest);
assert(0 == wcscmp(wtest.c_str(), btest));
将 BSTR 转换为 std::string 需要先转换为 char*。这是有损的,因为 BSTR 存储了一个 utf-16 编码的 Unicode 字符串。除非你想用 utf-8 编码。您可以在 ICU 库中找到执行此操作以及操作结果字符串的辅助方法。
【讨论】:
这会截断任何包含空字符的字符串,即使BSTR
和std::wstring
都可以正确存储它们。
如果btest
代表null
也会失败
呃,永远不要避免让您的程序发生意外的 null 崩溃的机会。以上是关于BSTR 到 std::string (std::wstring) 反之亦然的主要内容,如果未能解决你的问题,请参考以下文章
std::vector<std::string> 到 char* 数组
如何使用参数将 std::string 复制到 std::string?
如何摆脱“Intellisense:没有合适的转换函数从“std::string”到“std::string *”存在”错误?
std::move 将 std::string 移动到另一个线程时出错
从‘std::wstring aka std::basic_string<wchar_t>’到非标量类型‘UString aka std::basic_string<char>