【问题标题】:How would you convert a std::string to BSTR*?如何将 std::string 转换为 BSTR*?
【发布时间】:2015-09-27 15:16:26
【问题描述】:

如何将std::string 转换为BSTR*

STDMETHODIMP CMyRESTApp::rest(BSTR data, BSTR* restr)
{
    RESTClient restclient;
    RESTClient::response resp = restclient.get(data);

    Log("Response Status code: %s", resp.code);
    Log("Response Body: %s", resp.body);

    *restr = // here
    return S_OK;
}

我需要转换 resp.body,然后在此处返回 *restr

【问题讨论】:

  • 视情况而定。什么是BSTR*?标记您正在使用的库。

标签: c++ winapi bstr


【解决方案1】:

基于 ATL 的方法是使用ATL::CComBSTR,然后使用Detach()(或CopyTo(...))将结果CComBSTR 转换为BSTR*

类似:

CComBSTR temp(stlstr.c_str());
*restr = temp.Detach();

一般情况下,对于std::basic_string,您可以使用Win32 API Sys* 系列函数,例如SysAllocStringByteLenSysAllocString

// For the `const char*` data type (`LPCSTR`);
*restr = SysAllocStringByteLen(stlstr.c_str(), stlstr.size());

// More suitable for OLECHAR
*restr = SysAllocString(stlwstr.c_str());

OLECHAR取决于目标平台,但一般是wchar_t

鉴于您的代码,最短的 sn-p 可能是;

*restr = SysAllocStringByteLen(resp.body.c_str(), resp.body.size());

注意这些 Windows API 函数使用“通常”的 Windows 代码页转换,如果需要,请参阅 MSDN 文档了解如何控制它。

【讨论】:

  • 关于“取决于底层字符类型”评论:该问题专门询问关于从std::string 转换,而不是从std::wstring 或任意std::basic_string<T> 转换。
  • @jamesdlin。正确,这是一般性评论。我会在答案中澄清这一点。
  • 我对这段代码有些担心:CComBSTR temp(stlstr.c_str());。虽然我知道有一个CComBSTR 构造函数采用const char*,所以这段代码肯定会编译,但我不确定这个构造函数实现了什么样的“代码页”转换。例如,我不相信它会从 UTF-8(std::string 的可能内容)转换为 UTF-16(BSTR)。那些不明确的模棱两可的转换可能会导致国际文本出现细微的错误。我建议使用从std::string 使用的任何格式显式转换BSTR 的UTF-16 的代码。
【解决方案2】:

std::stringchars 制作; BSTR 通常是基于 Unicode UTF-16 wchar_t 的字符串,带有长度前缀。

即使可以使用BSTR 作为编组字节数组的简单方法(因为BSTR 是长度前缀的,因此它可以存储嵌入的NUL),因此可能会使用BSTR为了存储非 UTF-16 文本,BSTR 通常的“自然”行为是包含 Unicode UTF-16 wchar_t-string

所以,第一个问题是澄清std::string 使用什么样的编码(例如:Unicode UTF-8?还是其他代码页?)。然后你必须将该字符串转换为 Unicode UTF-16,并创建一个包含该 UTF-16 字符串的BSTR

要将 UTF-8(或其他代码页)转换为 UTF-16,您可以使用 MultiByteToWideChar() function。如果源 std::string 包含 UTF-8 字符串,则可以将 CP_UTF8 代码页值与上述 API 一起使用。

获得 UTF-16 转换后的字符串后,您可以使用它创建一个 BSTR,并将其作为输出 BSTR* 参数传递。

创建BSTR 的主要Win32 API 是SysAllocString()。还有一些变体可以指定字符串长度。

或者,作为更方便的替代方法,您可以使用 ATL 的 CComBSTR 类将 BSTR 包装在安全的 RAII 边界中,并使用其 Detach() methodBSTR 作为输出 BSTR* 参数传递.

CComBSTR bstrResult( /* UTF-16 string from std::string */ );
*restr = bstrResult.Detach();

额外阅读:

Eric's Complete Guide To BSTR Semantics

【讨论】:

【解决方案3】:

这很有可能:

std::string singer("happy new year 2016");
_bstr_t sa_1(singer.c_str()); //std::string to _bstr_t
_bstr_t sa_2("Goodbye 2015"); 
std::string kapa(sa_2); //_bstr_t to std::string

【讨论】:

  • 你如何将 _bstr_t 转换为 BSTR?问题是询问 std::string 到 BSTR
【解决方案4】:
size_t sztBuffer = (resp.body.length() + 1) * sizeof(wchar_t);
wchar_t* pBuffer = new wchar_t[resp.body.length() + 1];
ZeroMemory(&pBuffer[0], sztBuffer);
MultiByteToWideChar(CP_ACP, 0, resp.body.c_str(), resp.body.length(), pBuffer, sString.length());    
SysAllocString((OLECHAR*)pBuffer);
delete[] pBuffer;

之后不要忘记释放它。

【讨论】:

  • 最后一段很没用,不是合同。
  • 你当然是对的。要将此方法与 std::string 一起使用,必须先将其转换为 Unicode。
  • 代码使用std::string。无需不使用std::vector<wchar_t>,而是使用笨重的数组。另外,您计算所需缓冲区大小的数学是错误的。让MultiByteToWideChar 帮你算算。
猜你喜欢
  • 2016-02-14
  • 1970-01-01
  • 2012-11-23
  • 1970-01-01
  • 2015-01-07
  • 2016-01-28
相关资源
最近更新 更多