如何使用CompareString函数,因此它适用于Windows XP和Windows 7

时间:2013-07-02 11:22:59

标签: winapi windows-7 string-comparison windows-xp-sp3

我有一个基于Windows 7 SP1 Visual Studio 2010 SP1构建的应用程序。

似乎CompareString在Windows 7和Windows XP上的工作方式不同。我正在创建EndsWith / StartsWith - 类似(请参阅C#String.EndsWith)方法,但它在Windows 7上按预期工作,但不在Windows XP上。

以下是我的StartsWithEndsWith

bool String::StartsWith( const String& value, bool bCaseSensitive ) const
{
    if(this->strLen == 0 || value.strLen == 0)
        return false;

    DWORD flags;
    if(bCaseSensitive == false)
        flags = LINGUISTIC_IGNORECASE;
    else
        flags = NORM_LINGUISTIC_CASING;

    if( CSTR_EQUAL == CompareStringW(LOCALE_USER_DEFAULT, flags, this->_str, static_cast<int>(value.strLen), value._str, static_cast<int>(value.strLen)) )
        return true;
    else if(CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, flags, this->_str, static_cast<int>(value.strLen), value._str, static_cast<int>(value.strLen)))
        return true;
    else if(CSTR_EQUAL == CompareStringW(GetThreadLocale(), flags, this->_str, static_cast<int>(value.strLen), value._str, static_cast<int>(value.strLen)))
        return true;
    else
        return false;
}

bool String::EndsWith( const String& value, bool bCaseSensitive ) const
{
    if(this->strLen == 0 || value.strLen == 0)
        return false;

    DWORD flags;
    if(bCaseSensitive == false)
        flags = LINGUISTIC_IGNORECASE;
    else
        flags = NORM_LINGUISTIC_CASING;

    size_t maxLen;
    if(this->strLen < value.strLen)
        maxLen = this->strLen;
    else
        maxLen = value.strLen;

    LPCWSTR szStartOffset;

    if(maxLen == this->strLen)
        szStartOffset = this->_str;
    else
        szStartOffset = (this->_str + (this->strLen - value.strLen));

    if( CSTR_EQUAL == CompareStringW(LOCALE_USER_DEFAULT, flags, szStartOffset, static_cast<int>(maxLen), value._str, static_cast<int>(maxLen)) )
        return true;
    else if(CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, flags, szStartOffset, static_cast<int>(maxLen), value._str, static_cast<int>(maxLen)))
        return true;
    else if(CSTR_EQUAL == CompareStringW(GetThreadLocale(), flags, szStartOffset, static_cast<int>(maxLen), value._str, static_cast<int>(maxLen)))
        return true;
    else
        return false;
}

如果有人能帮助我,我会非常感激。

1 个答案:

答案 0 :(得分:1)

所以有各种各样的事情。

首先,CompareString在出错时返回0,正如您所看到的,我不会检查它。在Windows XP上,它确实失败了,并且GetLastError()设置为1004 =“无效标志。”。错误是下一期的线索。

其次,我总是使用一个标志或另一个标志,而在Windows XP上,NORM_LINGUISTIC_CASING会导致1004错误。由于此函数的默认行为区分大小写,因此大部分时间并非真正需要此标志,并且标志可以设置为0.

我创建了一个实现StartsWith的演示程序: stringtest.cpp

// cl /MTd /DUNICODE /D_UNICODE_ stringtest.cpp
// MTd  - statically compile libcrt to binary, this way you don't have to copy msvcrtd100.dll etc to the XP machine.

#include <windows.h>
#include <cstdio>

int StartsWith(LCID locale, const WCHAR* szOrg, const WCHAR* szValue, bool sensitive, bool expected /* Can be used for asserts. */)
{
    int retval(0)
    DWORD flags = sensitive ? 0 : NORM_IGNORECASE; // You could replace 0 with NORM_LINGUISTIC_CASING to make it fail on Windows XP.

    int cchValue = lstrlenW(szValue);

    // if szOrg can't hold szValue, it doesn't start with szValue.
    if( cchValue > lstrlenW(szOrg) )
        return CSTR_LESS_THAN;

    // We trick CompareString to think szOrg is the same length as szValue.
    // This is how we check only the cchValue first characters of szOrg.
    retval = CompareStringW(locale, flags, szOrg, cchValue, szValue, cchValue);

    // You could assert on retval and parameter 'expected '.

    return(retval);
}

// Some compiler magic..
#define SHOWBOOL(expr)  { \
                            int ret = expr; \
                            DWORD gle=GetLastError(); /* Cache GLE in case printf changes it. */ \
                            printf( "%s = %s\r\n", ( ret == CSTR_EQUAL ? "true" : "false"), #expr ); \
                            printf("GetLastError() = %d - ret = %d\r\n\r\n", gle, ret); \
                        }

// Named this way since we get the expression to console, easier to read.
bool ExpectsTrue = true;
bool ExpectsFalse = false;

bool Sensitive = true;
bool Insensitive = false;

int main(int argc, WCHAR* argv[])
{
    SHOWBOOL( StartsWith(LOCALE_USER_DEFAULT, L"Hello World", L"Hello", Sensitive, ExpectsTrue) );
    SHOWBOOL( StartsWith(LOCALE_USER_DEFAULT, L"Hello World", L"hello", Sensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(LOCALE_USER_DEFAULT, L"Hello World", L"hello", Insensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(LOCALE_USER_DEFAULT, L"Hello World", L"1Hello", Sensitive, ExpectsFalse) );

    SHOWBOOL( StartsWith(LOCALE_SYSTEM_DEFAULT, L"Hello World", L"Hello", Sensitive, ExpectsTrue) );
    SHOWBOOL( StartsWith(LOCALE_SYSTEM_DEFAULT, L"Hello World", L"hello", Sensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(LOCALE_SYSTEM_DEFAULT, L"Hello World", L"hello", Insensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(LOCALE_SYSTEM_DEFAULT, L"Hello World", L"1Hello", Sensitive, ExpectsFalse) );

    SHOWBOOL( StartsWith(GetThreadLocale(), L"Hello World", L"Hello", Sensitive, ExpectsTrue) );
    SHOWBOOL( StartsWith(GetThreadLocale(), L"Hello World", L"hello", Sensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(GetThreadLocale(), L"Hello World", L"hello", Insensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(GetThreadLocale(), L"Hello World", L"1Hello", Sensitive, ExpectsFalse) );

    SHOWBOOL( StartsWith(GetSystemDefaultLCID(), L"Hello World", L"Hello", Sensitive, ExpectsTrue) );
    SHOWBOOL( StartsWith(GetSystemDefaultLCID(), L"Hello World", L"hello", Sensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(GetSystemDefaultLCID(), L"Hello World", L"hello", Insensitive, ExpectsFalse) );
    SHOWBOOL( StartsWith(GetSystemDefaultLCID(), L"Hello World", L"1Hello", Sensitive, ExpectsFalse) );

    return(NO_ERROR);
}