简体   繁体   中英

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

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 *'

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).

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.

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) )
{
}

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.

My solution:

static const std::wstring IPCamera = L"IP Camera [JPEG/MJPEG]";
if (varName.bstrVal == IPCamera {
  //...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM