How would you convert a std::string to BSTR*?
Asked Answered
K

4

11

How would you convert a std::string to 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;
}

I need convert the resp.body and this then to be returned for the *restr here.

Knighterrant answered 9/7, 2015 at 10:0 Comment(1)
Depends. What is a BSTR*? Tag the library you're using.Bisitun
N
17

An ATL based approach is to use ATL::CComBSTR and then a Detach() (or CopyTo(...)) the resultant CComBSTR to the BSTR*

Something like:

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

Else in general for std::basic_string you can use the Win32 API Sys* family of functions, such as SysAllocStringByteLen and SysAllocString;

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

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

OLECHAR depends on the target platform, but generally it is wchar_t.

Given your code, the shortest snippet could just be;

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

Note these Windows API functions use the "usual" windows code page conversions, please see further MSDN documentation on how to control this if required.

Nitroso answered 9/7, 2015 at 10:8 Comment(3)
Regarding the "depends on underlying char type" comment: the question specifically asks about converting from a std::string, not from a std::wstring or from an arbitrary std::basic_string<T>.Prescience
@jamesdlin. Correct, this was a general comment. I'll clear that up in the answer.Nitroso
I have some concern about this code: CComBSTR temp(stlstr.c_str());. While I know there is a CComBSTR constructor taking a const char*, so this code would certainly compile, I'm not sure what kind of "code page" conversion this constructor implements. For example, I don't believe it converts from UTF-8 (possible content of the std::string) to UTF-16 (for the BSTR). Those kind of unclear ambiguous conversions can cause subtle bugs with international text. I'd suggest using code that does explicit conversions from whatever format the std::string uses to UTF-16 for the BSTR.Irfan
I
2

std::string is made by chars; BSTR is usually a Unicode UTF-16 wchar_t-based string, with a length prefix.

Even if one could use a BSTR as a simple way to marshal a byte array (since the BSTR is length-prefixed, so it can store embedded NULs), and so potentially a BSTR could be used also to store non-UTF-16 text, the usual "natural" behavior for a BSTR is to contain a Unicode UTF-16 wchar_t-string.

So, the first problem is to clarify what kind of encoding the std::string uses (for example: Unicode UTF-8? Or some other code page?). Then you have to convert that string to Unicode UTF-16, and create a BSTR containing that UTF-16 string.

To convert from UTF-8 (or some other code page) to UTF-16, you can use the MultiByteToWideChar() function. If the source std::string contains a UTF-8 string, you can use the CP_UTF8 code page value with the aforementioned API.

Once you have the UTF-16 converted string, you can create a BSTR using it, and pass that as the output BSTR* parameter.

The main Win32 API to create a BSTR is SysAllocString(). There are also some variants in which you can specify the string length.

Or, as a more convenient alternative, you can use the ATL's CComBSTR class to wrap a BSTR in safe RAII boundaries, and use its Detach() method to pass the BSTR as an output BSTR* parameter.

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

Bonus reading:

Eric's Complete Guide To BSTR Semantics

Irfan answered 9/7, 2015 at 11:23 Comment(1)
Another alternative is the _bstr_t Class, available as a Compiler COM Support Class in Visual Studio, if you do not want a dependency on ATL.Merri
L
2

This is very much possible :

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
Logarithmic answered 11/1, 2016 at 9:57 Comment(1)
And how you convert _bstr_t to BSTR? question is asking std::string to BSTRDiscommodity
S
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;

Do not forget to deallocate it afterward.

Surrogate answered 9/7, 2015 at 10:5 Comment(4)
That last paragraph is very unhelpful, it is not the contract.Lucienlucienne
I do not see how this can work if resp.body is a std::string (rather than a std::wstring), which is what the question is asking about.Prescience
You are right of course. To use this approach with std::string it must be converted to Unicode first.Surrogate
The code is using a std::string. No need to not use a std::vector<wchar_t>, instead of the clunky array. Plus, your math for calculating the required buffer size is wrong. Let MultiByteToWideChar do the math for you.Merri

© 2022 - 2024 — McMap. All rights reserved.