1

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

CompareString在 Windows 7 和 Windows XP 上的工作方式似乎不同。我正在创建一个 EndsWith/ StartsWith-like (参见 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;
}

如果有人可以帮助我,我将不胜感激。

4

1 回答 1

1

所以有一个组合。

首先,CompareString 出错时返回 0,如您所见,我不检查它。在 Windows XP 上,它确实失败了,并且 GetLastError() 设置为 1004 = "Invalid flags."。该错误是下一个问题的线索。

其次,我总是使用一个或另一个标志,在 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);
}
于 2013-07-02T12:48:14.087 回答