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 包装器?

更新

感谢所有以任何方式帮助我的人!正因为没有人解决BSTRstd::string 之间转换的问题,所以我想在这里提供一些关于如何做到这一点的线索。

以下是我用来分别将BSTR 转换为std::stringstd::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】:

BSTRstd::wstring:

// given BSTR bs
assert(bs != nullptr);
std::wstring ws(bs, SysStringLen(bs));

 std::wstringBSTR

// 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 的情况下查询该长度。 NULLBSTR有效 状态,相当于一个空字符串。所以代码应该是std::wstring(bs ? bs : L""); 语义没有混淆。 NULL BSTR 在语义上与空的 BSTR 相同。这很容易映射到std::wstring。构造一个空的std::wstringNULL 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::wstringstd::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 库中找到执行此操作以及操作结果字符串的辅助方法。

【讨论】:

这会截断任何包含空字符的字符串,即使BSTRstd::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>

文件到 std::string_view