How to compare BSTR against a string in c/c++?
Asked Answered
M

5

14
wprintf(L"Selecting Audio Input Device: %s\n", 
                            varName.bstrVal);

if(0 == strcmp(varName.bstrVal, "IP Camera [JPEG/MJPEG]"))...

The above reports :

error C2664: 'strcmp' : cannot convert parameter 1 from 'BSTR' to 'const char *'
Monomania answered 13/9, 2010 at 13:22 Comment(0)
R
23

You have to use wcscmp instead:

if(0 == wcscmp(varName.bstrVal, L"IP Camera [JPEG/MJPEG]"))
{
}

Here is a description of the BSTR data type, it has a length prefix and a real string part which is just an array of WCHAR characters. It also has 2 NULL terminators.

The only thing to look out for is that the BSTR data type can contain embedded NULLs in the string portion, so wcscmp will only work in the cases where the BSTR does not contain embedded NULLs (which is probably most cases).

Redmer answered 13/9, 2010 at 13:26 Comment(3)
Why some functions are prefixed with w while some are wc?Monomania
@COMer: I'm not sure but wcs stands for wide character string.Redmer
@COMer: I'm guessing "str" gets replaced with "wcs" (e.g. strcmp -> wcscmp, strdup -> wcsdup), but functions without "str" get a "w" inserted somewhere (e.g. printf -> wprintf, fopen -> _wfopen).Retrace
M
1

As a richer alternative to the C runtime, you could use the Unicode CompareString or CompareStringEx APIs in Win32. If you don't have charset issues to consider, wcscmp is fine though.

Maineetloire answered 13/9, 2010 at 13:30 Comment(0)
K
0

My solution:

static const std::wstring IPCamera = L"IP Camera [JPEG/MJPEG]";
if (varName.bstrVal == IPCamera {
  //...
Kristopher answered 25/11, 2011 at 11:36 Comment(1)
Trying that failed for me. The example is missing a right parenthesis, which I corrected (it compiled), but the logic does not see two identical strings as equal.Bowls
H
0

All other answers here are either outright wrong or partially incorrect because they are ignoring the fact that both BSTR and std::wstring can contain multiple embedded null characters.

That means they should not be compared using wcscmp(), which will stop comparison on the first \0 it encounters in either string.

Here is how to properly compare BSTR with std::wstring:

// Windows.h defines min() and max() as macros
#define NOMINMAX

#include <Windows.h>
#include <string>

// std::string_literals namespace requires C++14,
// but it is needed only to construct strings with
// embedded nulls, not for the comparison itself
using namespace std::string_literals;

int wmain(int argc, wchar_t *argv[])
{
    std::wstring    String1 = L"I am a happy BSTR \0with \0embedded \0null chars"s;
    std::wstring    Temp = L"I am a happy bstr \0with \0embedded \0NULL chars"s;
    BSTR            String2 = SysAllocStringLen(Temp.c_str(), Temp.size());

    if (String2 == nullptr) {
        return ERROR_OUTOFMEMORY;
    }

    // make sure not to create a security vulnerability by
    // reading past the end of either buffer when comparing
    const size_t MaxCount = std::min(String1.size(), static_cast<size_t>(SysStringLen(String2)));

    bool Equal = wcsncmp(String1.c_str(), String2, MaxCount) == 0;

    if (Equal) {
        wprintf(L"Strings are equal\n");
    } else {
        wprintf(L"Strings are NOT equal\n");
    }

    SysFreeString(String2);

    return 0;
}

Note that the example will print "Strings are NOT equal" unless you change it to use _wcsnicmp() for case-insensitive comparison.

Hirst answered 25/2, 2022 at 13:35 Comment(0)
T
-1

I always construct _bstr_t wrappers around BSTRs. It makes things quite a bit easier and more idiomatic:

if(std::string("IP Camera [JPEG/MJPEG]") ==
                   static_cast<const char*>( _bstr_t(varName.bstrVal) )
{
}
Tadio answered 13/9, 2010 at 13:44 Comment(2)
Not such a great idea: the _bstr_t constructor makes a full-length copy of the string in varName.bstrVal.Lais
This also does a run-time conversion of the bstr from unicode to ANSI, which is unnecessary since you could just compare against a unicode literal in the first place.Augustusaugy

© 2022 - 2024 — McMap. All rights reserved.