diff --git a/ThunksList.md b/ThunksList.md index 34f7f82..44734d9 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -530,6 +530,7 @@ | GetCalendarInfoEx | 不存在时,调用GetCalendarInfoW。 | GetNLSVersionEx | 不存在时,返回一个假版本。 | IsNLSDefinedString | 不存在时,调用GetStringTypeW。 +| FindNLSStringEx | 调用 CompareStringW。 | SetProcessWorkingSetSizeEx | 不存在时,调用SetProcessWorkingSetSize。 | GetProcessWorkingSetSizeEx | 不存在时,调用GetProcessWorkingSetSize。 | GetTimeZoneInformationForYear | 不存在时,直接读取`Time Zones`注册表。 diff --git a/src/Thunks/api-ms-win-core-localization.hpp b/src/Thunks/api-ms-win-core-localization.hpp index 3fe00b9..6010e48 100644 --- a/src/Thunks/api-ms-win-core-localization.hpp +++ b/src/Thunks/api-ms-win-core-localization.hpp @@ -2537,4 +2537,145 @@ } #endif + + +#if (YY_Thunks_Target < __WindowsNT6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + kernel32, + 40, + int, + WINAPI, + FindNLSStringEx, + _In_opt_ LPCWSTR _szLocaleName, + _In_ DWORD _fFindNLSStringFlags, + _In_reads_(_cchSource) LPCWSTR _szStringSource, + _In_ int _cchSource, + _In_reads_(_cchValue) LPCWSTR _szStringValue, + _In_ int _cchValue, + _Out_opt_ LPINT _pcchFound, + _In_opt_ LPNLSVERSIONINFO _pVersionInformation, + _In_opt_ LPVOID _pReserved, + _In_opt_ LPARAM _hSortHandle + ) + { + if (auto const _pfnFindNLSStringEx = try_get_FindNLSStringEx()) + { + return _pfnFindNLSStringEx(_szLocaleName, _fFindNLSStringFlags, _szStringSource, _cchSource, _szStringValue, _cchValue, _pcchFound, _pVersionInformation, _pReserved, _hSortHandle); + } + + __WarningMessage__("FindNLSStringEx 暂时只支持搜索 _cchValue 的子字符串。"); + + const DWORD _fFindFlags = _fFindNLSStringFlags & (FIND_STARTSWITH | FIND_ENDSWITH | FIND_FROMSTART | FIND_FROMEND); + if (_fFindFlags & (_fFindFlags - 1)) + { + SetLastError(ERROR_INVALID_FLAGS); + return -1; + } + + if (_pVersionInformation || _pReserved|| _hSortHandle + || _szStringSource == nullptr || _cchSource == 0 || _cchSource < -1 + || _szStringValue == nullptr || _cchValue == 0 || _cchValue < -1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + const auto _Locale = LocaleNameToLCID(_szLocaleName, 0); + if (_Locale == 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + if (_cchSource == -1) + { + _cchSource = wcslen(_szStringSource); + } + + if (_cchValue == -1) + { + _cchValue = wcslen(_szStringValue); + } + + if (_cchSource < _cchValue) + return -1; + + const DWORD _fCmpFlags = _fFindNLSStringFlags & ~(FIND_STARTSWITH | FIND_ENDSWITH | FIND_FROMSTART | FIND_FROMEND); + if ((_fFindNLSStringFlags & (FIND_ENDSWITH | FIND_FROMEND)) == 0) + { + // 从头开始搜索 + if (_fFindNLSStringFlags & FIND_STARTSWITH) + { + const auto _nResult = CompareStringW(_Locale, _fCmpFlags, _szStringSource, _cchValue, _szStringValue, _cchValue); + if (_nResult == CSTR_EQUAL) + { + if (_pcchFound) + *_pcchFound = _cchValue; + + return 0; + } + } + else + { + auto _szStr = _szStringSource; + auto _szStrEnd = _szStringSource + _cchSource - _cchValue + 1; + for (; _szStr != _szStrEnd;++_szStr) + { + const auto _nResult = CompareStringW(_Locale, _fCmpFlags, _szStr, _cchValue, _szStringValue, _cchValue); + if (_nResult == 0) + return -1; + + if (_nResult == CSTR_EQUAL) + { + if (_pcchFound) + *_pcchFound = _cchValue; + + return _szStr - _szStringSource; + } + } + } + } + else + { + // 反向搜索 + auto _szStr = _szStringSource + _cchSource - _cchValue; + if (_fFindNLSStringFlags & FIND_ENDSWITH) + { + const auto _nResult = CompareStringW(_Locale, _fCmpFlags, _szStr, _cchValue, _szStringValue, _cchValue); + if (_nResult == CSTR_EQUAL) + { + if (_pcchFound) + *_pcchFound = _cchValue; + + return _szStr - _szStringSource; + } + } + else + { + for(;; --_szStr) + { + const auto _nResult = CompareStringW(_Locale, _fCmpFlags, _szStr, _cchValue, _szStringValue, _cchValue); + if (_nResult == 0) + return -1; + + if (_nResult == CSTR_EQUAL) + { + if (_pcchFound) + *_pcchFound = _cchValue; + + return _szStr - _szStringSource; + } + + if (_szStr == _szStringSource) + break; + } + } + } + + return -1; + } +#endif } //namespace YY diff --git a/src/Thunks/api-ms-win-core-string.hpp b/src/Thunks/api-ms-win-core-string.hpp index 1d64cf3..553b8af 100644 --- a/src/Thunks/api-ms-win-core-string.hpp +++ b/src/Thunks/api-ms-win-core-string.hpp @@ -265,25 +265,11 @@ namespace YY::Thunks #endif -#if defined(YY_Thunks_Implemented) && (YY_Thunks_Target < __WindowsNT5_1) - static bool IsSupportLOCALE_INVARIANT() - { - // 特意不考虑多线程支持,因为这里产生写入竞争并没有关系。 - static int s_iStat = 0; - if (s_iStat == 0) - { - s_iStat = internal::GetSystemVersion() >= internal::MakeVersion(5, 1) ? 1 : -1; - } - return s_iStat == 1; - } -#endif - - -#if (YY_Thunks_Target < __WindowsNT5_1) +#if (YY_Thunks_Target < __WindowsNT6) - // Windows 2000 不支持 LOCALE_INVARIANT 参数特殊处理一下。 // Minimum supported client Windows 2000 Professional [desktop apps only] // Minimum supported server Windows 2000 Server [desktop apps only] + // 虽然Windows 2000已经支持,但是几个新标记老系统不支持,特殊处理一下。 __DEFINE_THUNK( kernel32, 24, @@ -305,21 +291,33 @@ namespace YY::Thunks return 0; } - if (Locale == LOCALE_INVARIANT && IsSupportLOCALE_INVARIANT() == false) +#if (YY_Thunks_Target < __WindowsNT5_1) + // Windows 2000 不支持 LOCALE_INVARIANT 参数特殊处理一下。 + // 网友 海好蓝 提供 + if (Locale == LOCALE_INVARIANT && internal::GetSystemVersion() < internal::MakeVersion(5, 1)) { Locale = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); } +#endif +#if (YY_Thunks_Target < __WindowsNT6) + // Windows XP不支持 NORM_LINGUISTIC_CASING + // 网友 海好蓝 反馈 + if (internal::GetSystemVersion() < internal::MakeVersion(6, 0)) + { + dwCmpFlags &= ~NORM_LINGUISTIC_CASING; + } +#endif return _pfnCompareStringA(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); } #endif -#if (YY_Thunks_Target < __WindowsNT5_1) +#if (YY_Thunks_Target < __WindowsNT6) - // Windows 2000 不支持 LOCALE_INVARIANT 参数特殊处理一下。 // Minimum supported client Windows 2000 Professional [desktop apps only] // Minimum supported server Windows 2000 Server [desktop apps only] + // 虽然Windows 2000已经支持,但是几个新标记老系统不支持,特殊处理一下。 __DEFINE_THUNK( kernel32, 24, @@ -334,7 +332,6 @@ namespace YY::Thunks _In_ int cchCount2 ) { - // 网友 海好蓝 提供 const auto _pfnCompareStringW = try_get_CompareStringW(); if (!_pfnCompareStringW) { @@ -342,10 +339,23 @@ namespace YY::Thunks return 0; } - if (Locale == LOCALE_INVARIANT && IsSupportLOCALE_INVARIANT() == false) +#if (YY_Thunks_Target < __WindowsNT5_1) + // Windows 2000 不支持 LOCALE_INVARIANT 参数特殊处理一下。 + // 网友 海好蓝 提供 + if (Locale == LOCALE_INVARIANT && internal::GetSystemVersion() < internal::MakeVersion(5, 1)) { Locale = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); } +#endif + +#if (YY_Thunks_Target < __WindowsNT6) + // Windows XP不支持 NORM_LINGUISTIC_CASING + // 网友 海好蓝 反馈 + if (internal::GetSystemVersion() < internal::MakeVersion(6, 0)) + { + dwCmpFlags &= ~NORM_LINGUISTIC_CASING; + } +#endif return _pfnCompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); } diff --git a/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp b/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp index d5f9aea..20bd577 100644 --- a/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/api-ms-win-core-localization.UnitTest.cpp @@ -411,369 +411,460 @@ namespace api_ms_win_core_localization } }; - TEST_CLASS(GetThreadPreferredUILanguages) - { + TEST_CLASS(GetThreadPreferredUILanguages) + { AwaysNullGuard Guard; - public: - GetThreadPreferredUILanguages() - { + public: + GetThreadPreferredUILanguages() + { Guard |= YY::Thunks::aways_null_try_get_GetThreadPreferredUILanguages; - } + } - TEST_METHOD(无效参数验证) - { - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + TEST_METHOD(无效参数验证) + { + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, nullptr, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, nullptr, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - cchLanguagesBuffer = _countof(szLanguagesBuffer); - //pwszLanguagesBuffer 为nullptr 时, pcchLanguagesBuffer 必须为 0 - bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, nullptr, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + cchLanguagesBuffer = _countof(szLanguagesBuffer); + //pwszLanguagesBuffer 为nullptr 时, pcchLanguagesBuffer 必须为 0 + bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, nullptr, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - //pcchLanguagesBuffer不能为 nullptr - bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, szLanguagesBuffer, nullptr); - Assert::IsFalse(bRet); + //pcchLanguagesBuffer不能为 nullptr + bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &ulNumLanguages, szLanguagesBuffer, nullptr); + Assert::IsFalse(bRet); - //MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID不能同时使用 - cchLanguagesBuffer = _countof(szLanguagesBuffer); - bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + //MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID不能同时使用 + cchLanguagesBuffer = _countof(szLanguagesBuffer); + bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - //MUI_MERGE_SYSTEM_FALLBACK | MUI_THREAD_LANGUAGES不能同时使用 - cchLanguagesBuffer = _countof(szLanguagesBuffer); - bRet = ::GetThreadPreferredUILanguages(MUI_MERGE_SYSTEM_FALLBACK | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + //MUI_MERGE_SYSTEM_FALLBACK | MUI_THREAD_LANGUAGES不能同时使用 + cchLanguagesBuffer = _countof(szLanguagesBuffer); + bRet = ::GetThreadPreferredUILanguages(MUI_MERGE_SYSTEM_FALLBACK | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - //MUI_MERGE_USER_FALLBACK | MUI_THREAD_LANGUAGES不能同时使用 - cchLanguagesBuffer = _countof(szLanguagesBuffer); - bRet = ::GetThreadPreferredUILanguages(MUI_MERGE_USER_FALLBACK | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + //MUI_MERGE_USER_FALLBACK | MUI_THREAD_LANGUAGES不能同时使用 + cchLanguagesBuffer = _countof(szLanguagesBuffer); + bRet = ::GetThreadPreferredUILanguages(MUI_MERGE_USER_FALLBACK | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - //不允许使用MUI_CONSOLE_FILTER - cchLanguagesBuffer = _countof(szLanguagesBuffer); - bRet = ::GetThreadPreferredUILanguages(MUI_CONSOLE_FILTER, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); + //不允许使用MUI_CONSOLE_FILTER + cchLanguagesBuffer = _countof(szLanguagesBuffer); + bRet = ::GetThreadPreferredUILanguages(MUI_CONSOLE_FILTER, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); - //不允许使用MUI_COMPLEX_SCRIPT_FILTER - cchLanguagesBuffer = _countof(szLanguagesBuffer); - bRet = ::GetThreadPreferredUILanguages(MUI_COMPLEX_SCRIPT_FILTER, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsFalse(bRet); - } + //不允许使用MUI_COMPLEX_SCRIPT_FILTER + cchLanguagesBuffer = _countof(szLanguagesBuffer); + bRet = ::GetThreadPreferredUILanguages(MUI_COMPLEX_SCRIPT_FILTER, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsFalse(bRet); + } - TEST_METHOD(MUI_LANGUAGE_ID验证) - { - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + TEST_METHOD(MUI_LANGUAGE_ID验证) + { + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsTrue(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsTrue(bRet); - Assert::AreEqual(ulNumLanguages, 1ul); - Assert::AreEqual(cchLanguagesBuffer, 6ul); + Assert::AreEqual(ulNumLanguages, 1ul); + Assert::AreEqual(cchLanguagesBuffer, 6ul); - Assert::AreEqual(szLanguagesBuffer[4], L'\0'); - Assert::AreEqual(szLanguagesBuffer[5], L'\0'); + Assert::AreEqual(szLanguagesBuffer[4], L'\0'); + Assert::AreEqual(szLanguagesBuffer[5], L'\0'); - CStringW ThreadHex; - ThreadHex.Format(L"%.4x", GetThreadLocale()); + CStringW ThreadHex; + ThreadHex.Format(L"%.4x", GetThreadLocale()); - Assert::AreEqual(ThreadHex.GetString(), szLanguagesBuffer, true); - } + Assert::AreEqual(ThreadHex.GetString(), szLanguagesBuffer, true); + } - TEST_METHOD(MUI_LANGUAGE_NAME验证) - { + TEST_METHOD(MUI_LANGUAGE_NAME验证) + { - //zh-cn\0\0 - SetThreadLocale(0x0804); + //zh-cn\0\0 + SetThreadLocale(0x0804); - { - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + { + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsTrue(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsTrue(bRet); - Assert::AreEqual(ulNumLanguages, 1ul); - Assert::AreEqual(cchLanguagesBuffer, 7ul); + Assert::AreEqual(ulNumLanguages, 1ul); + Assert::AreEqual(cchLanguagesBuffer, 7ul); - Assert::AreEqual(szLanguagesBuffer[5], L'\0'); - Assert::AreEqual(szLanguagesBuffer[6], L'\0'); + Assert::AreEqual(szLanguagesBuffer[5], L'\0'); + Assert::AreEqual(szLanguagesBuffer[6], L'\0'); - Assert::AreEqual(L"zh-cn", szLanguagesBuffer, true); - } + Assert::AreEqual(L"zh-cn", szLanguagesBuffer, true); + } - //默认为 MUI_LANGUAGE_NAME - { - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + //默认为 MUI_LANGUAGE_NAME + { + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsTrue(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_THREAD_LANGUAGES, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsTrue(bRet); - Assert::AreEqual(ulNumLanguages, 1ul); - Assert::AreEqual(cchLanguagesBuffer, 7ul); + Assert::AreEqual(ulNumLanguages, 1ul); + Assert::AreEqual(cchLanguagesBuffer, 7ul); - Assert::AreEqual(szLanguagesBuffer[5], L'\0'); - Assert::AreEqual(szLanguagesBuffer[6], L'\0'); + Assert::AreEqual(szLanguagesBuffer[5], L'\0'); + Assert::AreEqual(szLanguagesBuffer[6], L'\0'); - Assert::AreEqual(L"zh-cn", szLanguagesBuffer, true); - } + Assert::AreEqual(L"zh-cn", szLanguagesBuffer, true); + } - } + } - TEST_METHOD(Languages消重验证) - { + TEST_METHOD(Languages消重验证) + { - //zh-cn\0\0 - SetThreadLocale(GetUserDefaultLangID()); + //zh-cn\0\0 + SetThreadLocale(GetUserDefaultLangID()); - { - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + { + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsTrue(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsTrue(bRet); - std::set Map; + std::set Map; - for (auto Str = szLanguagesBuffer; *Str; Str = Str + wcslen(Str) + 1) - { - Assert::IsTrue(Map.insert(CStringW(Str).MakeLower()).second); - } + for (auto Str = szLanguagesBuffer; *Str; Str = Str + wcslen(Str) + 1) + { + Assert::IsTrue(Map.insert(CStringW(Str).MakeLower()).second); + } - Assert::IsTrue(Map.size() >= 1); - } + Assert::IsTrue(Map.size() >= 1); + } - // - { - auto UserId = GetUserDefaultLangID(); - LANGID ThreadId; + // + { + auto UserId = GetUserDefaultLangID(); + LANGID ThreadId; - if (UserId == 0x0804) - { - //en-us - ThreadId = 0x0409; - } - else - { - ThreadId = 0x0804; - } + if (UserId == 0x0804) + { + //en-us + ThreadId = 0x0409; + } + else + { + ThreadId = 0x0804; + } - SetThreadLocale(ThreadId); + SetThreadLocale(ThreadId); - wchar_t szLanguagesBuffer[512]; - ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); - ULONG ulNumLanguages = 0; + wchar_t szLanguagesBuffer[512]; + ULONG cchLanguagesBuffer = _countof(szLanguagesBuffer); + ULONG ulNumLanguages = 0; - //pulNumLanguages 不能为 nullptr - auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); - Assert::IsTrue(bRet); + //pulNumLanguages 不能为 nullptr + auto bRet = ::GetThreadPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK, &ulNumLanguages, szLanguagesBuffer, &cchLanguagesBuffer); + Assert::IsTrue(bRet); - std::set Map; + std::set Map; - for (auto Str = szLanguagesBuffer; *Str; Str = Str + wcslen(Str) + 1) - { - Assert::IsTrue(Map.insert(CStringW(Str).MakeLower()).second); - } + for (auto Str = szLanguagesBuffer; *Str; Str = Str + wcslen(Str) + 1) + { + Assert::IsTrue(Map.insert(CStringW(Str).MakeLower()).second); + } - Assert::IsTrue(Map.size() >= 1); - } + Assert::IsTrue(Map.size() >= 1); + } - } + } - }; + }; - TEST_CLASS(ResolveLocaleName) - { + TEST_CLASS(ResolveLocaleName) + { AwaysNullGuard Guard; - public: - ResolveLocaleName() - { + public: + ResolveLocaleName() + { Guard |= YY::Thunks::aways_null_try_get_ResolveLocaleName; - } + } - TEST_METHOD(中性语言验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(中性语言验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(L"zh", Buffer, _countof(Buffer)); + auto result = ::ResolveLocaleName(L"zh", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-CN")); + Assert::AreEqual(result, (int)_countof(L"zh-CN")); - Assert::AreEqual(Buffer, L"zh-CN", true); + Assert::AreEqual(Buffer, L"zh-CN", true); - result = ::ResolveLocaleName(L"zh-Hant", Buffer, _countof(Buffer)); + result = ::ResolveLocaleName(L"zh-Hant", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-HK")); + Assert::AreEqual(result, (int)_countof(L"zh-HK")); - Assert::AreEqual(Buffer, L"zh-HK", true); + Assert::AreEqual(Buffer, L"zh-HK", true); - result = ::ResolveLocaleName(L"mn-Mong", Buffer, _countof(Buffer)); + result = ::ResolveLocaleName(L"mn-Mong", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"mn-Mong-CN")); + Assert::AreEqual(result, (int)_countof(L"mn-Mong-CN")); - Assert::AreEqual(Buffer, L"mn-Mong-CN", true); - } + Assert::AreEqual(Buffer, L"mn-Mong-CN", true); + } - TEST_METHOD(特定区域语言验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(特定区域语言验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(L"zh-TW", Buffer, _countof(Buffer)); + auto result = ::ResolveLocaleName(L"zh-TW", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-TW")); + Assert::AreEqual(result, (int)_countof(L"zh-TW")); - Assert::AreEqual(Buffer, L"zh-TW", true); + Assert::AreEqual(Buffer, L"zh-TW", true); - result = ::ResolveLocaleName(L"es-ES_tradnl", Buffer, _countof(Buffer)); + result = ::ResolveLocaleName(L"es-ES_tradnl", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"es-ES_tradnl")); + Assert::AreEqual(result, (int)_countof(L"es-ES_tradnl")); - Assert::AreEqual(Buffer, L"es-ES_tradnl", true); - } + Assert::AreEqual(Buffer, L"es-ES_tradnl", true); + } - TEST_METHOD(特定区域排序语言验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(特定区域排序语言验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(L"x-IV-mathan", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"")); - Assert::AreEqual(Buffer, L"", true); + auto result = ::ResolveLocaleName(L"x-IV-mathan", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"")); + Assert::AreEqual(Buffer, L"", true); - result = ::ResolveLocaleName(L"de-DE_phoneb", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"de-DE")); - Assert::AreEqual(Buffer, L"de-DE", true); + result = ::ResolveLocaleName(L"de-DE_phoneb", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"de-DE")); + Assert::AreEqual(Buffer, L"de-DE", true); - result = ::ResolveLocaleName(L"hu-HU_technl", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"hu-HU")); - Assert::AreEqual(Buffer, L"hu-HU", true); + result = ::ResolveLocaleName(L"hu-HU_technl", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"hu-HU")); + Assert::AreEqual(Buffer, L"hu-HU", true); - result = ::ResolveLocaleName(L"ka-GE_modern", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"ka-GE")); - Assert::AreEqual(Buffer, L"ka-GE", true); + result = ::ResolveLocaleName(L"ka-GE_modern", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"ka-GE")); + Assert::AreEqual(Buffer, L"ka-GE", true); - result = ::ResolveLocaleName(L"zh-CN_stroke", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-CN")); - Assert::AreEqual(Buffer, L"zh-CN", true); + result = ::ResolveLocaleName(L"zh-CN_stroke", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-CN")); + Assert::AreEqual(Buffer, L"zh-CN", true); - result = ::ResolveLocaleName(L"zh-SG_stroke", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-SG")); - Assert::AreEqual(Buffer, L"zh-SG", true); + result = ::ResolveLocaleName(L"zh-SG_stroke", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-SG")); + Assert::AreEqual(Buffer, L"zh-SG", true); - result = ::ResolveLocaleName(L"zh-MO_stroke", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-MO")); - Assert::AreEqual(Buffer, L"zh-MO", true); + result = ::ResolveLocaleName(L"zh-MO_stroke", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-MO")); + Assert::AreEqual(Buffer, L"zh-MO", true); - result = ::ResolveLocaleName(L"zh-TW_pronun", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-TW")); - Assert::AreEqual(Buffer, L"zh-TW", true); + result = ::ResolveLocaleName(L"zh-TW_pronun", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-TW")); + Assert::AreEqual(Buffer, L"zh-TW", true); - result = ::ResolveLocaleName(L"zh-TW_radstr", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-TW")); - Assert::AreEqual(Buffer, L"zh-TW", true); + result = ::ResolveLocaleName(L"zh-TW_radstr", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-TW")); + Assert::AreEqual(Buffer, L"zh-TW", true); - result = ::ResolveLocaleName(L"ja-JP_radstr", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"ja-JP")); - Assert::AreEqual(Buffer, L"ja-JP", true); + result = ::ResolveLocaleName(L"ja-JP_radstr", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"ja-JP")); + Assert::AreEqual(Buffer, L"ja-JP", true); - result = ::ResolveLocaleName(L"zh-HK_radstr", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-HK")); - Assert::AreEqual(Buffer, L"zh-HK", true); + result = ::ResolveLocaleName(L"zh-HK_radstr", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-HK")); + Assert::AreEqual(Buffer, L"zh-HK", true); - result = ::ResolveLocaleName(L"zh-MO_radstr", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-MO")); - Assert::AreEqual(Buffer, L"zh-MO", true); + result = ::ResolveLocaleName(L"zh-MO_radstr", Buffer, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-MO")); + Assert::AreEqual(Buffer, L"zh-MO", true); - } + } - TEST_METHOD(自动回退验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(自动回退验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(L"zh-TW-XXXXXX", Buffer, _countof(Buffer)); + auto result = ::ResolveLocaleName(L"zh-TW-XXXXXX", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-TW")); + Assert::AreEqual(result, (int)_countof(L"zh-TW")); - Assert::AreEqual(Buffer, L"zh-TW", true); + Assert::AreEqual(Buffer, L"zh-TW", true); - result = ::ResolveLocaleName(L"zh-Hant-XXXXXX", Buffer, _countof(Buffer)); + result = ::ResolveLocaleName(L"zh-Hant-XXXXXX", Buffer, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-HK")); + Assert::AreEqual(result, (int)_countof(L"zh-HK")); - Assert::AreEqual(Buffer, L"zh-HK", true); - } + Assert::AreEqual(Buffer, L"zh-HK", true); + } - TEST_METHOD(默认值验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(默认值验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(nullptr, Buffer, _countof(Buffer)); + auto result = ::ResolveLocaleName(nullptr, Buffer, _countof(Buffer)); - Assert::AreNotEqual(result, 0); + Assert::AreNotEqual(result, 0); - Assert::AreEqual(::LocaleNameToLCID(Buffer, 0), ::GetUserDefaultLCID()); + Assert::AreEqual(::LocaleNameToLCID(Buffer, 0), ::GetUserDefaultLCID()); - - ::ResolveLocaleName(LOCALE_NAME_SYSTEM_DEFAULT, Buffer, _countof(Buffer)); + + ::ResolveLocaleName(LOCALE_NAME_SYSTEM_DEFAULT, Buffer, _countof(Buffer)); - Assert::AreNotEqual(result, 0); + Assert::AreNotEqual(result, 0); - Assert::AreEqual(::LocaleNameToLCID(Buffer, 0), ::GetSystemDefaultLCID()); + Assert::AreEqual(::LocaleNameToLCID(Buffer, 0), ::GetSystemDefaultLCID()); - result = ::ResolveLocaleName(L"wrwrwrwr", Buffer, _countof(Buffer)); - Assert::AreEqual(result, 1); + result = ::ResolveLocaleName(L"wrwrwrwr", Buffer, _countof(Buffer)); + Assert::AreEqual(result, 1); - Assert::AreEqual(Buffer, L"", true); - } + Assert::AreEqual(Buffer, L"", true); + } - TEST_METHOD(仅返回长度验证) - { - wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; + TEST_METHOD(仅返回长度验证) + { + wchar_t Buffer[LOCALE_NAME_MAX_LENGTH] = {}; - auto result = ::ResolveLocaleName(L"zh-CN", Buffer, 0); - Assert::AreEqual(result, (int)_countof(L"zh-CN")); + auto result = ::ResolveLocaleName(L"zh-CN", Buffer, 0); + Assert::AreEqual(result, (int)_countof(L"zh-CN")); - result = ::ResolveLocaleName(L"zh-CN", 0, _countof(Buffer)); - Assert::AreEqual(result, (int)_countof(L"zh-CN")); + result = ::ResolveLocaleName(L"zh-CN", 0, _countof(Buffer)); + Assert::AreEqual(result, (int)_countof(L"zh-CN")); - result = ::ResolveLocaleName(L"zh-CN", 0, 0); - Assert::AreEqual(result, (int)_countof(L"zh-CN")); - } - }; + result = ::ResolveLocaleName(L"zh-CN", 0, 0); + Assert::AreEqual(result, (int)_countof(L"zh-CN")); + } + }; + + TEST_CLASS(FindNLSStringEx) + { + AwaysNullGuard Guard; + + public: + FindNLSStringEx() + { + Guard |= YY::Thunks::aways_null_try_get_FindNLSStringEx; + } + + TEST_METHOD(FIND_STARTSWITH验证) + { + INT _nFound; + int _nIndex; + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_STARTSWITH, L"0123456789", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 0); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_STARTSWITH, L"0123456789", -1, L"1234", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, -1); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_STARTSWITH, L"0123456789", -1, L"6789", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, -1); + } + + TEST_METHOD(FIND_FROMSTART验证) + { + INT _nFound; + int _nIndex; + + // 默认值 + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, L"01234567890123", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 0); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, L"01234567890123", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 0); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, L"01234501230123", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 0); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, L"01234567890123", -1, L"1234", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 1); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, L"01234567890123", -1, L"6789", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 6); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMSTART, L"01234567890123", -1, L"3210", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, -1); + } + + TEST_METHOD(FIND_ENDSWITH验证) + { + INT _nFound; + int _nIndex; + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_ENDSWITH, L"0123456789", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, -1); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_ENDSWITH, L"0123456789", -1, L"6789", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 6); + Assert::AreEqual(_nFound, 4); + } + + TEST_METHOD(FIND_FROMEND验证) + { + INT _nFound; + int _nIndex; + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMEND, L"01234567890123", -1, L"0123", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 10); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMEND, L"0123456789", -1, L"6789", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 6); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMEND, L"6789456789", -1, L"6789", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, 6); + Assert::AreEqual(_nFound, 4); + + _nIndex = ::FindNLSStringEx(LOCALE_NAME_SYSTEM_DEFAULT, FIND_FROMEND, L"0123456789", -1, L"9876", -1, &_nFound, nullptr, nullptr, 0); + Assert::AreEqual(_nIndex, -1); + } + }; }