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

11

你如何将一个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* 是什么?请标记您正在使用的库。 - Lightness Races in Orbit
4个回答

17

一种基于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

根据您的代码,最短的代码片段可能只需要:

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

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


关于 "取决于底层 char 类型" 的评论:该问题特别询问从 std::string 转换,而不是从 std::wstring 或任意的 std::basic_string<T> 转换。 - jamesdlin
@jamesdlin。没错,这是一条普通评论。我会在答案中澄清的。 - Niall
我对这段代码有一些疑虑:CComBSTR temp(stlstr.c_str());。虽然我知道有一个接受 const char*CComBSTR 构造函数,所以这段代码肯定可以编译通过,但我不确定这个构造函数实现了什么样的“代码页”转换。例如,我不认为它会将 UTF-8(std::string 可能的内容)转换为 UTF-16(用于 BSTR)。这种不明确的模糊转换可能会导致国际文本中的微妙错误。我建议使用代码进行显式转换,从 std::string 使用的任何格式转换为 BSTR 的 UTF-16 格式。 - Mr.C64

2

这是完全可能的:

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。 - AaA

2

std::string是由char组成的;BSTR通常是一个基于Unicode UTF-16 wchar_t的字符串,并带有长度前缀。

即使可以使用BSTR作为一个简单的方式来调用字节数组(因为BSTR是带有长度前缀的,所以它可以存储嵌入式NULs),因此潜在地BSTR也可以用于存储非UTF-16文本,但通常的“自然”行为是包含一个Unicode UTF-16 wchar_t-字符串的BSTR

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

要从UTF-8(或其他代码页)转换为UTF-16,您可以使用MultiByteToWideChar()函数。如果源std::string包含UTF-8字符串,则可以使用带有上述API的CP_UTF8代码页值。

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

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

或者,作为更方便的选择,您可以使用ATL的CComBSTR类来包装一个安全的RAII边界中的BSTR,并使用其Detach()方法BSTR作为输出BSTR*参数传递。

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

额外阅读:

Eric的完整BSTR语义指南


另一个选择是_bstr_t类,它作为编译器COM支持类在Visual Studio中提供,如果您不想依赖ATL。 - IInspectable

0
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;

不要忘记在之后释放它。


3
最后一段非常无助,它不是合同。 - Hans Passant
1
我不明白如果resp.body是一个std::string(而不是问题所问的std::wstring),这个方法怎么能起作用。 - jamesdlin
当然,您是正确的。要使用这种方法与std :: string一起使用,必须首先将其转换为Unicode。 - Ari0nhh
代码正在使用std::string。无需使用笨重的数组,而是使用std::vector<wchar_t>。此外,您计算所需缓冲区大小的数学公式是错误的。让MultiByteToWideChar为您计算。 - IInspectable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接