开发者

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 [J开发者_运维百科PEG/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.


My solution:

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


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.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜