Reputation: 63806
There's a tried and tested answer here how to convert BSTR
-> std::wstring
. But I want to include the BSTR in a wstringstream
I am building up.
Clearly I can do (a bit contrived as a MRE):
std::wstring proc(BSTR bStr)
{
std::wstringstream ss;
std::wstring ws(bStr, SysStringLen(bStr));
ss << "The string is: " << ws;
return ss.str();
}
But is there a way to avoid creating the temporary ws
object and pipe bStr
in directly?
Upvotes: 0
Views: 157
Reputation: 968
I'll post this as an answer even though it should be a comment (to your own post and the other responses), and it doesn't actually address your question (others correctly have), but just an (off-topic) FYI that a BSTR is not technically a "wchar_t" pointer. It's actually an OLECHAR pointer but since OLECHAR maps to "wchar_t" on modern Windows you can effectively treat it that way (and likely get away with it forever at this point, at least on Windows).
It's therefore a pedantic (really moot) issue at this point (for a very long time now), but to be technically correct (and old-school developers in this stuff often will be), you should be explicitly converting your BSTR to a "wchar_t" pointer (or even TCHAR pointer on Windows) before treating it that way (as a "wchar_t" pointer or whatever TCHAR is for those still using it, normally "wchar_t" as well).
How you do this is off-topic here (ancient MFC has ancient macros for it as one possible way - search for "OLE conversion macros" here), but again, in reality you can safely (usually) get away with just treating it as a "wchar_t" pointer on (modern) Windows as you're now doing (since going through the hoops of explicitly converting it to a "wchar_t" pointer on modern Windows will just treat a BSTR as a "wchar_t" pointer anyway - no conversion necessary and the above MFC macros handle things this way).
If you ever need to target an environment where OLECHAR doesn't map to "wchar_t" however, religiously doing the conversion now will correctly handle things in the future (that's what the conversion is for), compared to how you're now handling it (though most do treat a BSTR as a "wchar_t" pointer these days, though in the context that it's still a BSTR so needs to be treated that way, and even Microsoft itself treats it as a "wchar_t" pointer in some of its own sample code and documentation, but it's still an OLECHAR pointer nevertheless so such code will break if you ever target an environment where OLECHAR doesn't map to "wchar_t").
Upvotes: 0
Reputation: 51496
[I]s there a way to avoid creating the temporary
ws
object and pipebStr
in directly?
Yes, of course!
A BSTR
is a wchar_t*
in disguise that upholds all requirements to make basic_ostream::operator<<
happy: It is guaranteed to be either a nullptr
or a pointer to a sequence of CharT
values, terminated by a NUL
character.
Writing
ss << "The string is: " << bstr;
is perfectly valid.
Albeit, doing so ignores acknowledging two edge cases where a BSTR
is more lenient than a conventional C-style string:
NUL
characters as part of the sequence, leading to truncationnullptr
producing an implementation-defined string in the output streamNeither is desirable, and either issue is addressed by introducing the std::wstring
ws
as an intermediary. This isn't something we can give up. With the intermediary a non-negotiable requirement, the question is: Can we get std::wstring
's services without paying the price of a (needless) allocation?
As of C++17, we can. The tool is called std::wstring_view
, capable of producing "modern" dangling pointers as well as solving the issue at hand:
ss << "The string is: " << std::wstring_view(bstr, ::SysStringLen(bStr));
This brings back the std::wstring
niceties without a price tag.
Upvotes: 1
Reputation: 597315
BSTR
is just a typedef for wchar_t*
as far as the compiler is concerned (it is just allocated differently at runtime than a normal wchar_t
C string).
And by definition, a non-empty BSTR
is always null-terminated (even though it is also length-prefixed).
So, unless your string has embedded nul characters in it (which is possible), you can just use the normal operator<<
for wide strings. Just watch out for the case where the BSTR
is a null pointer, which will exhibit undefined behavior for the operator.
Try this:
std::wstring proc(BSTR bStr)
{
std::wstringstream ss;
ss << L"The string is: ";
if (bStr) ss << bStr;
return ss.str();
}
Upvotes: 2