2 * Unit tests for locale functions
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24 * even when the user has overridden their default i8n settings (e.g. in
25 * the control panel i8n page), we will still get the expected results.
28 #define _CRT_NON_CONFORMING_WCSTOK
36 #define WIN32_NO_STATUS
37 #include "wine/test.h"
45 static const WCHAR upper_case
[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
46 static const WCHAR lower_case
[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
47 static const WCHAR title_case
[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
48 static const WCHAR symbols_stripped
[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
49 static const WCHAR localeW
[] = {'e','n','-','U','S',0};
50 static const WCHAR fooW
[] = {'f','o','o',0};
51 static const WCHAR emptyW
[] = {0};
52 static const WCHAR invalidW
[] = {'i','n','v','a','l','i','d',0};
54 /* Some functions are only in later versions of kernel32.dll */
55 static WORD enumCount
;
57 static INT (WINAPI
*pGetTimeFormatEx
)(LPCWSTR
, DWORD
, const SYSTEMTIME
*, LPCWSTR
, LPWSTR
, INT
);
58 static INT (WINAPI
*pGetDateFormatEx
)(LPCWSTR
, DWORD
, const SYSTEMTIME
*, LPCWSTR
, LPWSTR
, INT
, LPCWSTR
);
59 static BOOL (WINAPI
*pEnumSystemLanguageGroupsA
)(LANGUAGEGROUP_ENUMPROCA
, DWORD
, LONG_PTR
);
60 static BOOL (WINAPI
*pEnumLanguageGroupLocalesA
)(LANGGROUPLOCALE_ENUMPROCA
, LGRPID
, DWORD
, LONG_PTR
);
61 static BOOL (WINAPI
*pEnumUILanguagesA
)(UILANGUAGE_ENUMPROCA
, DWORD
, LONG_PTR
);
62 static BOOL (WINAPI
*pEnumSystemLocalesEx
)(LOCALE_ENUMPROCEX
, DWORD
, LPARAM
, LPVOID
);
63 static INT (WINAPI
*pLCMapStringEx
)(LPCWSTR
, DWORD
, LPCWSTR
, INT
, LPWSTR
, INT
, LPNLSVERSIONINFO
, LPVOID
, LPARAM
);
64 static LCID (WINAPI
*pLocaleNameToLCID
)(LPCWSTR
, DWORD
);
65 static NTSTATUS (WINAPI
*pRtlLocaleNameToLcid
)(LPCWSTR
, LCID
*, DWORD
);
66 static BOOLEAN (WINAPI
*pRtlIsValidLocaleName
)(const WCHAR
*,ULONG
);
67 static NTSTATUS (WINAPI
*pRtlLcidToLocaleName
)(LCID
, UNICODE_STRING
*,DWORD
,BYTE
);
68 static INT (WINAPI
*pLCIDToLocaleName
)(LCID
, LPWSTR
, INT
, DWORD
);
69 static BOOL (WINAPI
*pIsValidLanguageGroup
)(LGRPID
, DWORD
);
70 static INT (WINAPI
*pIdnToNameprepUnicode
)(DWORD
, LPCWSTR
, INT
, LPWSTR
, INT
);
71 static INT (WINAPI
*pIdnToAscii
)(DWORD
, LPCWSTR
, INT
, LPWSTR
, INT
);
72 static INT (WINAPI
*pIdnToUnicode
)(DWORD
, LPCWSTR
, INT
, LPWSTR
, INT
);
73 static INT (WINAPI
*pGetLocaleInfoEx
)(LPCWSTR
, LCTYPE
, LPWSTR
, INT
);
74 static BOOL (WINAPI
*pIsValidLocaleName
)(LPCWSTR
);
75 static INT (WINAPI
*pResolveLocaleName
)(LPCWSTR
,LPWSTR
,INT
);
76 static INT (WINAPI
*pCompareStringOrdinal
)(const WCHAR
*, INT
, const WCHAR
*, INT
, BOOL
);
77 static INT (WINAPI
*pCompareStringEx
)(LPCWSTR
, DWORD
, LPCWSTR
, INT
, LPCWSTR
, INT
,
78 LPNLSVERSIONINFO
, LPVOID
, LPARAM
);
79 static INT (WINAPI
*pGetGeoInfoA
)(GEOID
, GEOTYPE
, LPSTR
, INT
, LANGID
);
80 static INT (WINAPI
*pGetGeoInfoW
)(GEOID
, GEOTYPE
, LPWSTR
, INT
, LANGID
);
81 static INT (WINAPI
*pGetGeoInfoEx
)(const WCHAR
*, GEOTYPE
, PWSTR
, INT
);
82 static INT (WINAPI
*pGetUserDefaultGeoName
)(LPWSTR
, int);
83 static BOOL (WINAPI
*pSetUserGeoName
)(PWSTR
);
84 static BOOL (WINAPI
*pEnumSystemGeoID
)(GEOCLASS
, GEOID
, GEO_ENUMPROC
);
85 static BOOL (WINAPI
*pGetSystemPreferredUILanguages
)(DWORD
, ULONG
*, WCHAR
*, ULONG
*);
86 static BOOL (WINAPI
*pGetThreadPreferredUILanguages
)(DWORD
, ULONG
*, WCHAR
*, ULONG
*);
87 static BOOL (WINAPI
*pGetUserPreferredUILanguages
)(DWORD
, ULONG
*, WCHAR
*, ULONG
*);
88 static WCHAR (WINAPI
*pRtlUpcaseUnicodeChar
)(WCHAR
);
89 static INT (WINAPI
*pGetNumberFormatEx
)(LPCWSTR
, DWORD
, LPCWSTR
, const NUMBERFMTW
*, LPWSTR
, int);
90 static INT (WINAPI
*pFindNLSStringEx
)(LPCWSTR
, DWORD
, LPCWSTR
, INT
, LPCWSTR
, INT
, LPINT
, LPNLSVERSIONINFO
, LPVOID
, LPARAM
);
91 static void * (WINAPI
*pNlsValidateLocale
)(LCID
*,ULONG
);
92 static LANGID (WINAPI
*pSetThreadUILanguage
)(LANGID
);
93 static LANGID (WINAPI
*pGetThreadUILanguage
)(VOID
);
94 static INT (WINAPI
*pNormalizeString
)(NORM_FORM
, LPCWSTR
, INT
, LPWSTR
, INT
);
95 static INT (WINAPI
*pFindStringOrdinal
)(DWORD
, LPCWSTR lpStringSource
, INT
, LPCWSTR
, INT
, BOOL
);
96 static BOOL (WINAPI
*pGetNLSVersion
)(NLS_FUNCTION
,LCID
,NLSVERSIONINFO
*);
97 static BOOL (WINAPI
*pGetNLSVersionEx
)(NLS_FUNCTION
,LPCWSTR
,NLSVERSIONINFOEX
*);
98 static DWORD (WINAPI
*pIsValidNLSVersion
)(NLS_FUNCTION
,LPCWSTR
,NLSVERSIONINFOEX
*);
99 static BOOL (WINAPI
*pIsNLSDefinedString
)(NLS_FUNCTION
,DWORD
,NLSVERSIONINFO
*,const WCHAR
*,int);
100 static NTSTATUS (WINAPI
*pRtlNormalizeString
)(ULONG
, LPCWSTR
, INT
, LPWSTR
, INT
*);
101 static NTSTATUS (WINAPI
*pRtlIsNormalizedString
)(ULONG
, LPCWSTR
, INT
, BOOLEAN
*);
102 static NTSTATUS (WINAPI
*pNtGetNlsSectionPtr
)(ULONG
,ULONG
,void*,void**,SIZE_T
*);
103 static NTSTATUS (WINAPI
*pNtInitializeNlsFiles
)(void**,LCID
*,LARGE_INTEGER
*);
104 static NTSTATUS (WINAPI
*pRtlGetLocaleFileMappingAddress
)(void**,LCID
*,LARGE_INTEGER
*);
105 static void (WINAPI
*pRtlInitCodePageTable
)(USHORT
*,CPTABLEINFO
*);
106 static NTSTATUS (WINAPI
*pRtlCustomCPToUnicodeN
)(CPTABLEINFO
*,WCHAR
*,DWORD
,DWORD
*,const char*,DWORD
);
107 static NTSTATUS (WINAPI
*pRtlGetSystemPreferredUILanguages
)(DWORD
,ULONG
,ULONG
*,WCHAR
*,ULONG
*);
108 static NTSTATUS (WINAPI
*pRtlGetThreadPreferredUILanguages
)(DWORD
,ULONG
*,WCHAR
*,ULONG
*);
109 static NTSTATUS (WINAPI
*pRtlGetUserPreferredUILanguages
)(DWORD
,ULONG
,ULONG
*,WCHAR
*,ULONG
*);
111 static void InitFunctionPointers(void)
113 HMODULE mod
= GetModuleHandleA("kernel32");
115 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
118 X(EnumSystemLanguageGroupsA
);
119 X(EnumLanguageGroupLocalesA
);
123 X(IsValidLanguageGroup
);
125 X(EnumSystemLocalesEx
);
126 X(IdnToNameprepUnicode
);
130 X(IsValidLocaleName
);
131 X(ResolveLocaleName
);
132 X(CompareStringOrdinal
);
137 X(GetUserDefaultGeoName
);
140 X(GetSystemPreferredUILanguages
);
141 X(GetThreadPreferredUILanguages
);
142 X(GetUserPreferredUILanguages
);
143 X(GetNumberFormatEx
);
145 X(SetThreadUILanguage
);
146 X(GetThreadUILanguage
);
148 X(FindStringOrdinal
);
151 X(IsValidNLSVersion
);
152 X(IsNLSDefinedString
);
154 mod
= GetModuleHandleA("kernelbase");
155 X(NlsValidateLocale
);
157 mod
= GetModuleHandleA("ntdll");
158 X(RtlUpcaseUnicodeChar
);
159 X(RtlLocaleNameToLcid
);
160 X(RtlIsValidLocaleName
);
161 X(RtlLcidToLocaleName
);
162 X(RtlNormalizeString
);
163 X(RtlIsNormalizedString
);
164 X(NtGetNlsSectionPtr
);
165 X(NtInitializeNlsFiles
);
166 X(RtlInitCodePageTable
);
167 X(RtlCustomCPToUnicodeN
);
168 X(RtlGetLocaleFileMappingAddress
);
169 X(RtlGetSystemPreferredUILanguages
);
170 X(RtlGetThreadPreferredUILanguages
);
171 X(RtlGetUserPreferredUILanguages
);
175 #define eq(received, expected, label, type) \
176 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
177 (label), (received), (expected))
179 #define BUFFER_SIZE 128
181 #define expect_str(r,s,e) expect_str_(__LINE__, r, s, e)
182 static void expect_str_(int line
, int ret
, const char *str
, const char *expected
)
186 ok_(__FILE__
, line
)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError());
187 ok_(__FILE__
, line
)(ret
== strlen(expected
) + 1, "Expected ret %Id, got %d\n", strlen(expected
) + 1, ret
);
189 ok_(__FILE__
, line
)(strcmp(str
, expected
) == 0, "Expected '%s', got '%s'\n", expected
, str
);
192 ok_(__FILE__
, line
)(0, "expected success, got error %ld\n", GetLastError());
195 #define expect_err(r,s,e) expect_err_(__LINE__, r, s, e, #e)
196 static void expect_err_(int line
, int ret
, const char *str
, DWORD err
, const char* err_name
)
198 ok_(__FILE__
, line
)(!ret
&& GetLastError() == err
,
199 "Expected %s, got %ld and ret=%d\n", err_name
, GetLastError(), ret
);
201 ok_(__FILE__
, line
)(strcmp(str
, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", str
);
204 #define expect_wstr(r,s,e) expect_wstr_(__LINE__, r, s, e)
205 static void expect_wstr_(int line
, int ret
, const WCHAR
*str
, const WCHAR
*expected
)
209 ok_(__FILE__
, line
)(GetLastError() == 0xdeadbeef, "unexpected gle %lu\n", GetLastError());
210 ok_(__FILE__
, line
)(ret
== wcslen(expected
) + 1, "Expected ret %Id, got %d\n", wcslen(expected
) + 1, ret
);
212 ok_(__FILE__
, line
)(wcscmp(str
, expected
) == 0, "Expected %s, got %s\n", wine_dbgstr_w(expected
), wine_dbgstr_w(str
));
215 ok_(__FILE__
, line
)(0, "expected success, got error %ld\n", GetLastError());
218 #define expect_werr(r,s,e) expect_werr_(__LINE__, r, s, e, #e)
219 static void expect_werr_(int line
, int ret
, const WCHAR
*str
, DWORD err
, const char* err_name
)
221 ok_(__FILE__
, line
)(!ret
&& GetLastError() == err
,
222 "Expected %s, got %ld and ret=%d\n", err_name
, GetLastError(), ret
);
224 ok_(__FILE__
, line
)(wcscmp(str
, L
"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(str
));
227 static int get_utf16( const WCHAR
*src
, unsigned int srclen
, unsigned int *ch
)
229 if (IS_HIGH_SURROGATE( src
[0] ))
231 if (srclen
<= 1) return 0;
232 if (!IS_LOW_SURROGATE( src
[1] )) return 0;
233 *ch
= 0x10000 + ((src
[0] & 0x3ff) << 10) + (src
[1] & 0x3ff);
236 if (IS_LOW_SURROGATE( src
[0] )) return 0;
241 static int put_utf16( WCHAR
*str
, unsigned int c
)
249 str
[0] = 0xd800 | (c
>> 10);
250 str
[1] = 0xdc00 | (c
& 0x3ff);
254 #define NUO LOCALE_NOUSEROVERRIDE
256 static void test_GetLocaleInfoA(void)
260 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
261 char buffer
[BUFFER_SIZE
];
262 char expected
[BUFFER_SIZE
];
265 ok(lcid
== 0x409, "wrong LCID calculated - %ld\n", lcid
);
267 ret
= GetLocaleInfoA(lcid
, LOCALE_ILANGUAGE
|LOCALE_RETURN_NUMBER
, (char*)&val
, sizeof(val
));
268 ok(ret
, "got %d\n", ret
);
269 ok(val
== lcid
, "got 0x%08lx\n", val
);
271 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
272 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
273 assumes SUBLANG_NEUTRAL for zh */
274 memset(expected
, 0, ARRAY_SIZE(expected
));
275 len
= GetLocaleInfoA(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), LOCALE_SLANGUAGE
, expected
, ARRAY_SIZE(expected
));
276 SetLastError(0xdeadbeef);
277 memset(buffer
, 0, ARRAY_SIZE(buffer
));
278 ret
= GetLocaleInfoA(LANG_ENGLISH
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
279 ok((ret
== len
) && !lstrcmpA(buffer
, expected
),
280 "got %d with '%s' (expected %d with '%s')\n",
281 ret
, buffer
, len
, expected
);
283 memset(expected
, 0, ARRAY_SIZE(expected
));
284 len
= GetLocaleInfoA(MAKELANGID(LANG_ARABIC
, SUBLANG_DEFAULT
), LOCALE_SLANGUAGE
, expected
, ARRAY_SIZE(expected
));
286 SetLastError(0xdeadbeef);
287 memset(buffer
, 0, ARRAY_SIZE(buffer
));
288 ret
= GetLocaleInfoA(LANG_ARABIC
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
289 ok((ret
== len
) && !lstrcmpA(buffer
, expected
),
290 "got %d with '%s' (expected %d with '%s')\n",
291 ret
, buffer
, len
, expected
);
294 win_skip("LANG_ARABIC not installed\n");
296 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
297 memset(expected
, 0, ARRAY_SIZE(expected
));
298 len
= GetLocaleInfoA(MAKELANGID(LANG_GERMAN
, SUBLANG_DEFAULT
), LOCALE_SLANGUAGE
, expected
, ARRAY_SIZE(expected
));
299 SetLastError(0xdeadbeef);
300 memset(buffer
, 0, ARRAY_SIZE(buffer
));
301 ret
= GetLocaleInfoA(LANG_GERMAN
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
302 ok((ret
== len
) && !lstrcmpA(buffer
, expected
),
303 "got %d with '%s' (expected %d with '%s')\n",
304 ret
, buffer
, len
, expected
);
306 len
= GetLocaleInfoA(GetUserDefaultLCID(), LOCALE_SLANGUAGE
, expected
, ARRAY_SIZE(expected
));
307 ret
= GetLocaleInfoA(LOCALE_NEUTRAL
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
308 ok( (ret
== len
) && !lstrcmpA(buffer
, expected
), "got %d with '%s' (expected %d with '%s')\n",
309 ret
, buffer
, len
, expected
);
310 ret
= GetLocaleInfoA(LOCALE_CUSTOM_DEFAULT
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
311 ok( (ret
== len
) && !lstrcmpA(buffer
, expected
), "got %d with '%s' (expected %d with '%s')\n",
312 ret
, buffer
, len
, expected
);
313 ret
= GetLocaleInfoA(LOCALE_CUSTOM_UNSPECIFIED
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
314 ok( (ret
== len
&& !lstrcmpA(buffer
, expected
)) || broken(!ret
), /* <= win8 */
315 "got %d with '%s' (expected %d with '%s')\n", ret
, buffer
, len
, expected
);
316 len
= GetLocaleInfoA(GetUserDefaultUILanguage(), LOCALE_SLANGUAGE
, expected
, ARRAY_SIZE(expected
));
317 ret
= GetLocaleInfoA(LOCALE_CUSTOM_UI_DEFAULT
, LOCALE_SLANGUAGE
, buffer
, ARRAY_SIZE(buffer
));
318 if (ret
) ok( (ret
== len
&& !lstrcmpA(buffer
, expected
)),
319 "got %d with '%s' (expected %d with '%s')\n", ret
, buffer
, len
, expected
);
321 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
322 * partially fill the buffer even if it is too short. See bug 637.
324 SetLastError(0xdeadbeef);
325 memset(buffer
, 0, ARRAY_SIZE(buffer
));
326 ret
= GetLocaleInfoA(lcid
, NUO
|LOCALE_SDAYNAME1
, buffer
, 0);
327 ok(ret
== 7 && !buffer
[0], "Expected len=7, got %d\n", ret
);
329 SetLastError(0xdeadbeef);
330 memset(buffer
, 0, ARRAY_SIZE(buffer
));
331 ret
= GetLocaleInfoA(lcid
, NUO
|LOCALE_SDAYNAME1
, buffer
, 3);
332 ok( !ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
333 "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
334 ok(!strcmp(buffer
, "Mon"), "Expected 'Mon', got '%s'\n", buffer
);
336 SetLastError(0xdeadbeef);
337 memset(buffer
, 0, ARRAY_SIZE(buffer
));
338 ret
= GetLocaleInfoA(lcid
, NUO
|LOCALE_SDAYNAME1
, buffer
, 10);
339 ok(ret
== 7, "Expected ret == 7, got %d, error %ld\n", ret
, GetLastError());
340 ok(!strcmp(buffer
, "Monday"), "Expected 'Monday', got '%s'\n", buffer
);
343 struct neutralsublang_name2_t
{
348 WCHAR sname_broken
[15];
351 static const struct neutralsublang_name2_t neutralsublang_names2
[] = {
352 { {'a','r',0}, {'a','r','-','S','A',0},
353 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_SAUDI_ARABIA
), SORT_DEFAULT
) },
354 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
355 MAKELCID(MAKELANGID(LANG_AZERI
, SUBLANG_AZERI_LATIN
), SORT_DEFAULT
) },
356 { {'d','e',0}, {'d','e','-','D','E',0},
357 MAKELCID(MAKELANGID(LANG_GERMAN
, SUBLANG_GERMAN
), SORT_DEFAULT
) },
358 { {'e','n',0}, {'e','n','-','U','S',0},
359 MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
) },
360 { {'e','s',0}, {'e','s','-','E','S',0},
361 MAKELCID(MAKELANGID(LANG_SPANISH
, SUBLANG_SPANISH_MODERN
), SORT_DEFAULT
),
362 MAKELCID(MAKELANGID(LANG_SPANISH
, SUBLANG_SPANISH
), SORT_DEFAULT
) /* vista */,
363 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
364 { {'g','a',0}, {'g','a','-','I','E',0},
365 MAKELCID(MAKELANGID(LANG_IRISH
, SUBLANG_IRISH_IRELAND
), SORT_DEFAULT
), 0, {0} },
366 { {'i','t',0}, {'i','t','-','I','T',0},
367 MAKELCID(MAKELANGID(LANG_ITALIAN
, SUBLANG_ITALIAN
), SORT_DEFAULT
) },
368 { {'m','s',0}, {'m','s','-','M','Y',0},
369 MAKELCID(MAKELANGID(LANG_MALAY
, SUBLANG_MALAY_MALAYSIA
), SORT_DEFAULT
) },
370 { {'n','l',0}, {'n','l','-','N','L',0},
371 MAKELCID(MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH
), SORT_DEFAULT
) },
372 { {'p','t',0}, {'p','t','-','B','R',0},
373 MAKELCID(MAKELANGID(LANG_PORTUGUESE
, SUBLANG_PORTUGUESE_BRAZILIAN
), SORT_DEFAULT
) },
374 { {'s','r',0}, {'h','r','-','H','R',0},
375 MAKELCID(MAKELANGID(LANG_SERBIAN
, SUBLANG_SERBIAN_CROATIA
), SORT_DEFAULT
) },
376 { {'s','v',0}, {'s','v','-','S','E',0},
377 MAKELCID(MAKELANGID(LANG_SWEDISH
, SUBLANG_SWEDISH
), SORT_DEFAULT
) },
378 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
379 MAKELCID(MAKELANGID(LANG_UZBEK
, SUBLANG_UZBEK_LATIN
), SORT_DEFAULT
) },
380 { {'z','h',0}, {'z','h','-','C','N',0},
381 MAKELCID(MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
), SORT_DEFAULT
) },
385 static void test_GetLocaleInfoW(void)
387 LCID lcid_en
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
388 LCID lcid_ru
= MAKELCID(MAKELANGID(LANG_RUSSIAN
, SUBLANG_NEUTRAL
), SORT_DEFAULT
);
389 LCID lcid_en_neut
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), SORT_DEFAULT
);
390 WCHAR bufferW
[80], buffer2W
[80];
396 ret
= GetLocaleInfoW(lcid_en
, LOCALE_SMONTHNAME1
, bufferW
, ARRAY_SIZE(bufferW
));
398 win_skip("GetLocaleInfoW() isn't implemented\n");
402 ret
= GetLocaleInfoW(lcid_en
, LOCALE_ILANGUAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, sizeof(val
)/sizeof(WCHAR
));
403 ok(ret
, "got %ld\n", ret
);
404 ok(val
== lcid_en
, "got 0x%08lx\n", val
);
406 ret
= GetLocaleInfoW(lcid_en_neut
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
409 static const WCHAR slangW
[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
410 'S','t','a','t','e','s',')',0};
411 static const WCHAR statesW
[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
412 static const WCHAR enW
[] = {'e','n','-','U','S',0};
413 const struct neutralsublang_name2_t
*ptr
= neutralsublang_names2
;
415 ok(!lstrcmpW(bufferW
, enW
), "got wrong name %s\n", wine_dbgstr_w(bufferW
));
417 ret
= GetLocaleInfoW(lcid_en_neut
, LOCALE_SCOUNTRY
, bufferW
, ARRAY_SIZE(bufferW
));
418 ok(ret
, "got %ld\n", ret
);
419 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH
) ||
420 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH
))
422 skip("Non-English locale\n");
425 ok(!lstrcmpW(statesW
, bufferW
), "got wrong name %s\n", wine_dbgstr_w(bufferW
));
427 ret
= GetLocaleInfoW(lcid_en_neut
, LOCALE_SLANGUAGE
, bufferW
, ARRAY_SIZE(bufferW
));
428 ok(ret
, "got %ld\n", ret
);
429 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH
) ||
430 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH
))
432 skip("Non-English locale\n");
435 ok(!lstrcmpW(slangW
, bufferW
), "got wrong name %s\n", wine_dbgstr_w(bufferW
));
442 /* make neutral lcid */
443 langid
= MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr
->lcid
)), SUBLANG_NEUTRAL
);
444 lcid
= MAKELCID(langid
, SORT_DEFAULT
);
447 GetLocaleInfoW(lcid
, LOCALE_ILANGUAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, sizeof(val
)/sizeof(WCHAR
));
448 ok(val
== ptr
->lcid
|| (val
&& broken(val
== ptr
->lcid_broken
)), "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
449 wine_dbgstr_w(ptr
->name
), val
, ptr
->lcid
);
451 /* now check LOCALE_SNAME */
452 GetLocaleInfoW(lcid
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
453 ok(!lstrcmpW(bufferW
, ptr
->sname
) ||
454 (*ptr
->sname_broken
&& broken(!lstrcmpW(bufferW
, ptr
->sname_broken
))),
455 "%s: got %s\n", wine_dbgstr_w(ptr
->name
), wine_dbgstr_w(bufferW
));
460 win_skip("English neutral locale not supported\n");
462 ret
= GetLocaleInfoW(lcid_ru
, LOCALE_SMONTHNAME1
, bufferW
, ARRAY_SIZE(bufferW
));
464 win_skip("LANG_RUSSIAN locale data unavailable\n");
467 ret
= GetLocaleInfoW(lcid_ru
, LOCALE_SMONTHNAME1
|LOCALE_RETURN_GENITIVE_NAMES
,
468 bufferW
, ARRAY_SIZE(bufferW
));
470 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
474 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
476 SetLastError(0xdeadbeef);
477 ret
= GetLocaleInfoA(lcid_ru
, LOCALE_SMONTHNAME1
|LOCALE_RETURN_GENITIVE_NAMES
,
478 bufferA
, ARRAY_SIZE(bufferA
));
479 ok(ret
== 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
480 ok(bufferA
[0] == 'a', "Expected buffer to be untouched\n");
481 ok(GetLastError() == ERROR_INVALID_FLAGS
,
482 "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError());
485 SetLastError(0xdeadbeef);
486 ret
= GetLocaleInfoW(lcid_ru
, LOCALE_RETURN_GENITIVE_NAMES
, bufferW
, ARRAY_SIZE(bufferW
));
488 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %ld\n", ret
);
489 ok(bufferW
[0] == 'a', "Expected buffer to be untouched\n");
490 ok(GetLastError() == ERROR_INVALID_FLAGS
,
491 "Expected ERROR_INVALID_FLAGS, got %lx\n", GetLastError());
493 /* yes, test empty 13 month entry too */
494 for (i
= 0; i
< 12; i
++) {
496 ret
= GetLocaleInfoW(lcid_ru
, (LOCALE_SMONTHNAME1
+i
)|LOCALE_RETURN_GENITIVE_NAMES
,
497 bufferW
, ARRAY_SIZE(bufferW
));
498 ok(ret
, "Expected non zero result\n");
499 ok(ret
== lstrlenW(bufferW
)+1, "Expected actual length, got %ld, length %d\n",
500 ret
, lstrlenW(bufferW
));
502 ret
= GetLocaleInfoW(lcid_ru
, LOCALE_SMONTHNAME1
+i
, buffer2W
, ARRAY_SIZE(buffer2W
));
503 ok(ret
, "Expected non zero result\n");
504 ok(ret
== lstrlenW(buffer2W
)+1, "Expected actual length, got %ld, length %d\n",
505 ret
, lstrlenW(buffer2W
));
507 ok(lstrcmpW(bufferW
, buffer2W
) != 0,
508 "Expected genitive name to differ, got the same for month %d\n", i
+1);
510 /* for locale without genitive names nominative returned in both cases */
512 ret
= GetLocaleInfoW(lcid_en
, (LOCALE_SMONTHNAME1
+i
)|LOCALE_RETURN_GENITIVE_NAMES
,
513 bufferW
, ARRAY_SIZE(bufferW
));
514 ok(ret
, "Expected non zero result\n");
515 ok(ret
== lstrlenW(bufferW
)+1, "Expected actual length, got %ld, length %d\n",
516 ret
, lstrlenW(bufferW
));
518 ret
= GetLocaleInfoW(lcid_en
, LOCALE_SMONTHNAME1
+i
, buffer2W
, ARRAY_SIZE(buffer2W
));
519 ok(ret
, "Expected non zero result\n");
520 ok(ret
== lstrlenW(buffer2W
)+1, "Expected actual length, got %ld, length %d\n",
521 ret
, lstrlenW(buffer2W
));
523 ok(lstrcmpW(bufferW
, buffer2W
) == 0,
524 "Expected same names, got different for month %d\n", i
+1);
528 static void test_GetTimeFormatA(void)
532 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
533 char buffer
[BUFFER_SIZE
];
535 SetLastError(0xdeadbeef);
538 memset(&curtime
, 2, sizeof(SYSTEMTIME
));
539 strcpy(buffer
, "pristine");
540 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, "tt HH':'mm'@'ss", buffer
, ARRAY_SIZE(buffer
));
541 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
542 SetLastError(0xdeadbeef);
546 curtime
.wMinute
= 56;
547 curtime
.wSecond
= 13;
548 curtime
.wMilliseconds
= 22;
549 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, "tt HH':'mm'@'ss", buffer
, ARRAY_SIZE(buffer
));
550 expect_str(ret
, buffer
, "AM 08:56@13");
552 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
553 strcpy(buffer
, "pristine");
554 ret
= GetTimeFormatA(lcid
, NUO
|TIME_FORCE24HOURFORMAT
, &curtime
, "HH", buffer
, ARRAY_SIZE(buffer
));
555 expect_err(ret
, buffer
, ERROR_INVALID_FLAGS
);
556 SetLastError(0xdeadbeef);
558 /* Insufficient buffer */
559 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, " HH", buffer
, 2);
560 /* The content of the buffer depends on implementation details:
561 * it may be " ristine" or " 0ristine" or unchanged and cannot be relied on.
563 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
564 SetLastError(0xdeadbeef);
566 /* Calculate length only */
567 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, "tt HH':'mm'@'ss", NULL
, 0);
568 expect_str(ret
, NULL
, "AM 08:56@13");
570 /* TIME_NOMINUTESORSECONDS, default format */
571 ret
= GetTimeFormatA(lcid
, NUO
|TIME_NOMINUTESORSECONDS
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
572 expect_str(ret
, buffer
, "8 AM");
574 /* TIME_NOMINUTESORSECONDS/complex format */
575 ret
= GetTimeFormatA(lcid
, TIME_NOMINUTESORSECONDS
, &curtime
, "m1s2m3s4", buffer
, ARRAY_SIZE(buffer
));
576 expect_str(ret
, buffer
, "");
578 /* TIME_NOSECONDS/Default format */
579 ret
= GetTimeFormatA(lcid
, NUO
|TIME_NOSECONDS
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
580 expect_str(ret
, buffer
, "8:56 AM");
583 strcpy(buffer
, "pristine"); /* clear previous identical result */
584 ret
= GetTimeFormatA(lcid
, TIME_NOSECONDS
, &curtime
, "h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
585 expect_str(ret
, buffer
, "8:56 AM");
587 /* Multiple delimiters */
588 ret
= GetTimeFormatA(lcid
, TIME_NOSECONDS
, &curtime
, "h.@:m.@:s.@:tt", buffer
, ARRAY_SIZE(buffer
));
589 expect_str(ret
, buffer
, "8.@:56AM");
591 /* Duplicate tokens */
592 ret
= GetTimeFormatA(lcid
, TIME_NOSECONDS
, &curtime
, "s1s2s3", buffer
, ARRAY_SIZE(buffer
));
593 expect_str(ret
, buffer
, "");
596 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "t/tt", buffer
, ARRAY_SIZE(buffer
));
597 expect_str(ret
, buffer
, "A/AM");
601 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "t/tt", buffer
, ARRAY_SIZE(buffer
));
602 expect_str(ret
, buffer
, "P/PM");
604 /* TIME_NOTIMEMARKER: removes text around time marker token */
605 ret
= GetTimeFormatA(lcid
, TIME_NOTIMEMARKER
, &curtime
, "h1t2tt3m", buffer
, ARRAY_SIZE(buffer
));
606 expect_str(ret
, buffer
, "156");
608 /* TIME_FORCE24HOURFORMAT */
609 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, "h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
610 expect_str(ret
, buffer
, "13:56:13 PM");
612 /* TIME_FORCE24HOURFORMAT doesn't add time marker */
613 ret
= GetTimeFormatA(lcid
, TIME_FORCE24HOURFORMAT
, &curtime
, "h:m:s", buffer
, ARRAY_SIZE(buffer
));
614 expect_str(ret
, buffer
, "13:56:13");
616 /* 24 hrs, leading 0 */
617 curtime
.wHour
= 14; /* change this to 14 or 2pm */
620 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h hh H HH m mm s ss t tt", buffer
, ARRAY_SIZE(buffer
));
621 expect_str(ret
, buffer
, "2 02 14 14 5 05 3 03 P PM");
625 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h/H/hh/HH", buffer
, ARRAY_SIZE(buffer
));
626 expect_str(ret
, buffer
, "12/0/12/00");
628 /* non-zero flags should fail with format, doesn't */
629 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
630 expect_str(ret
, buffer
, "12:5:3 AM");
632 /* try to convert formatting strings with more than two letters
633 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
634 * NOTE: We expect any letter for which there is an upper case value
635 * we should see a replacement. For letters that DO NOT have
636 * upper case values we should see NO REPLACEMENT.
639 curtime
.wMinute
= 56;
640 curtime
.wSecond
= 13;
641 curtime
.wMilliseconds
= 22;
642 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer
, ARRAY_SIZE(buffer
));
643 expect_str(ret
, buffer
, "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
645 /* Don't write to buffer if len is 0 */
646 strcpy(buffer
, "pristine");
647 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h:mm", buffer
, 0);
648 expect_str(ret
, NULL
, "8:56");
649 ok(strcmp(buffer
, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer
);
651 /* "'" preserves tokens */
652 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer
, ARRAY_SIZE(buffer
));
653 expect_str(ret
, buffer
, "8 h 8 H 08 HH 56 m 13 s A t AM tt");
655 /* invalid quoted string */
656 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "'''", buffer
, ARRAY_SIZE(buffer
));
657 expect_str(ret
, buffer
, "'");
659 /* check that MSDN's suggested single quotation usage works as expected */
660 strcpy(buffer
, "pristine"); /* clear previous identical result */
661 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "''''", buffer
, ARRAY_SIZE(buffer
));
662 expect_str(ret
, buffer
, "'");
665 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "''HHHHHH", buffer
, ARRAY_SIZE(buffer
));
666 expect_str(ret
, buffer
, "08");
668 /* and test for normal use of the single quotation mark */
669 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "'''HHHHHH'", buffer
, ARRAY_SIZE(buffer
));
670 expect_str(ret
, buffer
, "'HHHHHH");
673 strcpy(buffer
, "pristine"); /* clear previous identical result */
674 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "'''HHHHHH", buffer
, ARRAY_SIZE(buffer
));
675 expect_str(ret
, buffer
, "'HHHHHH");
677 /* TIME_NOTIMEMARKER drops literals too */
678 ret
= GetTimeFormatA(lcid
, TIME_NOTIMEMARKER
, &curtime
, "'123'tt", buffer
, ARRAY_SIZE(buffer
));
679 expect_str(ret
, buffer
, "");
683 strcpy(buffer
, "pristine");
684 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "'123'tt", buffer
, ARRAY_SIZE(buffer
));
685 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
686 SetLastError(0xdeadbeef);
691 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h:m:s", buffer
, ARRAY_SIZE(buffer
));
692 expect_str(ret
, buffer
, "12:56:13");
694 /* The ANSI string may be longer than the Unicode one.
695 * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5".
698 lcid
= MAKELCID(MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), SORT_DEFAULT
);
700 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h\x93\xfa", buffer
, 5);
701 expect_str(ret
, buffer
, "12\x93\xfa"); /* only 3+1 WCHARs */
703 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h\x93\xfa", buffer
, 4);
704 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
705 SetLastError(0xdeadbeef);
707 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h\x93\xfa", NULL
, 0);
708 expect_str(ret
, NULL
, "12\x93\xfa");
710 strcpy(buffer
, "pristine"); /* clear previous identical result */
711 ret
= GetTimeFormatA(lcid
, 0, &curtime
, "h\x93\xfa", buffer
, 0);
712 expect_str(ret
, NULL
, "12\x93\xfa");
713 ok(strcmp(buffer
, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer
);
716 static void test_GetTimeFormatEx(void)
720 WCHAR buffer
[BUFFER_SIZE
];
722 if (!pGetTimeFormatEx
)
724 win_skip("GetTimeFormatEx not supported\n");
728 SetLastError(0xdeadbeef);
731 memset(&curtime
, 2, sizeof(SYSTEMTIME
));
732 wcscpy(buffer
, L
"pristine");
733 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
"tt HH':'mm'@'ss", buffer
, ARRAY_SIZE(buffer
));
734 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
735 SetLastError(0xdeadbeef);
739 curtime
.wMinute
= 56;
740 curtime
.wSecond
= 13;
741 curtime
.wMilliseconds
= 22;
742 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
"tt HH':'mm'@'ss", buffer
, ARRAY_SIZE(buffer
));
743 expect_wstr(ret
, buffer
, L
"AM 08:56@13");
745 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
746 wcscpy(buffer
, L
"pristine");
747 ret
= pGetTimeFormatEx(localeW
, NUO
|TIME_FORCE24HOURFORMAT
, &curtime
, L
"HH", buffer
, ARRAY_SIZE(buffer
));
748 expect_werr(ret
, buffer
, ERROR_INVALID_FLAGS
);
749 SetLastError(0xdeadbeef);
751 /* Insufficient buffer */
752 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
" tt", buffer
, 2);
753 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
754 expect_werr(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
755 SetLastError(0xdeadbeef);
757 /* Calculate length only */
758 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
"tt HH':'mm'@'ss", NULL
, 0);
759 expect_wstr(ret
, NULL
, L
"AM 08:56@13");
761 /* TIME_NOMINUTESORSECONDS, default format */
762 ret
= pGetTimeFormatEx(localeW
, NUO
|TIME_NOMINUTESORSECONDS
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
763 expect_wstr(ret
, buffer
, L
"8 AM");
765 /* TIME_NOMINUTESORSECONDS/complex format */
766 wcscpy(buffer
, L
"pristine");
767 ret
= pGetTimeFormatEx(localeW
, TIME_NOMINUTESORSECONDS
, &curtime
, L
"m1s2m3s4", buffer
, ARRAY_SIZE(buffer
));
768 expect_wstr(ret
, buffer
, L
"");
770 /* TIME_NOSECONDS/Default format */
771 ret
= pGetTimeFormatEx(localeW
, NUO
|TIME_NOSECONDS
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
772 expect_wstr(ret
, buffer
, L
"8:56 AM");
775 wcscpy(buffer
, L
"pristine"); /* clear previous identical result */
776 ret
= pGetTimeFormatEx(localeW
, TIME_NOSECONDS
, &curtime
, L
"h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
777 expect_wstr(ret
, buffer
, L
"8:56 AM");
779 /* Multiple delimiters */
780 ret
= pGetTimeFormatEx(localeW
, TIME_NOSECONDS
, &curtime
, L
"h.@:m.@:s.@:tt", buffer
, ARRAY_SIZE(buffer
));
781 expect_wstr(ret
, buffer
, L
"8.@:56AM");
783 /* Duplicate tokens */
784 wcscpy(buffer
, L
"pristine");
785 ret
= pGetTimeFormatEx(localeW
, TIME_NOSECONDS
, &curtime
, L
"s1s2s3", buffer
, ARRAY_SIZE(buffer
));
786 expect_wstr(ret
, buffer
, L
"");
789 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"t/tt", buffer
, ARRAY_SIZE(buffer
));
790 expect_wstr(ret
, buffer
, L
"A/AM");
794 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"t/tt", buffer
, ARRAY_SIZE(buffer
));
795 expect_wstr(ret
, buffer
, L
"P/PM");
797 /* TIME_NOTIMEMARKER: removes text around time marker token */
798 ret
= pGetTimeFormatEx(localeW
, TIME_NOTIMEMARKER
, &curtime
, L
"h1t2tt3m", buffer
, ARRAY_SIZE(buffer
));
799 expect_wstr(ret
, buffer
, L
"156");
801 /* TIME_FORCE24HOURFORMAT */
802 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
"h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
803 expect_wstr(ret
, buffer
, L
"13:56:13 PM");
805 /* TIME_FORCE24HOURFORMAT doesn't add time marker */
806 ret
= pGetTimeFormatEx(localeW
, TIME_FORCE24HOURFORMAT
, &curtime
, L
"h:m:s", buffer
, ARRAY_SIZE(buffer
));
807 expect_wstr(ret
, buffer
, L
"13:56:13");
809 /* 24 hrs, leading 0 */
810 curtime
.wHour
= 14; /* change this to 14 or 2pm */
813 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h hh H HH m mm s ss t tt", buffer
, ARRAY_SIZE(buffer
));
814 expect_wstr(ret
, buffer
, L
"2 02 14 14 5 05 3 03 P PM");
818 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h/H/hh/HH", buffer
, ARRAY_SIZE(buffer
));
819 expect_wstr(ret
, buffer
, L
"12/0/12/00");
821 /* non-zero flags should fail with format, doesn't */
822 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h:m:s tt", buffer
, ARRAY_SIZE(buffer
));
823 expect_wstr(ret
, buffer
, L
"12:5:3 AM");
825 /* try to convert formatting strings with more than two letters
826 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
827 * NOTE: We expect any letter for which there is an upper case value
828 * we should see a replacement. For letters that DO NOT have
829 * upper case values we should see NO REPLACEMENT.
832 curtime
.wMinute
= 56;
833 curtime
.wSecond
= 13;
834 curtime
.wMilliseconds
= 22;
835 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", buffer
, ARRAY_SIZE(buffer
));
836 expect_wstr(ret
, buffer
, L
"8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
838 /* Don't write to buffer if len is 0 */
839 wcscpy(buffer
, L
"pristine");
840 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h:mm", buffer
, 0);
841 expect_wstr(ret
, NULL
, L
"8:56");
842 ok(wcscmp(buffer
, L
"pristine") == 0, "Expected a pristine buffer, got %s\n", wine_dbgstr_w(buffer
));
844 /* "'" preserves tokens */
845 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", buffer
, ARRAY_SIZE(buffer
));
846 expect_wstr(ret
, buffer
, L
"8 h 8 H 08 HH 56 m 13 s A t AM tt");
848 /* invalid quoted string */
849 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"'''", buffer
, ARRAY_SIZE(buffer
));
850 expect_wstr(ret
, buffer
, L
"'");
852 /* check that MSDN's suggested single quotation usage works as expected */
853 wcscpy(buffer
, L
"pristine"); /* clear previous identical result */
854 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"''''", buffer
, ARRAY_SIZE(buffer
));
855 expect_wstr(ret
, buffer
, L
"'");
858 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"''HHHHHH", buffer
, ARRAY_SIZE(buffer
));
859 expect_wstr(ret
, buffer
, L
"08");
861 /* and test for normal use of the single quotation mark */
862 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"'''HHHHHH'", buffer
, ARRAY_SIZE(buffer
));
863 expect_wstr(ret
, buffer
, L
"'HHHHHH");
866 wcscpy(buffer
, L
"pristine"); /* clear previous identical result */
867 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"'''HHHHHH", buffer
, ARRAY_SIZE(buffer
));
868 expect_wstr(ret
, buffer
, L
"'HHHHHH");
870 /* TIME_NOTIMEMARKER drops literals too */
871 ret
= pGetTimeFormatEx(localeW
, TIME_NOTIMEMARKER
, &curtime
, L
"'123'tt", buffer
, ARRAY_SIZE(buffer
));
872 expect_wstr(ret
, buffer
, L
"");
876 wcscpy(buffer
, L
"pristine");
877 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"'123'tt", buffer
, ARRAY_SIZE(buffer
));
878 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
879 SetLastError(0xdeadbeef);
884 ret
= pGetTimeFormatEx(localeW
, 0, &curtime
, L
"h:m:s", buffer
, ARRAY_SIZE(buffer
));
885 expect_wstr(ret
, buffer
, L
"12:56:13");
888 static void test_GetDateFormatA(void)
892 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
893 LCID lcid_ru
= MAKELCID(MAKELANGID(LANG_RUSSIAN
, SUBLANG_NEUTRAL
), SORT_DEFAULT
);
894 LCID lcid_ja
= MAKELCID(MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), SORT_DEFAULT
);
895 char buffer
[BUFFER_SIZE
], Expected
[BUFFER_SIZE
];
896 char short_day
[10], month
[10], genitive_month
[10];
898 SetLastError(0xdeadbeef);
901 memset(&curtime
, 2, sizeof(SYSTEMTIME
));
902 strcpy(buffer
, "pristine");
903 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd',' MMM dd yy", buffer
, ARRAY_SIZE(buffer
));
904 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
905 SetLastError(0xdeadbeef);
908 curtime
.wYear
= 2002;
911 curtime
.wDayOfWeek
= 3;
912 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd',' MMM dd yy", buffer
, ARRAY_SIZE(buffer
));
913 expect_str(ret
, buffer
, "Sat, May 04 02");
915 /* Same as above but with LOCALE_NOUSEROVERRIDE */
916 strcpy(buffer
, "pristine");
917 ret
= GetDateFormatA(lcid
, NUO
, &curtime
, "ddd',' MMM dd yy", buffer
, ARRAY_SIZE(buffer
));
918 expect_err(ret
, buffer
, ERROR_INVALID_FLAGS
);
919 SetLastError(0xdeadbeef);
921 /* Format containing "'" */
922 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd',' MMM dd yy", buffer
, ARRAY_SIZE(buffer
));
923 expect_str(ret
, buffer
, "Sat, May 04 02");
927 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd',' MMM dd ''''yy", buffer
, ARRAY_SIZE(buffer
));
928 expect_str(ret
, buffer
, "Sat, May 04 '02");
931 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd',' MMM dd ''''yy", NULL
, 0);
932 expect_str(ret
, NULL
, "Sat, May 04 '02");
934 /* Buffer too small */
935 strcpy(buffer
, "pristine");
936 ret
= GetDateFormatA(lcid
, 0, &curtime
, "ddd", buffer
, 2);
937 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
938 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
939 SetLastError(0xdeadbeef);
941 /* Default to DATE_SHORTDATE */
942 ret
= GetDateFormatA(lcid
, NUO
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
943 expect_str(ret
, buffer
, "5/4/2002");
946 ret
= GetDateFormatA(lcid
, NUO
|DATE_LONGDATE
, &curtime
, NULL
, buffer
, ARRAY_SIZE(buffer
));
947 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
948 ok(strcmp(buffer
, "Saturday, May 04, 2002") == 0 ||
949 strcmp(buffer
, "Saturday, May 4, 2002") == 0 /* Win 8 */,
950 "got an unexpected date string '%s'\n", buffer
);
952 /* test for expected DATE_YEARMONTH behavior with null format */
953 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
954 strcpy(buffer
, "pristine");
955 ret
= GetDateFormatA(lcid
, NUO
|DATE_YEARMONTH
, &curtime
, "ddd',' MMM dd ''''yy", buffer
, ARRAY_SIZE(buffer
));
956 expect_err(ret
, buffer
, ERROR_INVALID_FLAGS
);
957 SetLastError(0xdeadbeef);
959 /* Test that using invalid DATE_* flags results in the correct error */
960 /* and return values */
961 ret
= GetDateFormatA(lcid
, DATE_YEARMONTH
|DATE_SHORTDATE
|DATE_LONGDATE
, &curtime
, "m/d/y", buffer
, ARRAY_SIZE(buffer
));
962 expect_err(ret
, NULL
, ERROR_INVALID_FLAGS
);
963 SetLastError(0xdeadbeef);
965 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "ddMMMM", buffer
, ARRAY_SIZE(buffer
));
968 win_skip("LANG_RUSSIAN locale data unavailable\n");
972 /* month part should be in genitive form */
973 strcpy(genitive_month
, buffer
+ 2);
974 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "MMMM", buffer
, ARRAY_SIZE(buffer
));
975 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
976 strcpy(month
, buffer
);
977 ok(strcmp(genitive_month
, month
) != 0, "Expected different month forms\n");
979 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "ddd", buffer
, ARRAY_SIZE(buffer
));
980 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
981 strcpy(short_day
, buffer
);
983 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "dd MMMMddd dd", buffer
, ARRAY_SIZE(buffer
));
984 sprintf(Expected
, "04 %s%s 04", genitive_month
, short_day
);
985 expect_str(ret
, buffer
, Expected
);
987 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "MMMMddd dd", buffer
, ARRAY_SIZE(buffer
));
988 sprintf(Expected
, "%s%s 04", month
, short_day
);
989 expect_str(ret
, buffer
, Expected
);
991 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "MMMMddd", buffer
, ARRAY_SIZE(buffer
));
992 sprintf(Expected
, "%s%s", month
, short_day
);
993 expect_str(ret
, buffer
, Expected
);
995 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "MMMMdd", buffer
, ARRAY_SIZE(buffer
));
996 sprintf(Expected
, "%s04", genitive_month
);
997 expect_str(ret
, buffer
, Expected
);
999 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "MMMMdd ddd", buffer
, ARRAY_SIZE(buffer
));
1000 sprintf(Expected
, "%s04 %s", genitive_month
, short_day
);
1001 expect_str(ret
, buffer
, Expected
);
1003 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "dd dddMMMM", buffer
, ARRAY_SIZE(buffer
));
1004 sprintf(Expected
, "04 %s%s", short_day
, month
);
1005 expect_str(ret
, buffer
, Expected
);
1007 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "dd dddMMMM ddd MMMMdd", buffer
, ARRAY_SIZE(buffer
));
1008 sprintf(Expected
, "04 %s%s %s %s04", short_day
, month
, short_day
, genitive_month
);
1009 expect_str(ret
, buffer
, Expected
);
1011 /* with literal part */
1012 ret
= GetDateFormatA(lcid_ru
, 0, &curtime
, "ddd',' MMMM dd", buffer
, ARRAY_SIZE(buffer
));
1013 sprintf(Expected
, "%s, %s 04", short_day
, genitive_month
);
1014 expect_str(ret
, buffer
, Expected
);
1016 /* The ANSI string may be longer than the Unicode one.
1017 * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5".
1018 * See the corresponding GetDateFormatW() test.
1021 ret
= GetDateFormatA(lcid_ja
, 0, &curtime
, "d\x93\xfa", buffer
, 4);
1022 expect_str(ret
, buffer
, "4\x93\xfa"); /* only 2+1 WCHARs */
1024 ret
= GetDateFormatA(lcid_ja
, 0, &curtime
, "d\x93\xfa", buffer
, 3);
1025 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
1026 SetLastError(0xdeadbeef);
1028 strcpy(buffer
, "pristine"); /* clear previous identical result */
1029 ret
= GetDateFormatA(lcid_ja
, 0, &curtime
, "d\x93\xfa", NULL
, 0);
1030 expect_str(ret
, NULL
, "4\x93\xfa");
1033 static void test_GetDateFormatEx(void)
1037 WCHAR buffer
[BUFFER_SIZE
];
1039 if (!pGetDateFormatEx
)
1041 win_skip("GetDateFormatEx not supported\n");
1045 SetLastError(0xdeadbeef);
1047 /* If flags are set, then format must be NULL */
1048 wcscpy(buffer
, L
"pristine");
1049 ret
= pGetDateFormatEx(localeW
, DATE_LONGDATE
, NULL
, L
"", buffer
, ARRAY_SIZE(buffer
), NULL
);
1050 expect_werr(ret
, buffer
, ERROR_INVALID_FLAGS
);
1051 SetLastError(0xdeadbeef);
1053 /* NULL buffer, len > 0 */
1054 wcscpy(buffer
, L
"pristine");
1055 ret
= pGetDateFormatEx(localeW
, 0, NULL
, L
"", NULL
, ARRAY_SIZE(buffer
), NULL
);
1056 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1057 SetLastError(0xdeadbeef);
1059 /* NULL buffer, len == 0 */
1060 ret
= pGetDateFormatEx(localeW
, 0, NULL
, L
"", NULL
, 0, NULL
);
1061 expect_wstr(ret
, NULL
, L
"");
1063 /* Invalid flag combination */
1064 wcscpy(buffer
, L
"pristine");
1065 ret
= pGetDateFormatEx(localeW
, DATE_LONGDATE
|DATE_SHORTDATE
, NULL
,
1066 L
"", NULL
, 0, NULL
);
1067 expect_werr(ret
, buffer
, ERROR_INVALID_FLAGS
);
1068 SetLastError(0xdeadbeef);
1070 /* Incorrect DOW and time */
1071 curtime
.wYear
= 2002;
1072 curtime
.wMonth
= 10;
1074 curtime
.wDayOfWeek
= 45612; /* Should be 3 - Wednesday */
1075 curtime
.wHour
= 65432; /* Invalid */
1076 curtime
.wMinute
= 34512; /* Invalid */
1077 curtime
.wSecond
= 65535; /* Invalid */
1078 curtime
.wMilliseconds
= 12345;
1079 ret
= pGetDateFormatEx(localeW
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
), NULL
);
1080 expect_wstr(ret
, buffer
, L
"Wednesday 23 October 2002");
1082 curtime
.wYear
= 2002;
1083 curtime
.wMonth
= 10;
1085 curtime
.wDayOfWeek
= 45612; /* Should be 3 - Wednesday */
1086 curtime
.wHour
= 65432; /* Invalid */
1087 curtime
.wMinute
= 34512; /* Invalid */
1088 curtime
.wSecond
= 65535; /* Invalid */
1089 curtime
.wMilliseconds
= 12345;
1090 wcscpy(buffer
, L
"pristine");
1091 ret
= pGetDateFormatEx(localeW
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
), emptyW
); /* Use reserved arg */
1092 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1093 SetLastError(0xdeadbeef);
1097 curtime
.wYear
= 1601;
1100 curtime
.wDayOfWeek
= 0; /* Irrelevant */
1102 curtime
.wMinute
= 0;
1103 curtime
.wSecond
= 0;
1104 curtime
.wMilliseconds
= 0;
1105 ret
= pGetDateFormatEx(localeW
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
), NULL
);
1106 expect_wstr(ret
, buffer
, L
"Monday 1 January 1601");
1108 curtime
.wYear
= 1600;
1109 curtime
.wMonth
= 12;
1111 curtime
.wDayOfWeek
= 0; /* Irrelevant */
1113 curtime
.wMinute
= 59;
1114 curtime
.wSecond
= 59;
1115 curtime
.wMilliseconds
= 999;
1116 wcscpy(buffer
, L
"pristine");
1117 ret
= pGetDateFormatEx(localeW
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
), NULL
);
1118 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1121 static void test_GetDateFormatW(void)
1125 WCHAR buffer
[BUFFER_SIZE
];
1126 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
1128 SetLastError(0xdeadbeef);
1130 /* If flags is not zero then format must be NULL */
1131 wcscpy(buffer
, L
"pristine");
1132 ret
= GetDateFormatW(LOCALE_SYSTEM_DEFAULT
, DATE_LONGDATE
, NULL
, L
"", buffer
, ARRAY_SIZE(buffer
));
1133 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1135 win_skip("GetDateFormatW is not implemented\n");
1138 expect_werr(ret
, buffer
, ERROR_INVALID_FLAGS
);
1139 SetLastError(0xdeadbeef);
1141 /* NULL buffer, len > 0 */
1142 wcscpy(buffer
, L
"pristine");
1143 ret
= GetDateFormatW (lcid
, 0, NULL
, L
"", NULL
, ARRAY_SIZE(buffer
));
1144 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1145 SetLastError(0xdeadbeef);
1147 /* NULL buffer, len == 0 */
1148 ret
= GetDateFormatW (lcid
, 0, NULL
, L
"", NULL
, 0);
1149 expect_wstr(ret
, NULL
, L
"");
1151 /* Incorrect DOW and time */
1152 curtime
.wYear
= 2002;
1153 curtime
.wMonth
= 10;
1155 curtime
.wDayOfWeek
= 45612; /* Should be 3 - Wednesday */
1156 curtime
.wHour
= 65432; /* Invalid */
1157 curtime
.wMinute
= 34512; /* Invalid */
1158 curtime
.wSecond
= 65535; /* Invalid */
1159 curtime
.wMilliseconds
= 12345;
1160 ret
= GetDateFormatW (lcid
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
));
1161 expect_wstr(ret
, buffer
, L
"Wednesday 23 October 2002");
1165 curtime
.wYear
= 1601;
1168 curtime
.wDayOfWeek
= 0; /* Irrelevant */
1170 curtime
.wMinute
= 0;
1171 curtime
.wSecond
= 0;
1172 curtime
.wMilliseconds
= 0;
1173 ret
= GetDateFormatW (lcid
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
));
1174 expect_wstr(ret
, buffer
, L
"Monday 1 January 1601");
1176 curtime
.wYear
= 1600;
1177 curtime
.wMonth
= 12;
1179 curtime
.wDayOfWeek
= 0; /* Irrelevant */
1181 curtime
.wMinute
= 59;
1182 curtime
.wSecond
= 59;
1183 curtime
.wMilliseconds
= 999;
1184 wcscpy(buffer
, L
"pristine");
1185 ret
= GetDateFormatW (lcid
, 0, &curtime
, L
"dddd d MMMM yyyy", buffer
, ARRAY_SIZE(buffer
));
1186 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1187 SetLastError(0xdeadbeef);
1189 /* See the corresponding GetDateFormatA() test */
1191 lcid
= MAKELCID(MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), SORT_DEFAULT
);
1193 curtime
.wYear
= 2002;
1196 ret
= GetDateFormatW(lcid
, 0, &curtime
, L
"d\x65e5", buffer
, 3);
1197 expect_wstr(ret
, buffer
, L
"4\x65e5");
1199 ret
= GetDateFormatW(lcid
, 0, &curtime
, L
"d\x65e5", NULL
, 0);
1200 expect_wstr(ret
, NULL
, L
"4\x65e5");
1204 #define CY_POS_LEFT 0
1205 #define CY_POS_RIGHT 1
1206 #define CY_POS_LEFT_SPACE 2
1207 #define CY_POS_RIGHT_SPACE 3
1209 static void test_GetCurrencyFormatA(void)
1211 static char szDot
[] = { '.', '\0' };
1212 static char szComma
[] = { ',', '\0' };
1213 static char szDollar
[] = { '$', '\0' };
1214 static const char* const negative_order
[] =
1233 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
1234 char buffer
[BUFFER_SIZE
];
1235 CURRENCYFMTA format
;
1237 SetLastError(0xdeadbeef);
1239 /* NULL output, length > 0 --> Error */
1240 ret
= GetCurrencyFormatA(lcid
, 0, "23", NULL
, NULL
, ARRAY_SIZE(buffer
));
1241 expect_err(ret
, NULL
, ERROR_INVALID_PARAMETER
);
1242 SetLastError(0xdeadbeef);
1244 /* Invalid character --> Error */
1245 strcpy(buffer
, "pristine");
1246 ret
= GetCurrencyFormatA(lcid
, 0, "23,53", NULL
, buffer
, ARRAY_SIZE(buffer
));
1247 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1248 SetLastError(0xdeadbeef);
1250 /* Double '-' --> Error */
1251 strcpy(buffer
, "pristine");
1252 ret
= GetCurrencyFormatA(lcid
, 0, "--", NULL
, buffer
, ARRAY_SIZE(buffer
));
1253 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1254 SetLastError(0xdeadbeef);
1256 /* Trailing '-' --> Error */
1257 strcpy(buffer
, "pristine");
1258 ret
= GetCurrencyFormatA(lcid
, 0, "0-", NULL
, buffer
, ARRAY_SIZE(buffer
));
1259 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1260 SetLastError(0xdeadbeef);
1262 /* Double '.' --> Error */
1263 strcpy(buffer
, "pristine");
1264 ret
= GetCurrencyFormatA(lcid
, 0, "0..", NULL
, buffer
, ARRAY_SIZE(buffer
));
1265 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1266 SetLastError(0xdeadbeef);
1268 /* Leading space --> Error */
1269 ret
= GetCurrencyFormatA(lcid
, 0, " 0.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1270 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1271 SetLastError(0xdeadbeef);
1273 /* Length too small --> Write up to length chars */
1274 strcpy(buffer
, "pristine");
1275 ret
= GetCurrencyFormatA(lcid
, NUO
, "1234", NULL
, buffer
, 2);
1276 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1277 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
1278 SetLastError(0xdeadbeef);
1281 ret
= GetCurrencyFormatA(lcid
, NUO
, "2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1282 expect_str(ret
, buffer
, "$2,353.00");
1284 /* Valid negative number */
1285 ret
= GetCurrencyFormatA(lcid
, NUO
, "-2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1286 expect_str(ret
, buffer
, "($2,353.00)");
1288 /* Valid real number */
1289 ret
= GetCurrencyFormatA(lcid
, NUO
, "2353.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1290 expect_str(ret
, buffer
, "$2,353.10");
1292 /* Too many DP --> Truncated */
1293 ret
= GetCurrencyFormatA(lcid
, NUO
, "2353.111", NULL
, buffer
, ARRAY_SIZE(buffer
));
1294 expect_str(ret
, buffer
, "$2,353.11");
1296 /* Too many DP --> Rounded */
1297 ret
= GetCurrencyFormatA(lcid
, NUO
, "2353.119", NULL
, buffer
, ARRAY_SIZE(buffer
));
1298 expect_str(ret
, buffer
, "$2,353.12");
1300 /* Format and flags given --> Error */
1301 memset(&format
, 0, sizeof(format
));
1302 strcpy(buffer
, "pristine");
1303 ret
= GetCurrencyFormatA(lcid
, NUO
, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1304 expect_err(ret
, buffer
, ERROR_INVALID_FLAGS
);
1305 SetLastError(0xdeadbeef);
1307 /* Invalid format --> Error */
1308 strcpy(buffer
, "pristine");
1309 ret
= GetCurrencyFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1310 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1311 SetLastError(0xdeadbeef);
1313 format
.NumDigits
= 0; /* No decimal separator */
1314 format
.LeadingZero
= 0;
1315 format
.Grouping
= 0; /* No grouping char */
1316 format
.NegativeOrder
= 0;
1317 format
.PositiveOrder
= CY_POS_LEFT
;
1318 format
.lpDecimalSep
= szDot
;
1319 format
.lpThousandSep
= szComma
;
1320 format
.lpCurrencySymbol
= szDollar
;
1322 /* No decimal or grouping chars expected */
1323 ret
= GetCurrencyFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1324 expect_str(ret
, buffer
, "$2353");
1326 /* 1 DP --> Expect decimal separator */
1327 format
.NumDigits
= 1;
1328 ret
= GetCurrencyFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1329 expect_str(ret
, buffer
, "$2353.0");
1331 /* Group by 100's */
1332 format
.Grouping
= 2;
1333 ret
= GetCurrencyFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1334 expect_str(ret
, buffer
, "$23,53.0");
1336 /* Grouping of a positive number */
1337 format
.Grouping
= 3;
1338 ret
= GetCurrencyFormatA(lcid
, 0, "235", &format
, buffer
, ARRAY_SIZE(buffer
));
1339 expect_str(ret
, buffer
, "$235.0");
1341 format
.Grouping
= 31;
1342 ret
= GetCurrencyFormatA(lcid
, 0, "1234567890", &format
, buffer
, ARRAY_SIZE(buffer
));
1343 expect_str(ret
, buffer
, "$1,2,3,4,5,6,7,890.0");
1345 format
.Grouping
= 312;
1346 ret
= GetCurrencyFormatA(lcid
, 0, "1234567890", &format
, buffer
, ARRAY_SIZE(buffer
));
1347 expect_str(ret
, buffer
, "$12,34,56,7,890.0");
1349 format
.Grouping
= 310;
1350 ret
= GetCurrencyFormatA(lcid
, 0, "1234567890", &format
, buffer
, ARRAY_SIZE(buffer
));
1351 expect_str(ret
, buffer
, "$123456,7,890.0");
1353 /* Grouping of a negative number */
1354 format
.NegativeOrder
= 2;
1355 ret
= GetCurrencyFormatA(lcid
, 0, "-235", &format
, buffer
, ARRAY_SIZE(buffer
));
1356 expect_str(ret
, buffer
, "$-235.0");
1358 /* Always provide leading zero */
1359 format
.LeadingZero
= 1;
1360 ret
= GetCurrencyFormatA(lcid
, 0, ".5", &format
, buffer
, ARRAY_SIZE(buffer
));
1361 expect_str(ret
, buffer
, "$0.5");
1362 ret
= GetCurrencyFormatA(lcid
, 0, "0.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1363 expect_str(ret
, buffer
, "$0.5");
1365 format
.LeadingZero
= 0;
1366 ret
= GetCurrencyFormatA(lcid
, 0, "0.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1367 expect_str(ret
, buffer
, "$.5");
1368 ret
= GetCurrencyFormatA(lcid
, 0, "0.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1369 expect_str(ret
, buffer
, "$.5");
1371 format
.PositiveOrder
= CY_POS_RIGHT
;
1372 ret
= GetCurrencyFormatA(lcid
, 0, "1", &format
, buffer
, ARRAY_SIZE(buffer
));
1373 expect_str(ret
, buffer
, "1.0$");
1375 format
.PositiveOrder
= CY_POS_LEFT_SPACE
;
1376 ret
= GetCurrencyFormatA(lcid
, 0, "1", &format
, buffer
, ARRAY_SIZE(buffer
));
1377 expect_str(ret
, buffer
, "$ 1.0");
1379 format
.PositiveOrder
= CY_POS_RIGHT_SPACE
;
1380 ret
= GetCurrencyFormatA(lcid
, 0, "1", &format
, buffer
, ARRAY_SIZE(buffer
));
1381 expect_str(ret
, buffer
, "1.0 $");
1384 for (o
= 0; o
<= 15; o
++)
1386 winetest_push_context("%d", o
);
1387 format
.NegativeOrder
= o
;
1388 strcpy(buffer
, "pristine");
1389 ret
= GetCurrencyFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1390 expect_str(ret
, buffer
, negative_order
[o
]);
1391 winetest_pop_context();
1395 #define NEG_PARENS 0 /* "(1.1)" */
1396 #define NEG_LEFT 1 /* "-1.1" */
1397 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1398 #define NEG_RIGHT 3 /* "1.1-" */
1399 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1401 static void test_GetNumberFormatA(void)
1403 static char szDot
[] = { '.', '\0' };
1404 static char szComma
[] = { ',', '\0' };
1406 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
1407 WCHAR grouping
[32], t1000
[8], dec
[8], frac
[8], lzero
[8];
1408 char buffer
[BUFFER_SIZE
];
1411 SetLastError(0xdeadbeef);
1413 /* NULL output, length > 0 --> Error */
1414 strcpy(buffer
, "pristine");
1415 ret
= GetNumberFormatA(lcid
, 0, "23", NULL
, NULL
, ARRAY_SIZE(buffer
));
1416 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1417 SetLastError(0xdeadbeef);
1419 /* Invalid character --> Error */
1420 strcpy(buffer
, "pristine");
1421 ret
= GetNumberFormatA(lcid
, 0, "23,53", NULL
, buffer
, ARRAY_SIZE(buffer
));
1422 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1423 SetLastError(0xdeadbeef);
1425 /* Double '-' --> Error */
1426 strcpy(buffer
, "pristine");
1427 ret
= GetNumberFormatA(lcid
, 0, "--", NULL
, buffer
, ARRAY_SIZE(buffer
));
1428 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1429 SetLastError(0xdeadbeef);
1431 /* Trailing '-' --> Error */
1432 strcpy(buffer
, "pristine");
1433 ret
= GetNumberFormatA(lcid
, 0, "0-", NULL
, buffer
, ARRAY_SIZE(buffer
));
1434 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1435 SetLastError(0xdeadbeef);
1437 /* Double '.' --> Error */
1438 strcpy(buffer
, "pristine");
1439 ret
= GetNumberFormatA(lcid
, 0, "0..", NULL
, buffer
, ARRAY_SIZE(buffer
));
1440 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1441 SetLastError(0xdeadbeef);
1443 /* Leading space --> Error */
1444 strcpy(buffer
, "pristine");
1445 ret
= GetNumberFormatA(lcid
, 0, " 0.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1446 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1447 SetLastError(0xdeadbeef);
1449 /* Length too small --> Write up to length chars */
1450 ret
= GetNumberFormatA(lcid
, NUO
, "1234", NULL
, buffer
, 2);
1451 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1452 expect_err(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
1453 SetLastError(0xdeadbeef);
1456 ret
= GetNumberFormatA(lcid
, NUO
, "2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1457 expect_str(ret
, buffer
, "2,353.00");
1459 /* Valid negative number */
1460 ret
= GetNumberFormatA(lcid
, NUO
, "-2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1461 expect_str(ret
, buffer
, "-2,353.00");
1463 /* test for off by one error in grouping */
1464 ret
= GetNumberFormatA(lcid
, NUO
, "-353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1465 expect_str(ret
, buffer
, "-353.00");
1467 /* Valid real number */
1468 ret
= GetNumberFormatA(lcid
, NUO
, "2353.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1469 expect_str(ret
, buffer
, "2,353.10");
1471 /* Too many DP --> Truncated */
1472 ret
= GetNumberFormatA(lcid
, NUO
, "2353.111", NULL
, buffer
, ARRAY_SIZE(buffer
));
1473 expect_str(ret
, buffer
, "2,353.11");
1475 /* Too many DP --> Rounded */
1476 ret
= GetNumberFormatA(lcid
, NUO
, "2353.119", NULL
, buffer
, ARRAY_SIZE(buffer
));
1477 expect_str(ret
, buffer
, "2,353.12");
1479 /* Format and flags given --> Error */
1480 memset(&format
, 0, sizeof(format
));
1481 strcpy(buffer
, "pristine");
1482 ret
= GetNumberFormatA(lcid
, NUO
, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1483 expect_err(ret
, buffer
, ERROR_INVALID_FLAGS
);
1484 SetLastError(0xdeadbeef);
1486 /* Invalid format --> Error */
1487 strcpy(buffer
, "pristine");
1488 ret
= GetNumberFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1489 expect_err(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1490 SetLastError(0xdeadbeef);
1492 format
.NumDigits
= 0; /* No decimal separator */
1493 format
.LeadingZero
= 0;
1494 format
.Grouping
= 0; /* No grouping char */
1495 format
.NegativeOrder
= 0;
1496 format
.lpDecimalSep
= szDot
;
1497 format
.lpThousandSep
= szComma
;
1499 /* No decimal or grouping chars expected */
1500 ret
= GetNumberFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1501 expect_str(ret
, buffer
, "2353");
1503 format
.NumDigits
= 1; /* 1 DP --> Expect decimal separator */
1504 ret
= GetNumberFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1505 expect_str(ret
, buffer
, "2353.0");
1507 format
.Grouping
= 2; /* Group by 100's */
1508 ret
= GetNumberFormatA(lcid
, 0, "2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1509 expect_str(ret
, buffer
, "23,53.0");
1511 /* Grouping of a positive number */
1512 format
.Grouping
= 3;
1513 ret
= GetNumberFormatA(lcid
, 0, "235", &format
, buffer
, ARRAY_SIZE(buffer
));
1514 expect_str(ret
, buffer
, "235.0");
1515 ret
= GetNumberFormatA(lcid
, 0, "000235", &format
, buffer
, ARRAY_SIZE(buffer
));
1516 expect_str(ret
, buffer
, "235.0");
1518 format
.Grouping
= 23;
1519 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1520 expect_str(ret
, buffer
, "1,234,567,89.0");
1522 format
.Grouping
= 230;
1523 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1524 expect_str(ret
, buffer
, "1234,567,89.0");
1526 format
.Grouping
= 203;
1527 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1528 expect_str(ret
, buffer
, "1,234,567,,89.0");
1530 format
.Grouping
= 2030;
1531 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1532 expect_str(ret
, buffer
, "1234,567,,89.0");
1534 format
.Grouping
= 2003;
1535 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1536 expect_str(ret
, buffer
, "1,234,567,,,89.0");
1538 format
.Grouping
= 1200;
1539 ret
= GetNumberFormatA(lcid
, 0, "123456789", &format
, buffer
, ARRAY_SIZE(buffer
));
1540 expect_str(ret
, buffer
, "123456,,78,9.0");
1542 /* Grouping of a negative number */
1543 format
.NegativeOrder
= NEG_LEFT
;
1544 format
.Grouping
= 3;
1545 ret
= GetNumberFormatA(lcid
, 0, "-235", &format
, buffer
, ARRAY_SIZE(buffer
));
1546 expect_str(ret
, buffer
, "-235.0");
1547 ret
= GetNumberFormatA(lcid
, 0, "-000235", &format
, buffer
, ARRAY_SIZE(buffer
));
1548 expect_str(ret
, buffer
, "-235.0");
1550 format
.LeadingZero
= 1; /* Always provide leading zero */
1551 ret
= GetNumberFormatA(lcid
, 0, ".5", &format
, buffer
, ARRAY_SIZE(buffer
));
1552 expect_str(ret
, buffer
, "0.5");
1553 ret
= GetNumberFormatA(lcid
, 0, "0000.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1554 expect_str(ret
, buffer
, "0.5");
1556 format
.NegativeOrder
= NEG_PARENS
;
1557 ret
= GetNumberFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1558 expect_str(ret
, buffer
, "(1.0)");
1560 format
.NegativeOrder
= NEG_LEFT
;
1561 ret
= GetNumberFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1562 expect_str(ret
, buffer
, "-1.0");
1564 format
.NegativeOrder
= NEG_LEFT_SPACE
;
1565 ret
= GetNumberFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1566 expect_str(ret
, buffer
, "- 1.0");
1568 format
.NegativeOrder
= NEG_RIGHT
;
1569 ret
= GetNumberFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1570 expect_str(ret
, buffer
, "1.0-");
1572 format
.NegativeOrder
= NEG_RIGHT_SPACE
;
1573 ret
= GetNumberFormatA(lcid
, 0, "-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1574 expect_str(ret
, buffer
, "1.0 -");
1576 /* Test French formatting */
1577 lcid
= MAKELCID(MAKELANGID(LANG_FRENCH
, SUBLANG_DEFAULT
), SORT_DEFAULT
);
1578 if (IsValidLocale(lcid
, 0))
1580 ret
= GetNumberFormatA(lcid
, NUO
, "-12345", NULL
, buffer
, ARRAY_SIZE(buffer
));
1581 expect_str(ret
, buffer
, "-12\xa0\x33\x34\x35,00"); /* Non breaking space */
1584 /* Test the actual LOCALE_SGROUPING string, the rules for repeats are opposite */
1585 if (GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
, ARRAY_SIZE(grouping
)) &&
1586 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, t1000
, ARRAY_SIZE(t1000
)) &&
1587 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, dec
, ARRAY_SIZE(dec
)) &&
1588 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDIGITS
, frac
, ARRAY_SIZE(frac
)) &&
1589 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
, lzero
, ARRAY_SIZE(lzero
)))
1593 const char *grouping
;
1594 const char *expected
;
1596 { "3;0", "1,234,567,890.54321" },
1597 { "2;3", "12345,678,90.54321" },
1598 { "1", "123456789,0.54321" },
1599 { "1;0", "1,2,3,4,5,6,7,8,9,0.54321" },
1600 { "1;0;3", "123456,789,,0.54321" },
1601 { "0", "1234567890.54321" },
1602 { "0;0", "1234567890.54321" },
1603 { "0;1", "123456789,0.54321" },
1604 { "0;0;0", "1234567890.54321" },
1605 { "0;1;0", "1,2,3,4,5,6,7,8,9,0.54321" },
1606 { "2;0;0", "12345678,90.54321" },
1607 { "2;0;0;0", "12345678,,90.54321" },
1608 { "2;0;0;0;0", "12345678,,,90.54321" },
1609 { "2;0;0;1;0", "1,2,3,4,5,6,7,8,,,90.54321" },
1610 { "1;3;2", "1234,56,789,0.54321" },
1611 { "1;3;2;0", "12,34,56,789,0.54321" },
1612 { "3;1;1;2;0", "1,23,45,6,7,890.54321" },
1613 { "6;1", "123,4,567890.54321" },
1617 SetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, ",");
1618 SetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, ".");
1619 SetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_IDIGITS
, "5");
1620 SetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
, "0");
1622 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
1624 SetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, tests
[i
].grouping
);
1625 SetLastError(0xdeadbeef);
1626 ret
= GetNumberFormatA(LOCALE_USER_DEFAULT
, 0, "1234567890.54321", NULL
, buffer
, ARRAY_SIZE(buffer
));
1629 ok(GetLastError() == 0xdeadbeef, "[%u] unexpected error %lu\n", i
, GetLastError());
1630 ok(ret
== strlen(tests
[i
].expected
) + 1, "[%u] unexpected ret %d\n", i
, ret
);
1631 ok(!strcmp(buffer
, tests
[i
].expected
), "[%u] unexpected string %s\n", i
, buffer
);
1634 ok(0, "[%u] expected success, got error %ld\n", i
, GetLastError());
1638 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
), "Restoring SGROUPING failed\n");
1639 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, t1000
), "Restoring STHOUSAND failed\n");
1640 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, dec
), "Restoring SDECIMAL failed\n");
1641 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDIGITS
, frac
), "Restoring IDIGITS failed\n");
1642 ok(SetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
, lzero
), "Restoring ILZERO failed\n");
1646 static void test_GetNumberFormatEx(void)
1650 static WCHAR dotW
[] = {'.',0};
1651 static WCHAR commaW
[] = {',',0};
1652 static const WCHAR enW
[] = {'e','n','-','U','S',0};
1653 static const WCHAR frW
[] = {'f','r','-','F','R',0};
1654 static const WCHAR bogusW
[] = {'b','o','g','u','s',0};
1655 WCHAR buffer
[BUFFER_SIZE
];
1657 if (!pGetNumberFormatEx
)
1659 win_skip("GetNumberFormatEx is not available.\n");
1663 SetLastError(0xdeadbeef);
1665 /* NULL output, length > 0 --> Error */
1666 wcscpy(buffer
, L
"pristine");
1667 ret
= pGetNumberFormatEx(enW
, 0, L
"23", NULL
, NULL
, ARRAY_SIZE(buffer
));
1668 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1669 SetLastError(0xdeadbeef);
1671 /* Invalid character --> Error */
1672 wcscpy(buffer
, L
"pristine");
1673 ret
= pGetNumberFormatEx(enW
, 0, L
"23,53", NULL
, buffer
, ARRAY_SIZE(buffer
));
1674 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1675 SetLastError(0xdeadbeef);
1677 /* Double '-' --> Error */
1678 wcscpy(buffer
, L
"pristine");
1679 ret
= pGetNumberFormatEx(enW
, 0, L
"--", NULL
, buffer
, ARRAY_SIZE(buffer
));
1680 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1681 SetLastError(0xdeadbeef);
1683 /* Trailing '-' --> Error */
1684 wcscpy(buffer
, L
"pristine");
1685 ret
= pGetNumberFormatEx(enW
, 0, L
"0-", NULL
, buffer
, ARRAY_SIZE(buffer
));
1686 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1687 SetLastError(0xdeadbeef);
1689 /* Double '.' --> Error */
1690 wcscpy(buffer
, L
"pristine");
1691 ret
= pGetNumberFormatEx(enW
, 0, L
"0..", NULL
, buffer
, ARRAY_SIZE(buffer
));
1692 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1693 SetLastError(0xdeadbeef);
1695 /* Leading space --> Error */
1696 wcscpy(buffer
, L
"pristine");
1697 ret
= pGetNumberFormatEx(enW
, 0, L
" 0.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1698 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1699 SetLastError(0xdeadbeef);
1701 /* Length too small --> Write up to length chars */
1702 wcscpy(buffer
, L
"pristine");
1703 ret
= pGetNumberFormatEx(enW
, NUO
, L
"1234", NULL
, buffer
, 2);
1704 /* there is no guarantee on the buffer content, see GetTimeFormatA() */
1705 expect_werr(ret
, NULL
, ERROR_INSUFFICIENT_BUFFER
);
1706 SetLastError(0xdeadbeef);
1708 /* Bogus locale --> Error */
1709 wcscpy(buffer
, L
"pristine");
1710 ret
= pGetNumberFormatEx(bogusW
, NUO
, L
"23", NULL
, buffer
, ARRAY_SIZE(buffer
));
1711 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1712 SetLastError(0xdeadbeef);
1714 memset(&format
, 0, sizeof(format
));
1716 /* Format and flags given --> Error */
1717 wcscpy(buffer
, L
"pristine");
1718 ret
= pGetNumberFormatEx(enW
, NUO
, L
"2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1719 expect_werr(ret
, buffer
, ERROR_INVALID_FLAGS
);
1720 SetLastError(0xdeadbeef);
1722 /* Invalid format --> Error */
1723 wcscpy(buffer
, L
"pristine");
1724 ret
= pGetNumberFormatEx(enW
, 0, L
"2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1725 expect_werr(ret
, buffer
, ERROR_INVALID_PARAMETER
);
1726 SetLastError(0xdeadbeef);
1729 ret
= pGetNumberFormatEx(enW
, NUO
, L
"2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1730 expect_wstr(ret
, buffer
, L
"2,353.00");
1732 /* Valid negative number */
1733 ret
= pGetNumberFormatEx(enW
, NUO
, L
"-2353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1734 expect_wstr(ret
, buffer
, L
"-2,353.00");
1736 /* test for off by one error in grouping */
1737 ret
= pGetNumberFormatEx(enW
, NUO
, L
"-353", NULL
, buffer
, ARRAY_SIZE(buffer
));
1738 expect_wstr(ret
, buffer
, L
"-353.00");
1740 /* Valid real number */
1741 ret
= pGetNumberFormatEx(enW
, NUO
, L
"2353.1", NULL
, buffer
, ARRAY_SIZE(buffer
));
1742 expect_wstr(ret
, buffer
, L
"2,353.10");
1744 /* Too many DP --> Truncated */
1745 ret
= pGetNumberFormatEx(enW
, NUO
, L
"2353.111", NULL
, buffer
, ARRAY_SIZE(buffer
));
1746 expect_wstr(ret
, buffer
, L
"2,353.11");
1748 /* Too many DP --> Rounded */
1749 ret
= pGetNumberFormatEx(enW
, NUO
, L
"2353.119", NULL
, buffer
, ARRAY_SIZE(buffer
));
1750 expect_wstr(ret
, buffer
, L
"2,353.12");
1752 format
.NumDigits
= 0; /* No decimal separator */
1753 format
.LeadingZero
= 0;
1754 format
.Grouping
= 0; /* No grouping char */
1755 format
.NegativeOrder
= 0;
1756 format
.lpDecimalSep
= dotW
;
1757 format
.lpThousandSep
= commaW
;
1759 /* No decimal or grouping chars expected */
1760 ret
= pGetNumberFormatEx(enW
, 0, L
"2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1761 expect_wstr(ret
, buffer
, L
"2353");
1763 /* 1 DP --> Expect decimal separator */
1764 format
.NumDigits
= 1;
1765 ret
= pGetNumberFormatEx(enW
, 0, L
"2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1766 expect_wstr(ret
, buffer
, L
"2353.0");
1768 /* Group by 100's */
1769 format
.Grouping
= 2;
1770 ret
= pGetNumberFormatEx(enW
, 0, L
"2353", &format
, buffer
, ARRAY_SIZE(buffer
));
1771 expect_wstr(ret
, buffer
, L
"23,53.0");
1773 /* Grouping of a positive number */
1774 format
.Grouping
= 3;
1775 ret
= pGetNumberFormatEx(enW
, 0, L
"235", &format
, buffer
, ARRAY_SIZE(buffer
));
1776 expect_wstr(ret
, buffer
, L
"235.0");
1778 /* Grouping of a negative number */
1779 format
.NegativeOrder
= NEG_LEFT
;
1780 ret
= pGetNumberFormatEx(enW
, 0, L
"-235", &format
, buffer
, ARRAY_SIZE(buffer
));
1781 expect_wstr(ret
, buffer
, L
"-235.0");
1783 /* Always provide leading zero */
1784 format
.LeadingZero
= 1;
1785 ret
= pGetNumberFormatEx(enW
, 0, L
".5", &format
, buffer
, ARRAY_SIZE(buffer
));
1786 expect_wstr(ret
, buffer
, L
"0.5");
1787 ret
= pGetNumberFormatEx(enW
, 0, L
"0.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1788 expect_wstr(ret
, buffer
, L
"0.5");
1790 format
.LeadingZero
= 0;
1791 ret
= pGetNumberFormatEx(enW
, 0, L
".5", &format
, buffer
, ARRAY_SIZE(buffer
));
1792 expect_wstr(ret
, buffer
, L
".5");
1793 ret
= pGetNumberFormatEx(enW
, 0, L
"0.5", &format
, buffer
, ARRAY_SIZE(buffer
));
1794 expect_wstr(ret
, buffer
, L
".5");
1796 format
.NegativeOrder
= NEG_PARENS
;
1797 ret
= pGetNumberFormatEx(enW
, 0, L
"-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1798 expect_wstr(ret
, buffer
, L
"(1.0)");
1800 format
.NegativeOrder
= NEG_LEFT
;
1801 ret
= pGetNumberFormatEx(enW
, 0, L
"-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1802 expect_wstr(ret
, buffer
, L
"-1.0");
1804 format
.NegativeOrder
= NEG_LEFT_SPACE
;
1805 ret
= pGetNumberFormatEx(enW
, 0, L
"-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1806 expect_wstr(ret
, buffer
, L
"- 1.0");
1808 format
.NegativeOrder
= NEG_RIGHT
;
1809 ret
= pGetNumberFormatEx(enW
, 0, L
"-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1810 expect_wstr(ret
, buffer
, L
"1.0-");
1812 format
.NegativeOrder
= NEG_RIGHT_SPACE
;
1813 ret
= pGetNumberFormatEx(enW
, 0, L
"-1", &format
, buffer
, ARRAY_SIZE(buffer
));
1814 expect_wstr(ret
, buffer
, L
"1.0 -");
1816 /* Test French formatting */
1817 if (pIsValidLocaleName(frW
))
1819 const WCHAR
*expected
;
1820 ret
= pGetNumberFormatEx(frW
, NUO
, L
"-12345", NULL
, buffer
, ARRAY_SIZE(buffer
));
1821 expected
= (ret
&& wcschr(buffer
, 0x202f)) ?
1822 L
"-12\x202f\x33\x34\x35,00" : /* Same but narrow (win11) */
1823 L
"-12\xa0\x33\x34\x35,00"; /* Non breaking space */
1824 expect_wstr(ret
, buffer
, expected
);
1828 struct comparestringa_entry
{
1839 static const struct comparestringa_entry comparestringa_data
[] = {
1840 { LOCALE_SYSTEM_DEFAULT
, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN
},
1841 { LOCALE_SYSTEM_DEFAULT
, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN
},
1842 { LOCALE_SYSTEM_DEFAULT
, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN
},
1843 { LOCALE_SYSTEM_DEFAULT
, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN
},
1844 { LOCALE_SYSTEM_DEFAULT
, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN
},
1845 { LOCALE_SYSTEM_DEFAULT
, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN
},
1846 { LOCALE_SYSTEM_DEFAULT
, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN
},
1847 { LOCALE_SYSTEM_DEFAULT
, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN
},
1848 { LOCALE_SYSTEM_DEFAULT
, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN
},
1849 { LOCALE_SYSTEM_DEFAULT
, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN
},
1850 { LOCALE_SYSTEM_DEFAULT
, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN
},
1851 { LOCALE_SYSTEM_DEFAULT
, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN
},
1852 { LOCALE_SYSTEM_DEFAULT
, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN
},
1853 { LOCALE_SYSTEM_DEFAULT
, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN
},
1854 { LOCALE_SYSTEM_DEFAULT
, 0, "a", -1, "{", -1, CSTR_GREATER_THAN
},
1855 { LOCALE_SYSTEM_DEFAULT
, 0, "A", -1, "{", -1, CSTR_GREATER_THAN
},
1856 { LOCALE_SYSTEM_DEFAULT
, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN
},
1857 { LOCALE_SYSTEM_DEFAULT
, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN
},
1858 { LOCALE_SYSTEM_DEFAULT
, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN
},
1859 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1860 { LOCALE_SYSTEM_DEFAULT
, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN
},
1861 { LOCALE_SYSTEM_DEFAULT
, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN
},
1862 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "-o", -1, "/m", -1, CSTR_LESS_THAN
},
1863 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "/m", -1, "-o", -1, CSTR_GREATER_THAN
},
1864 { LOCALE_SYSTEM_DEFAULT
, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN
},
1865 { LOCALE_SYSTEM_DEFAULT
, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN
},
1866 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "'o", -1, "/m", -1, CSTR_LESS_THAN
},
1867 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "/m", -1, "'o", -1, CSTR_GREATER_THAN
},
1868 { LOCALE_SYSTEM_DEFAULT
, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL
},
1869 { LOCALE_SYSTEM_DEFAULT
, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN
},
1870 { LOCALE_SYSTEM_DEFAULT
, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN
},
1871 { LOCALE_SYSTEM_DEFAULT
, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN
},
1872 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "a-", 3, "a\0", 3, CSTR_GREATER_THAN
},
1873 { LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "a'", 3, "a\0", 3, CSTR_GREATER_THAN
},
1874 { LOCALE_SYSTEM_DEFAULT
, NORM_IGNORESYMBOLS
, "a.", 3, "a\0", 3, CSTR_EQUAL
},
1875 { LOCALE_SYSTEM_DEFAULT
, NORM_IGNORESYMBOLS
, "a ", 3, "a\0", 3, CSTR_EQUAL
},
1876 { LOCALE_SYSTEM_DEFAULT
, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL
},
1877 { LOCALE_SYSTEM_DEFAULT
, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL
},
1878 { LOCALE_SYSTEM_DEFAULT
, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL
},
1879 { LOCALE_SYSTEM_DEFAULT
, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL
},
1880 { LOCALE_SYSTEM_DEFAULT
, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN
},
1881 { LOCALE_SYSTEM_DEFAULT
, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN
},
1882 { LOCALE_SYSTEM_DEFAULT
, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN
},
1883 { LOCALE_SYSTEM_DEFAULT
, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN
},
1885 { LOCALE_SYSTEM_DEFAULT
, LOCALE_USE_CP_ACP
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1886 { LOCALE_SYSTEM_DEFAULT
, LINGUISTIC_IGNORECASE
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1887 { LOCALE_SYSTEM_DEFAULT
, LINGUISTIC_IGNOREDIACRITIC
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1888 { LOCALE_SYSTEM_DEFAULT
, NORM_IGNOREKANATYPE
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1889 { LOCALE_SYSTEM_DEFAULT
, NORM_IGNORENONSPACE
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1890 { LOCALE_SYSTEM_DEFAULT
, NORM_IGNOREWIDTH
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1891 { LOCALE_SYSTEM_DEFAULT
, NORM_LINGUISTIC_CASING
, "NULL", -1, "NULL", -1, CSTR_EQUAL
},
1892 { LOCALE_SYSTEM_DEFAULT
, SORT_DIGITSASNUMBERS
, "NULL", -1, "NULL", -1, 0, ERROR_INVALID_FLAGS
}
1895 static void test_CompareStringA(void)
1897 static const char ABC_EE
[] = {'A','B','C',0,0xEE};
1898 static const char ABC_FF
[] = {'A','B','C',0,0xFF};
1903 LCID lcid
= MAKELCID(MAKELANGID(LANG_FRENCH
, SUBLANG_DEFAULT
), SORT_DEFAULT
);
1905 GetCPInfoExA( CP_ACP
, 0, &cpinfo
);
1906 is_utf8
= cpinfo
.CodePage
== CP_UTF8
;
1908 for (i
= 0; i
< ARRAY_SIZE(comparestringa_data
); i
++)
1910 const struct comparestringa_entry
*entry
= &comparestringa_data
[i
];
1912 SetLastError(0xdeadbeef);
1913 ret
= CompareStringA(entry
->lcid
, entry
->flags
, entry
->first
, entry
->first_len
,
1914 entry
->second
, entry
->second_len
);
1915 ok(ret
== entry
->ret
, "%d: got %d, expected %d\n", i
, ret
, entry
->ret
);
1916 ok(GetLastError() == (ret
? 0xdeadbeef : entry
->le
), "%d: got last error %ld, expected %ld\n",
1917 i
, GetLastError(), (ret
? 0xdeadbeef : entry
->le
));
1920 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "Salut", -1, "Salute", -1);
1921 ok (ret
== CSTR_LESS_THAN
, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret
);
1923 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "Salut", -1, "SaLuT", -1);
1924 ok (ret
== CSTR_EQUAL
, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret
);
1926 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "Salut", -1, "hola", -1);
1927 ok (ret
== CSTR_GREATER_THAN
, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret
);
1929 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "haha", -1, "hoho", -1);
1930 ok (ret
== CSTR_LESS_THAN
, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret
);
1932 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
1934 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "haha", -1, "hoho", -1);
1935 ok (ret
== CSTR_LESS_THAN
, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret
);
1937 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "haha", -1, "hoho", 0);
1938 ok (ret
== CSTR_GREATER_THAN
, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret
);
1940 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "Salut", 5, "saLuT", -1);
1941 ok (ret
== CSTR_EQUAL
, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret
);
1943 ret
= lstrcmpA("", "");
1944 ok (ret
== 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret
);
1946 ret
= lstrcmpA(NULL
, NULL
);
1947 ok (ret
== 0 || broken(ret
== -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret
);
1949 ret
= lstrcmpA("", NULL
);
1950 ok (ret
== 1 || broken(ret
== -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret
);
1952 ret
= lstrcmpA(NULL
, "");
1953 ok (ret
== -1 || broken(ret
== -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret
);
1955 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "'o", -1, "-o", -1 );
1956 ok(ret
== CSTR_LESS_THAN
, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret
);
1958 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "'o", -1, "-o", -1 );
1959 ok(ret
== CSTR_LESS_THAN
, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret
);
1961 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "'", -1, "-", -1 );
1962 ok(ret
== CSTR_LESS_THAN
, "' vs - expected CSTR_LESS_THAN, got %d\n", ret
);
1964 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "'", -1, "-", -1 );
1965 ok(ret
== CSTR_LESS_THAN
, "' vs - expected CSTR_LESS_THAN, got %d\n", ret
);
1967 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "`o", -1, "/m", -1 );
1968 ok(ret
== CSTR_GREATER_THAN
, "`o vs /m CSTR_GREATER_THAN got %d\n", ret
);
1970 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "/m", -1, "`o", -1 );
1971 ok(ret
== CSTR_LESS_THAN
, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret
);
1973 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "`o", -1, "/m", -1 );
1974 ok(ret
== CSTR_GREATER_THAN
, "`o vs /m CSTR_GREATER_THAN got %d\n", ret
);
1976 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "/m", -1, "`o", -1 );
1977 ok(ret
== CSTR_LESS_THAN
, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret
);
1979 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "`o", -1, "-m", -1 );
1980 ok(ret
== CSTR_LESS_THAN
, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret
);
1982 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, 0, "-m", -1, "`o", -1 );
1983 ok(ret
== CSTR_GREATER_THAN
, "-m vs `o CSTR_GREATER_THAN got %d\n", ret
);
1985 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "`o", -1, "-m", -1 );
1986 ok(ret
== CSTR_GREATER_THAN
, "`o vs -m CSTR_GREATER_THAN got %d\n", ret
);
1988 ret
= CompareStringA(LOCALE_SYSTEM_DEFAULT
, SORT_STRINGSORT
, "-m", -1, "`o", -1 );
1989 ok(ret
== CSTR_LESS_THAN
, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret
);
1991 /* WinXP handles embedded NULLs differently than earlier versions */
1992 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1993 ok(ret
== CSTR_LESS_THAN
|| ret
== CSTR_EQUAL
, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret
);
1995 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1996 ok(ret
== CSTR_LESS_THAN
|| ret
== CSTR_EQUAL
, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret
);
1998 ret
= CompareStringA(lcid
, 0, "a\0b", -1, "a", -1);
1999 ok(ret
== CSTR_EQUAL
, "a vs a expected CSTR_EQUAL, got %d\n", ret
);
2001 ret
= CompareStringA(lcid
, 0, "a\0b", 4, "a", 2);
2002 ok(ret
== CSTR_EQUAL
|| /* win2k */
2003 ret
== CSTR_GREATER_THAN
,
2004 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret
);
2006 ret
= CompareStringA(lcid
, 0, "\2", 2, "\1", 2);
2007 ok(ret
!= CSTR_EQUAL
, "\\2 vs \\1 expected unequal\n");
2009 ret
= CompareStringA(lcid
, NORM_IGNORECASE
| LOCALE_USE_CP_ACP
, "#", -1, ".", -1);
2010 ok(ret
== CSTR_LESS_THAN
, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret
);
2012 ret
= CompareStringA(lcid
, NORM_IGNORECASE
, "_", -1, ".", -1);
2013 ok(ret
== CSTR_GREATER_THAN
, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret
);
2015 ret
= lstrcmpiA("#", ".");
2016 ok(ret
== -1, "\"#\" vs \".\" expected -1, got %d\n", ret
);
2018 lcid
= MAKELCID(MAKELANGID(LANG_POLISH
, SUBLANG_DEFAULT
), SORT_DEFAULT
);
2020 /* \xB9 character lies between a and b */
2021 ret
= CompareStringA(lcid
, 0, "a", 1, "\xB9", 1);
2022 ok(ret
== CSTR_LESS_THAN
, "\'\\xB9\' character should be greater than \'a\'\n");
2023 ret
= CompareStringA(lcid
, 0, "\xB9", 1, "b", 1);
2024 ok(ret
== CSTR_LESS_THAN
, "\'\\xB9\' character should be smaller than \'b\'\n");
2026 memset(a
, 'a', sizeof(a
));
2027 SetLastError(0xdeadbeef);
2028 ret
= CompareStringA(lcid
, 0, a
, sizeof(a
), a
, sizeof(a
));
2029 ok (GetLastError() == 0xdeadbeef && ret
== CSTR_EQUAL
,
2030 "ret %d, error %ld, expected value %d\n", ret
, GetLastError(), CSTR_EQUAL
);
2032 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 3, ABC_FF
, 3);
2033 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2034 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 5, ABC_FF
, 3);
2035 ok(ret
== CSTR_GREATER_THAN
|| (is_utf8
&& ret
== CSTR_EQUAL
), "expected CSTR_GREATER_THAN, got %d\n", ret
);
2036 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 3, ABC_FF
, 5);
2037 ok(ret
== CSTR_LESS_THAN
|| (is_utf8
&& ret
== CSTR_EQUAL
), "expected CSTR_LESS_THAN, got %d\n", ret
);
2038 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 5, ABC_FF
, 5);
2039 ok(ret
== CSTR_LESS_THAN
|| (is_utf8
&& ret
== CSTR_EQUAL
), "expected CSTR_LESS_THAN, got %d\n", ret
);
2040 ret
= CompareStringA(LOCALE_USER_DEFAULT
, 0, ABC_FF
, 5, ABC_EE
, 5);
2041 ok(ret
== CSTR_GREATER_THAN
|| (is_utf8
&& ret
== CSTR_EQUAL
), "expected CSTR_GREATER_THAN, got %d\n", ret
);
2044 static void test_CompareStringW(void)
2046 static const WCHAR ABC_EE
[] = {'A','B','C',0,0xEE};
2047 static const WCHAR ABC_FF
[] = {'A','B','C',0,0xFF};
2048 static const WCHAR A_ACUTE_BC
[] = {0xc1,'B','C',0};
2049 static const WCHAR A_ACUTE_BC_DECOMP
[] = {'A',0x301,'B','C',0};
2050 static const WCHAR A_NULL_BC
[] = {'A',0,'B','C',0};
2059 buf
= VirtualAlloc(NULL
, si
.dwPageSize
* 4, MEM_COMMIT
, PAGE_READWRITE
);
2060 ok(buf
!= NULL
, "VirtualAlloc failed with %lu\n", GetLastError());
2061 success
= VirtualProtect(buf
+ si
.dwPageSize
, si
.dwPageSize
, PAGE_NOACCESS
, &old_prot
);
2062 ok(success
, "VirtualProtect failed with %lu\n", GetLastError());
2063 success
= VirtualProtect(buf
+ 3 * si
.dwPageSize
, si
.dwPageSize
, PAGE_NOACCESS
, &old_prot
);
2064 ok(success
, "VirtualProtect failed with %lu\n", GetLastError());
2066 str1
= (WCHAR
*)(buf
+ si
.dwPageSize
- sizeof(WCHAR
));
2067 str2
= (WCHAR
*)(buf
+ 3 * si
.dwPageSize
- sizeof(WCHAR
));
2071 /* CompareStringW should abort on the first non-matching character */
2072 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, str1
, 100, str2
, 100);
2073 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2075 success
= VirtualFree(buf
, 0, MEM_RELEASE
);
2076 ok(success
, "VirtualFree failed with %lu\n", GetLastError());
2078 SetLastError(0xdeadbeef);
2079 ret
= CompareStringW(LOCALE_USER_DEFAULT
, SORT_DIGITSASNUMBERS
, L
"NULL", -1, L
"NULL", -1);
2080 ok(ret
== CSTR_EQUAL
|| broken(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
) /* <Win7 */,
2081 "expected CSTR_EQUAL, got %d, last error %ld\n", ret
, GetLastError());
2083 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 3, ABC_FF
, 3);
2084 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2085 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 5, ABC_FF
, 3);
2086 ok(ret
== CSTR_GREATER_THAN
, "expected CSTR_GREATER_THAN, got %d\n", ret
);
2087 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 3, ABC_FF
, 5);
2088 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2089 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 5, ABC_FF
, 5);
2090 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2091 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_FF
, 5, ABC_EE
, 5);
2092 ok(ret
== CSTR_GREATER_THAN
, "expected CSTR_GREATER_THAN, got %d\n", ret
);
2094 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 4, A_ACUTE_BC
, 4);
2095 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2096 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 4, A_ACUTE_BC_DECOMP
, 5);
2097 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2098 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, A_ACUTE_BC
, 4, A_ACUTE_BC_DECOMP
, 5);
2099 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2101 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, ABC_EE
, 3, A_ACUTE_BC
, 4);
2102 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2103 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, ABC_EE
, 4, A_ACUTE_BC_DECOMP
, 5);
2104 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2105 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, A_ACUTE_BC
, 4, A_ACUTE_BC_DECOMP
, 5);
2106 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2108 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, ABC_EE
, 4, A_NULL_BC
, 4);
2109 ok(ret
== CSTR_EQUAL
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2110 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, ABC_EE
, 4, A_NULL_BC
, 4);
2111 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2113 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, A_NULL_BC
, 4, A_ACUTE_BC
, 4);
2114 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2115 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, A_NULL_BC
, 4, A_ACUTE_BC
, 4);
2116 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2118 ret
= CompareStringW(LOCALE_USER_DEFAULT
, 0, A_NULL_BC
, 4, A_ACUTE_BC_DECOMP
, 5);
2119 ok(ret
== CSTR_LESS_THAN
, "expected CSTR_LESS_THAN, got %d\n", ret
);
2120 ret
= CompareStringW(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
, A_NULL_BC
, 4, A_ACUTE_BC_DECOMP
, 5);
2121 ok(ret
== CSTR_EQUAL
, "expected CSTR_EQUAL, got %d\n", ret
);
2124 struct comparestringex_test
{
2127 const WCHAR first
[2];
2128 const WCHAR second
[2];
2133 static const struct comparestringex_test comparestringex_tests
[] = {
2134 /* default behavior */
2137 {'i',0}, {'I',0}, CSTR_LESS_THAN
, -1
2141 {'i',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2145 {'i',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2149 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2153 {'I',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2157 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, -1
2159 /* with NORM_IGNORECASE */
2161 "tr-TR", NORM_IGNORECASE
,
2162 {'i',0}, {'I',0}, CSTR_EQUAL
, -1
2165 "tr-TR", NORM_IGNORECASE
,
2166 {'i',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2169 "tr-TR", NORM_IGNORECASE
,
2170 {'i',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2173 "tr-TR", NORM_IGNORECASE
,
2174 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2177 "tr-TR", NORM_IGNORECASE
,
2178 {'I',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2181 "tr-TR", NORM_IGNORECASE
,
2182 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, -1
2184 /* with NORM_LINGUISTIC_CASING */
2186 "tr-TR", NORM_LINGUISTIC_CASING
,
2187 {'i',0}, {'I',0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2190 "tr-TR", NORM_LINGUISTIC_CASING
,
2191 {'i',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2194 "tr-TR", NORM_LINGUISTIC_CASING
,
2195 {'i',0}, {0x131,0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2198 "tr-TR", NORM_LINGUISTIC_CASING
,
2199 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2202 "tr-TR", NORM_LINGUISTIC_CASING
,
2203 {'I',0}, {0x131,0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2206 "tr-TR", NORM_LINGUISTIC_CASING
,
2207 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, -1
2209 /* with LINGUISTIC_IGNORECASE */
2211 "tr-TR", LINGUISTIC_IGNORECASE
,
2212 {'i',0}, {'I',0}, CSTR_EQUAL
, -1
2215 "tr-TR", LINGUISTIC_IGNORECASE
,
2216 {'i',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2219 "tr-TR", LINGUISTIC_IGNORECASE
,
2220 {'i',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2223 "tr-TR", LINGUISTIC_IGNORECASE
,
2224 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2227 "tr-TR", LINGUISTIC_IGNORECASE
,
2228 {'I',0}, {0x131,0}, CSTR_LESS_THAN
, -1
2231 "tr-TR", LINGUISTIC_IGNORECASE
,
2232 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, -1
2234 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2236 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2237 {'i',0}, {'I',0}, CSTR_GREATER_THAN
, CSTR_EQUAL
2240 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2241 {'i',0}, {0x130,0}, CSTR_EQUAL
, CSTR_LESS_THAN
2244 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2245 {'i',0}, {0x131,0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2248 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2249 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2252 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2253 {'I',0}, {0x131,0}, CSTR_EQUAL
, CSTR_LESS_THAN
2256 "tr-TR", NORM_LINGUISTIC_CASING
| NORM_IGNORECASE
,
2257 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, -1
2259 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2261 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2262 {'i',0}, {'I',0}, CSTR_GREATER_THAN
, CSTR_EQUAL
2265 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2266 {'i',0}, {0x130,0}, CSTR_EQUAL
, CSTR_LESS_THAN
2269 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2270 {'i',0}, {0x131,0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2273 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2274 {'I',0}, {0x130,0}, CSTR_LESS_THAN
, -1
2277 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2278 {'I',0}, {0x131,0}, CSTR_EQUAL
, CSTR_LESS_THAN
2281 "tr-TR", NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
,
2282 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN
, CSTR_LESS_THAN
2286 static void test_CompareStringEx(void)
2288 const char *op
[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2292 /* CompareStringEx is only available on Vista+ */
2293 if (!pCompareStringEx
)
2295 win_skip("CompareStringEx not supported\n");
2299 for (i
= 0; i
< ARRAY_SIZE(comparestringex_tests
); i
++)
2301 const struct comparestringex_test
*e
= &comparestringex_tests
[i
];
2303 MultiByteToWideChar(CP_ACP
, 0, e
->locale
, -1, locale
, ARRAY_SIZE(locale
));
2304 ret
= pCompareStringEx(locale
, e
->flags
, e
->first
, -1, e
->second
, -1, NULL
, NULL
, 0);
2305 ok(ret
== e
->ret
|| broken(ret
== e
->broken
),
2306 "%d: got %s, expected %s\n", i
, op
[ret
], op
[e
->ret
]);
2311 static const DWORD lcmap_invalid_flags
[] = {
2313 LCMAP_HIRAGANA
| LCMAP_KATAKANA
,
2314 LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
,
2315 LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
,
2316 LCMAP_LOWERCASE
| SORT_STRINGSORT
,
2317 LCMAP_UPPERCASE
| NORM_IGNORESYMBOLS
,
2318 LCMAP_LOWERCASE
| NORM_IGNORESYMBOLS
,
2319 LCMAP_UPPERCASE
| NORM_IGNORENONSPACE
,
2320 LCMAP_LOWERCASE
| NORM_IGNORENONSPACE
,
2321 LCMAP_HIRAGANA
| NORM_IGNORENONSPACE
,
2322 LCMAP_HIRAGANA
| NORM_IGNORESYMBOLS
,
2323 LCMAP_HIRAGANA
| LCMAP_SIMPLIFIED_CHINESE
,
2324 LCMAP_HIRAGANA
| LCMAP_TRADITIONAL_CHINESE
,
2325 LCMAP_KATAKANA
| NORM_IGNORENONSPACE
,
2326 LCMAP_KATAKANA
| NORM_IGNORESYMBOLS
,
2327 LCMAP_KATAKANA
| LCMAP_SIMPLIFIED_CHINESE
,
2328 LCMAP_KATAKANA
| LCMAP_TRADITIONAL_CHINESE
,
2329 LCMAP_FULLWIDTH
| NORM_IGNORENONSPACE
,
2330 LCMAP_FULLWIDTH
| NORM_IGNORESYMBOLS
,
2331 LCMAP_FULLWIDTH
| LCMAP_SIMPLIFIED_CHINESE
,
2332 LCMAP_FULLWIDTH
| LCMAP_TRADITIONAL_CHINESE
,
2333 LCMAP_HALFWIDTH
| NORM_IGNORENONSPACE
,
2334 LCMAP_HALFWIDTH
| NORM_IGNORESYMBOLS
,
2335 LCMAP_HALFWIDTH
| LCMAP_SIMPLIFIED_CHINESE
,
2336 LCMAP_HALFWIDTH
| LCMAP_TRADITIONAL_CHINESE
,
2339 static void test_LCMapStringA(void)
2342 char buf
[256], buf2
[256];
2343 static const char upper_case
[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2344 static const char lower_case
[] = "\tjust! a, test; string 1/*+-.\r\n";
2345 static const char symbols_stripped
[] = "justateststring1";
2347 SetLastError(0xdeadbeef);
2348 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LOCALE_USE_CP_ACP
| LCMAP_LOWERCASE
,
2349 lower_case
, -1, buf
, sizeof(buf
));
2350 ok(ret
== lstrlenA(lower_case
) + 1,
2351 "ret %d, error %ld, expected value %d\n",
2352 ret
, GetLastError(), lstrlenA(lower_case
) + 1);
2353 ok(!memcmp(buf
, lower_case
, ret
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2355 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
| LCMAP_UPPERCASE
,
2356 upper_case
, -1, buf
, sizeof(buf
));
2357 ok(!ret
, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2358 ok(GetLastError() == ERROR_INVALID_FLAGS
,
2359 "unexpected error code %ld\n", GetLastError());
2361 /* test invalid flag combinations */
2362 for (i
= 0; i
< ARRAY_SIZE(lcmap_invalid_flags
); i
++) {
2363 lstrcpyA(buf
, "foo");
2364 SetLastError(0xdeadbeef);
2365 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, lcmap_invalid_flags
[i
],
2366 lower_case
, -1, buf
, sizeof(buf
));
2367 ok(GetLastError() == ERROR_INVALID_FLAGS
,
2368 "LCMapStringA (flag %08lx) unexpected error code %ld\n",
2369 lcmap_invalid_flags
[i
], GetLastError());
2370 ok(!ret
, "LCMapStringA (flag %08lx) should return 0, got %d\n",
2371 lcmap_invalid_flags
[i
], ret
);
2374 /* test LCMAP_LOWERCASE */
2375 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
,
2376 upper_case
, -1, buf
, sizeof(buf
));
2377 ok(ret
== lstrlenA(upper_case
) + 1,
2378 "ret %d, error %ld, expected value %d\n",
2379 ret
, GetLastError(), lstrlenA(upper_case
) + 1);
2380 ok(!lstrcmpA(buf
, lower_case
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2382 /* test LCMAP_UPPERCASE */
2383 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
,
2384 lower_case
, -1, buf
, sizeof(buf
));
2385 ok(ret
== lstrlenA(lower_case
) + 1,
2386 "ret %d, error %ld, expected value %d\n",
2387 ret
, GetLastError(), lstrlenA(lower_case
) + 1);
2388 ok(!lstrcmpA(buf
, upper_case
), "LCMapStringA should return %s, but not %s\n", upper_case
, buf
);
2390 /* test buffer overflow */
2391 SetLastError(0xdeadbeef);
2392 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
,
2393 lower_case
, -1, buf
, 4);
2394 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2395 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret
);
2397 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2398 lstrcpyA(buf
, lower_case
);
2399 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
,
2400 buf
, -1, buf
, sizeof(buf
));
2401 if (!ret
) /* Win9x */
2402 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2405 ok(ret
== lstrlenA(lower_case
) + 1,
2406 "ret %d, error %ld, expected value %d\n",
2407 ret
, GetLastError(), lstrlenA(lower_case
) + 1);
2408 ok(!lstrcmpA(buf
, upper_case
), "LCMapStringA should return %s, but not %s\n", upper_case
, buf
);
2410 lstrcpyA(buf
, upper_case
);
2411 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
,
2412 buf
, -1, buf
, sizeof(buf
));
2413 if (!ret
) /* Win9x */
2414 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2417 ok(ret
== lstrlenA(upper_case
) + 1,
2418 "ret %d, error %ld, expected value %d\n",
2419 ret
, GetLastError(), lstrlenA(lower_case
) + 1);
2420 ok(!lstrcmpA(buf
, lower_case
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2423 /* otherwise src == dst should fail */
2424 SetLastError(0xdeadbeef);
2425 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
| LCMAP_UPPERCASE
,
2426 buf
, 10, buf
, sizeof(buf
));
2427 ok(GetLastError() == ERROR_INVALID_FLAGS
/* NT */ ||
2428 GetLastError() == ERROR_INVALID_PARAMETER
/* Win9x */,
2429 "unexpected error code %ld\n", GetLastError());
2430 ok(!ret
, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2432 /* test whether '\0' is always appended */
2433 memset(buf
, 0xff, sizeof(buf
));
2434 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
,
2435 upper_case
, -1, buf
, sizeof(buf
));
2436 ok(ret
, "LCMapStringA must succeed\n");
2437 ok(buf
[ret
-1] == 0, "LCMapStringA not null-terminated\n");
2438 ret2
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
,
2439 upper_case
, lstrlenA(upper_case
), buf2
, sizeof(buf2
));
2440 ok(ret2
, "LCMapStringA must succeed\n");
2441 ok(buf2
[ret2
-1] == 0, "LCMapStringA not null-terminated\n" );
2442 ok(ret
== ret2
, "lengths of sort keys must be equal\n");
2443 ok(!memcmp(buf
, buf2
, ret
), "sort keys must be equal\n");
2445 /* test we get the same length when no dest buffer is provided */
2446 ret2
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
,
2447 upper_case
, lstrlenA(upper_case
), NULL
, 0);
2448 ok(ret2
, "LCMapStringA must succeed\n");
2449 ok(ret
== ret2
, "lengths of sort keys must be equal (%d vs %d)\n", ret
, ret2
);
2451 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2452 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
| NORM_IGNORECASE
,
2453 upper_case
, -1, buf
, sizeof(buf
));
2454 ok(ret
, "LCMapStringA must succeed\n");
2455 ret2
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
,
2456 lower_case
, -1, buf2
, sizeof(buf2
));
2457 ok(ret2
, "LCMapStringA must succeed\n");
2458 ok(ret
== ret2
, "lengths of sort keys must be equal\n");
2459 ok(!memcmp(buf
, buf2
, ret
), "sort keys must be equal\n");
2461 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2462 results from plain LCMAP_SORTKEY on Vista */
2464 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2465 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
| NORM_IGNORESYMBOLS
,
2466 lower_case
, -1, buf
, sizeof(buf
));
2467 ok(ret
, "LCMapStringA must succeed\n");
2468 ret2
= LCMapStringA(LOCALE_USER_DEFAULT
, LCMAP_SORTKEY
,
2469 symbols_stripped
, -1, buf2
, sizeof(buf2
));
2470 ok(ret2
, "LCMapStringA must succeed\n");
2471 ok(ret
== ret2
, "lengths of sort keys must be equal\n");
2472 ok(!memcmp(buf
, buf2
, ret
), "sort keys must be equal\n");
2474 /* test NORM_IGNORENONSPACE */
2475 lstrcpyA(buf
, "foo");
2476 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, NORM_IGNORENONSPACE
,
2477 lower_case
, -1, buf
, sizeof(buf
));
2478 ok(ret
== lstrlenA(lower_case
) + 1, "LCMapStringA should return %d, ret = %d\n",
2479 lstrlenA(lower_case
) + 1, ret
);
2480 ok(!lstrcmpA(buf
, lower_case
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2482 /* test NORM_IGNORESYMBOLS */
2483 lstrcpyA(buf
, "foo");
2484 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, NORM_IGNORESYMBOLS
,
2485 lower_case
, -1, buf
, sizeof(buf
));
2486 ok(ret
== lstrlenA(symbols_stripped
) + 1, "LCMapStringA should return %d, ret = %d\n",
2487 lstrlenA(symbols_stripped
) + 1, ret
);
2488 ok(!lstrcmpA(buf
, symbols_stripped
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2490 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2491 lstrcpyA(buf
, "foo");
2492 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, NORM_IGNORESYMBOLS
| NORM_IGNORENONSPACE
,
2493 lower_case
, -1, buf
, sizeof(buf
));
2494 ok(ret
== lstrlenA(symbols_stripped
) + 1, "LCMapStringA should return %d, ret = %d\n",
2495 lstrlenA(symbols_stripped
) + 1, ret
);
2496 ok(!lstrcmpA(buf
, symbols_stripped
), "LCMapStringA should return %s, but not %s\n", lower_case
, buf
);
2498 /* test srclen = 0 */
2499 SetLastError(0xdeadbeef);
2500 ret
= LCMapStringA(LOCALE_USER_DEFAULT
, 0, upper_case
, 0, buf
, sizeof(buf
));
2501 ok(!ret
, "LCMapStringA should fail with srclen = 0\n");
2502 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
2503 "unexpected error code %ld\n", GetLastError());
2506 typedef INT (*lcmapstring_wrapper
)(DWORD
, LPCWSTR
, INT
, LPWSTR
, INT
);
2508 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr
, const char *func_name
)
2510 const static WCHAR japanese_text
[] = {
2511 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2512 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2513 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2515 const static WCHAR hiragana_text
[] = {
2516 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f, 0x3068,
2517 0x30fc, 0x3094, 0x3049, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2518 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2520 const static WCHAR katakana_text
[] = {
2521 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2522 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x91ce, 0x539f, 0x30cf, 0x5e83,
2523 0x30a4, 0x30f3, 0x30c0, 0x30e8, 0x3002, 0
2525 const static WCHAR halfwidth_text
[] = {
2526 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2527 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x91ce, 0x539f, 0x306f,
2528 0x5e83, 0x3044, 0x3093, 0x3060, 0x3088, 0xff61, 0
2530 const static WCHAR halfwidth_text2
[] = {
2531 0xff72, 0x30fd, 0xff94, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2532 0xff70, 0xff73, 0xff9e, 0xff6b, 0xff89, 0x91ce, 0x539f, 0xff8a,
2533 0x5e83, 0xff72, 0xff9d, 0xff80, 0xff9e, 0xff96, 0xff61, 0
2535 const static WCHAR math_text
[] = {
2536 0xd835, 0xdc00, 0xd835, 0xdc01, 0xd835, 0xdc02, 0xd835, 0xdc03,
2537 0xd835, 0xdd52, 0xd835, 0xdd53, 0xd835, 0xdd54, 0xd835, 0xdd55, 0
2539 const static WCHAR math_result
[] = L
"ABCDabcd";
2540 const static WCHAR math_arabic_text
[] = {
2541 0xd83b, 0xde00, 0xd83b, 0xde01, 0xd83b, 0xde02, 0xd83b, 0xde03,
2542 0xd83b, 0xde10, 0xd83b, 0xde11, 0xd83b, 0xde12, 0xd83b, 0xde13, 0
2544 const static WCHAR math_arabic_result
[] = {
2545 0x0627, 0x0628, 0x062c, 0x062f, 0x0641, 0x0635, 0x0642, 0x0631, 0
2547 const static WCHAR cjk_compat_text
[] = {
2548 0xd87e, 0xdc20, 0xd87e, 0xdc21, 0xd87e, 0xdc22, 0xd87e, 0xdc23,
2549 0xd87e, 0xdc24, 0xd87e, 0xdc25, 0xd87e, 0xdc26, 0xd87e, 0xdc27, 0
2551 const static WCHAR cjk_compat_result
[] = {
2552 0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4, 0
2554 const static WCHAR accents_text
[] = {
2555 0x00e0, 0x00e7, ' ', 0x00e9, ',', 0x00ee, 0x00f1, '/', 0x00f6, 0x00fb, 0x00fd, '!', 0
2557 const static WCHAR accents_result
[] = L
"ac e,in/ouy!";
2558 const static WCHAR accents_result2
[] = L
"aceinouy";
2560 WCHAR buf
[256], buf2
[256];
2561 char *p_buf
= (char *)buf
, *p_buf2
= (char *)buf2
;
2563 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2564 ret
= func_ptr(LCMAP_LOWERCASE
| LCMAP_UPPERCASE
, lower_case
, -1, buf
, ARRAY_SIZE(buf
));
2565 todo_wine
ok(ret
== lstrlenW(title_case
) + 1 || broken(!ret
),
2566 "%s ret %d, error %ld, expected value %d\n", func_name
,
2567 ret
, GetLastError(), lstrlenW(title_case
) + 1);
2568 todo_wine
ok(lstrcmpW(buf
, title_case
) == 0 || broken(!ret
),
2569 "Expected title case string\n");
2571 /* test invalid flag combinations */
2572 for (i
= 0; i
< ARRAY_SIZE(lcmap_invalid_flags
); i
++) {
2573 lstrcpyW(buf
, fooW
);
2574 SetLastError(0xdeadbeef);
2575 ret
= func_ptr(lcmap_invalid_flags
[i
],
2576 lower_case
, -1, buf
, sizeof(buf
));
2577 ok(GetLastError() == ERROR_INVALID_FLAGS
,
2578 "%s (flag %08lx) unexpected error code %ld\n",
2579 func_name
, lcmap_invalid_flags
[i
], GetLastError());
2580 ok(!ret
, "%s (flag %08lx) should return 0, got %d\n",
2581 func_name
, lcmap_invalid_flags
[i
], ret
);
2584 /* test LCMAP_LOWERCASE */
2585 ret
= func_ptr(LCMAP_LOWERCASE
, upper_case
, -1, buf
, ARRAY_SIZE(buf
));
2586 ok(ret
== lstrlenW(upper_case
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2587 ret
, GetLastError(), lstrlenW(upper_case
) + 1);
2588 ok(!lstrcmpW(buf
, lower_case
), "%s string compare mismatch\n", func_name
);
2590 /* test LCMAP_UPPERCASE */
2591 ret
= func_ptr(LCMAP_UPPERCASE
, lower_case
, -1, buf
, ARRAY_SIZE(buf
));
2592 ok(ret
== lstrlenW(lower_case
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2593 ret
, GetLastError(), lstrlenW(lower_case
) + 1);
2594 ok(!lstrcmpW(buf
, upper_case
), "%s string compare mismatch\n", func_name
);
2596 /* test LCMAP_HIRAGANA */
2597 ret
= func_ptr(LCMAP_HIRAGANA
, japanese_text
, -1, buf
, ARRAY_SIZE(buf
));
2598 ok(ret
== lstrlenW(hiragana_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2599 ret
, GetLastError(), lstrlenW(hiragana_text
) + 1);
2600 ok(!lstrcmpW(buf
, hiragana_text
), "%s string compare mismatch\n", func_name
);
2602 buf
[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2603 ret
= func_ptr(LCMAP_HIRAGANA
, buf
, 1, buf2
, 1);
2604 ok(ret
== 1, "%s ret %d, error %ld, expected value 1\n", func_name
,
2605 ret
, GetLastError());
2606 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2607 ok(buf2
[0] == 0x3095 || broken(buf2
[0] == 0x30f5 /* Vista and earlier versions */),
2608 "%s expected %04x, got %04x\n", func_name
, 0x3095, buf2
[0]);
2610 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2611 ret
= func_ptr(LCMAP_KATAKANA
| LCMAP_LOWERCASE
, japanese_text
, -1, buf
, ARRAY_SIZE(buf
));
2612 ok(ret
== lstrlenW(katakana_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2613 ret
, GetLastError(), lstrlenW(katakana_text
) + 1);
2614 ok(!lstrcmpW(buf
, katakana_text
), "%s string compare mismatch\n", func_name
);
2616 /* test LCMAP_FULLWIDTH */
2617 ret
= func_ptr(LCMAP_FULLWIDTH
, halfwidth_text
, -1, buf
, ARRAY_SIZE(buf
));
2618 ok(ret
== lstrlenW(japanese_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2619 ret
, GetLastError(), lstrlenW(japanese_text
) + 1);
2620 ok(!lstrcmpW(buf
, japanese_text
), "%s string compare mismatch\n", func_name
);
2622 ret2
= func_ptr(LCMAP_FULLWIDTH
, halfwidth_text
, -1, NULL
, 0);
2623 ok(ret
== ret2
, "%s ret %d, expected value %d\n", func_name
, ret2
, ret
);
2625 ret
= func_ptr(LCMAP_FULLWIDTH
, math_text
, -1, buf
, ARRAY_SIZE(buf
));
2626 ok(ret
== lstrlenW(buf
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2627 ret
, GetLastError(), lstrlenW(buf
) + 1);
2628 ok(!lstrcmpW(buf
, math_result
), "%s string compare mismatch %s\n", func_name
, debugstr_w(buf
));
2630 ret
= func_ptr(LCMAP_FULLWIDTH
, math_arabic_text
, -1, buf
, ARRAY_SIZE(buf
));
2631 ok(ret
== lstrlenW(buf
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2632 ret
, GetLastError(), lstrlenW(buf
) + 1);
2633 ok(!lstrcmpW(buf
, math_arabic_result
) ||
2634 broken(!lstrcmpW( buf
, math_arabic_text
)), /* win7 */
2635 "%s string compare mismatch %s\n", func_name
, debugstr_w(buf
));
2637 ret
= func_ptr(LCMAP_FULLWIDTH
, cjk_compat_text
, -1, buf
, ARRAY_SIZE(buf
));
2638 ok(ret
== lstrlenW(buf
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2639 ret
, GetLastError(), lstrlenW(buf
) + 1);
2640 ok(!lstrcmpW(buf
, cjk_compat_result
), "%s string compare mismatch %s\n", func_name
, debugstr_w(buf
));
2642 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2643 (half-width katakana is converted into full-width hiragana) */
2644 ret
= func_ptr(LCMAP_FULLWIDTH
| LCMAP_HIRAGANA
, halfwidth_text
, -1, buf
, ARRAY_SIZE(buf
));
2645 ok(ret
== lstrlenW(hiragana_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2646 ret
, GetLastError(), lstrlenW(hiragana_text
) + 1);
2647 ok(!lstrcmpW(buf
, hiragana_text
), "%s string compare mismatch\n", func_name
);
2649 ret2
= func_ptr(LCMAP_FULLWIDTH
| LCMAP_HIRAGANA
, halfwidth_text
, -1, NULL
, 0);
2650 ok(ret
== ret2
, "%s ret %d, expected value %d\n", func_name
, ret
, ret2
);
2652 /* LCMAP_FULLWIDTH | LCMAP_KATAKANA maps to full-width first */
2653 ret
= func_ptr(LCMAP_FULLWIDTH
| LCMAP_KATAKANA
, halfwidth_text
, -1, buf
, ARRAY_SIZE(buf
));
2654 ok(ret
== lstrlenW(katakana_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2655 ret
, GetLastError(), lstrlenW(katakana_text
) + 1);
2656 ok(!lstrcmpW(buf
, katakana_text
), "%s string compare mismatch\n", func_name
);
2658 /* test LCMAP_HALFWIDTH */
2659 ret
= func_ptr(LCMAP_HALFWIDTH
, japanese_text
, -1, buf
, ARRAY_SIZE(buf
));
2660 ok(ret
== lstrlenW(halfwidth_text
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2661 ret
, GetLastError(), lstrlenW(halfwidth_text
) + 1);
2662 ok(!lstrcmpW(buf
, halfwidth_text
), "%s string compare mismatch\n", func_name
);
2664 ret2
= func_ptr(LCMAP_HALFWIDTH
, japanese_text
, -1, NULL
, 0);
2665 ok(ret
== ret2
, "%s ret %d, expected value %d\n", func_name
, ret
, ret2
);
2667 /* test LCMAP_HALFWIDTH | LCMAP_KATAKANA
2668 (hiragana character is converted into half-width katakana) */
2669 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_KATAKANA
, japanese_text
, -1, buf
, ARRAY_SIZE(buf
));
2670 ok(ret
== lstrlenW(halfwidth_text2
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2671 ret
, GetLastError(), lstrlenW(halfwidth_text2
) + 1);
2672 ok(!lstrcmpW(buf
, halfwidth_text2
), "%s string compare mismatch\n", func_name
);
2674 ret2
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_KATAKANA
, japanese_text
, -1, NULL
, 0);
2675 ok(ret
== ret2
, "%s ret %d, expected value %d\n", func_name
, ret
, ret2
);
2677 /* LCMAP_HALFWIDTH | LCMAP_HIRAGANA maps to Hiragana first */
2678 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_HIRAGANA
, japanese_text
, -1, buf
, ARRAY_SIZE(buf
));
2679 ret2
= func_ptr(LCMAP_HALFWIDTH
, hiragana_text
, -1, buf2
, ARRAY_SIZE(buf2
));
2680 ok(ret
== ret2
, "%s ret %d, expected value %d\n", func_name
, ret
, ret2
);
2681 ok(!lstrcmpW(buf
, buf2
), "%s string compare mismatch %s vs %s\n", func_name
, debugstr_w(buf
), debugstr_w(buf2
));
2683 /* test buffer overflow */
2684 SetLastError(0xdeadbeef);
2685 ret
= func_ptr(LCMAP_UPPERCASE
,
2686 lower_case
, -1, buf
, 4);
2687 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2688 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name
, ret
);
2690 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2691 Thus, it requires two WCHARs. */
2693 SetLastError(0xdeadbeef);
2694 ret
= func_ptr(LCMAP_HALFWIDTH
, buf
, 1, buf2
, 1);
2695 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2696 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name
, ret
);
2700 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_UPPERCASE
, buf
, 2, buf2
, 0);
2701 ok(ret
== 3, "%s ret %d, expected value 3\n", func_name
, ret
);
2703 SetLastError(0xdeadbeef);
2704 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_UPPERCASE
, buf
, 2, buf2
, 1);
2705 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2706 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name
, ret
);
2708 SetLastError(0xdeadbeef);
2709 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_UPPERCASE
, buf
, 2, buf2
, 2);
2710 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2711 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name
, ret
);
2713 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_UPPERCASE
, buf
, 2, buf2
, 3);
2714 ok(ret
== 3, "%s ret %d, expected value 3\n", func_name
, ret
);
2716 ret
= func_ptr(LCMAP_HALFWIDTH
| LCMAP_UPPERCASE
, buf
, 2, buf2
, 4);
2717 ok(ret
== 3, "%s ret %d, expected value 3\n", func_name
, ret
);
2719 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2720 lstrcpyW(buf
, lower_case
);
2721 ret
= func_ptr(LCMAP_UPPERCASE
, buf
, -1, buf
, ARRAY_SIZE(buf
));
2722 ok(ret
== lstrlenW(lower_case
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2723 ret
, GetLastError(), lstrlenW(lower_case
) + 1);
2724 ok(!lstrcmpW(buf
, upper_case
), "%s string compare mismatch\n", func_name
);
2726 lstrcpyW(buf
, upper_case
);
2727 ret
= func_ptr(LCMAP_LOWERCASE
, buf
, -1, buf
, ARRAY_SIZE(buf
));
2728 ok(ret
== lstrlenW(upper_case
) + 1, "%s ret %d, error %ld, expected value %d\n", func_name
,
2729 ret
, GetLastError(), lstrlenW(lower_case
) + 1);
2730 ok(!lstrcmpW(buf
, lower_case
), "%s string compare mismatch\n", func_name
);
2732 /* otherwise src == dst should fail */
2733 SetLastError(0xdeadbeef);
2734 ret
= func_ptr(LCMAP_SORTKEY
| LCMAP_UPPERCASE
,
2735 buf
, 10, buf
, sizeof(buf
));
2736 ok(GetLastError() == ERROR_INVALID_FLAGS
/* NT */ ||
2737 GetLastError() == ERROR_INVALID_PARAMETER
/* Win7+ */,
2738 "%s unexpected error code %ld\n", func_name
, GetLastError());
2739 ok(!ret
, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name
);
2741 /* test whether '\0' is always appended */
2742 ret
= func_ptr(LCMAP_SORTKEY
,
2743 upper_case
, -1, buf
, sizeof(buf
));
2744 ok(ret
, "%s func_ptr must succeed\n", func_name
);
2745 ret2
= func_ptr(LCMAP_SORTKEY
,
2746 upper_case
, lstrlenW(upper_case
), buf2
, sizeof(buf2
));
2747 ok(ret
, "%s func_ptr must succeed\n", func_name
);
2748 ok(ret
== ret2
, "%s lengths of sort keys must be equal\n", func_name
);
2749 ok(!memcmp(p_buf
, p_buf2
, ret
), "%s sort keys must be equal\n", func_name
);
2751 /* test contents with short buffer */
2752 memset( buf
, 0xcc, sizeof(buf
) );
2753 ret
= func_ptr(LCMAP_SORTKEY
, upper_case
, -1, buf
, ret
- 1);
2754 ok( !ret
, "%s succeeded with %u\n", func_name
, ret
);
2755 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "%s wrong error %lu\n", func_name
, GetLastError() );
2756 ret
= (char *)memchr( p_buf
, 0xcc, sizeof(buf
) ) - p_buf
;
2757 ok( ret
, "%s buffer not filled\n", func_name
);
2758 ok( p_buf
[ret
- 1] == 0x01, "%s buffer filled up to %02x\n", func_name
, (BYTE
)p_buf
[ret
- 1] );
2759 ok( !memcmp( p_buf
, p_buf2
, ret
- 1 ), "%s buffers differ\n", func_name
);
2761 memset( buf
, 0xcc, sizeof(buf
) );
2762 ret
= func_ptr(LCMAP_SORTKEY
, upper_case
, -1, buf
, ret2
- 20);
2763 ok( !ret
, "%s succeeded with %u\n", func_name
, ret
);
2764 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "%s wrong error %lu\n", func_name
, GetLastError() );
2765 ret
= (char *)memchr( p_buf
, 0xcc, sizeof(buf
) ) - p_buf
;
2766 ok( ret
, "%s buffer not filled\n", func_name
);
2767 ok( p_buf
[ret
- 1] == 0x01, "%s buffer filled up to %02x\n", func_name
, (BYTE
)p_buf
[ret
- 1] );
2768 ok( !memcmp( p_buf
, p_buf2
, ret
- 1 ), "%s buffers differ\n", func_name
);
2770 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2771 ret
= func_ptr(LCMAP_SORTKEY
| NORM_IGNORECASE
,
2772 upper_case
, -1, buf
, sizeof(buf
));
2773 ok(ret
, "%s func_ptr must succeed\n", func_name
);
2774 ret2
= func_ptr(LCMAP_SORTKEY
,
2775 lower_case
, -1, buf2
, sizeof(buf2
));
2776 ok(ret2
, "%s func_ptr must succeed\n", func_name
);
2777 ok(ret
== ret2
, "%s lengths of sort keys must be equal\n", func_name
);
2778 ok(!memcmp(p_buf
, p_buf2
, ret
), "%s sort keys must be equal\n", func_name
);
2780 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2781 results from plain LCMAP_SORTKEY on Vista */
2783 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2784 ret
= func_ptr(LCMAP_SORTKEY
| NORM_IGNORESYMBOLS
,
2785 lower_case
, -1, buf
, sizeof(buf
));
2786 ok(ret
, "%s func_ptr must succeed\n", func_name
);
2787 ret2
= func_ptr(LCMAP_SORTKEY
,
2788 symbols_stripped
, -1, buf2
, sizeof(buf2
));
2789 ok(ret2
, "%s func_ptr must succeed\n", func_name
);
2790 ok(ret
== ret2
, "%s lengths of sort keys must be equal\n", func_name
);
2791 ok(!memcmp(p_buf
, p_buf2
, ret
), "%s sort keys must be equal\n", func_name
);
2793 /* test NORM_IGNORENONSPACE */
2794 lstrcpyW(buf
, fooW
);
2795 ret
= func_ptr(NORM_IGNORENONSPACE
, lower_case
, -1, buf
, ARRAY_SIZE(buf
));
2796 ok(ret
== lstrlenW(lower_case
) + 1, "%s func_ptr should return %d, ret = %d\n", func_name
,
2797 lstrlenW(lower_case
) + 1, ret
);
2798 ok(!lstrcmpW(buf
, lower_case
), "%s string comparison mismatch\n", func_name
);
2800 lstrcpyW(buf
, fooW
);
2801 ret
= func_ptr(NORM_IGNORENONSPACE
, accents_text
, -1, buf
, ARRAY_SIZE(buf
));
2802 ok(ret
== lstrlenW(buf
) + 1, "%s func_ptr should return %d, ret = %d\n", func_name
,
2803 lstrlenW(buf
) + 1, ret
);
2804 ok(!lstrcmpW(buf
, accents_result
), "%s string comparison mismatch %s\n", func_name
, debugstr_w(buf
));
2806 /* test NORM_IGNORESYMBOLS */
2807 lstrcpyW(buf
, fooW
);
2808 ret
= func_ptr(NORM_IGNORESYMBOLS
, lower_case
, -1, buf
, ARRAY_SIZE(buf
));
2809 ok(ret
== lstrlenW(symbols_stripped
) + 1, "%s func_ptr should return %d, ret = %d\n", func_name
,
2810 lstrlenW(symbols_stripped
) + 1, ret
);
2811 ok(!lstrcmpW(buf
, symbols_stripped
), "%s string comparison mismatch\n", func_name
);
2813 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2814 lstrcpyW(buf
, fooW
);
2815 ret
= func_ptr(NORM_IGNORESYMBOLS
| NORM_IGNORENONSPACE
, lower_case
, -1, buf
, ARRAY_SIZE(buf
));
2816 ok(ret
== lstrlenW(symbols_stripped
) + 1, "%s func_ptr should return %d, ret = %d\n", func_name
,
2817 lstrlenW(symbols_stripped
) + 1, ret
);
2818 ok(!lstrcmpW(buf
, symbols_stripped
), "%s string comparison mismatch\n", func_name
);
2820 lstrcpyW(buf
, fooW
);
2821 ret
= func_ptr(NORM_IGNORESYMBOLS
| NORM_IGNORENONSPACE
, accents_text
, -1, buf
, ARRAY_SIZE(buf
));
2822 ok(ret
== lstrlenW(buf
) + 1, "%s func_ptr should return %d, ret = %d\n", func_name
,
2823 lstrlenW(buf
) + 1, ret
);
2824 ok(!lstrcmpW(buf
, accents_result2
), "%s string comparison mismatch %s\n", func_name
, debugstr_w(buf
));
2826 /* test small buffer */
2827 lstrcpyW(buf
, fooW
);
2828 ret
= func_ptr(LCMAP_SORTKEY
, lower_case
, -1, buf
, 2);
2829 ok(ret
== 0, "Expected a failure\n");
2830 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
2831 "%s unexpected error code %ld\n", func_name
, GetLastError());
2833 /* test srclen = 0 */
2834 SetLastError(0xdeadbeef);
2835 ret
= func_ptr(0, upper_case
, 0, buf
, ARRAY_SIZE(buf
));
2836 ok(!ret
, "%s func_ptr should fail with srclen = 0\n", func_name
);
2837 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
2838 "%s unexpected error code %ld\n", func_name
, GetLastError());
2841 static INT
LCMapStringW_wrapper(DWORD flags
, LPCWSTR src
, INT srclen
, LPWSTR dst
, INT dstlen
)
2843 return LCMapStringW(LOCALE_USER_DEFAULT
, flags
, src
, srclen
, dst
, dstlen
);
2846 static void test_LCMapStringW(void)
2851 trace("testing LCMapStringW\n");
2853 SetLastError(0xdeadbeef);
2854 ret
= LCMapStringW((LCID
)-1, LCMAP_LOWERCASE
, upper_case
, -1, buf
, ARRAY_SIZE(buf
));
2855 ok(!ret
, "LCMapStringW should fail with bad lcid\n");
2856 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "unexpected error code %ld\n", GetLastError());
2858 SetLastError(0xdeadbeef);
2859 ret
= LCMapStringW((LCID
)0xdead, LCMAP_HIRAGANA
, upper_case
, -1, buf
, ARRAY_SIZE(buf
));
2860 ok(!ret
, "LCMapStringW should fail with bad lcid\n");
2861 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "unexpected error code %ld\n", GetLastError());
2863 test_lcmapstring_unicode(LCMapStringW_wrapper
, "LCMapStringW:");
2866 static INT
LCMapStringEx_wrapper(DWORD flags
, LPCWSTR src
, INT srclen
, LPWSTR dst
, INT dstlen
)
2868 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT
, flags
, src
, srclen
, dst
, dstlen
, NULL
, NULL
, 0);
2871 static void test_LCMapStringEx(void)
2876 if (!pLCMapStringEx
)
2878 win_skip( "LCMapStringEx not available\n" );
2882 trace("testing LCMapStringEx\n");
2884 SetLastError(0xdeadbeef);
2885 ret
= pLCMapStringEx(invalidW
, LCMAP_LOWERCASE
,
2886 upper_case
, -1, buf
, ARRAY_SIZE(buf
), NULL
, NULL
, 0);
2887 ok(!ret
, "LCMapStringEx should fail with bad locale name\n");
2888 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "unexpected error code %ld\n", GetLastError());
2890 SetLastError(0xdeadbeef);
2891 ret
= pLCMapStringEx(invalidW
, LCMAP_HIRAGANA
,
2892 upper_case
, -1, buf
, ARRAY_SIZE(buf
), NULL
, NULL
, 0);
2893 ok(ret
, "LCMapStringEx should not fail with bad locale name\n");
2895 /* test reserved parameters */
2896 ret
= pLCMapStringEx(LOCALE_NAME_USER_DEFAULT
, LCMAP_LOWERCASE
,
2897 upper_case
, -1, buf
, ARRAY_SIZE(buf
), NULL
, NULL
, 1);
2898 ok(ret
== lstrlenW(upper_case
) + 1, "ret %d, error %ld, expected value %d\n",
2899 ret
, GetLastError(), lstrlenW(upper_case
) + 1);
2900 ok(!lstrcmpW(buf
, lower_case
), "string compare mismatch\n");
2902 ret
= pLCMapStringEx(LOCALE_NAME_USER_DEFAULT
, LCMAP_LOWERCASE
,
2903 upper_case
, -1, buf
, ARRAY_SIZE(buf
), NULL
, (void*)1, 0);
2904 ok(ret
== lstrlenW(upper_case
) + 1, "ret %d, error %ld, expected value %d\n",
2905 ret
, GetLastError(), lstrlenW(upper_case
) + 1);
2906 ok(!lstrcmpW(buf
, lower_case
), "string compare mismatch\n");
2908 /* crashes on native */
2910 ret
= pLCMapStringEx(LOCALE_NAME_USER_DEFAULT
, LCMAP_LOWERCASE
,
2911 upper_case
, -1, buf
, ARRAY_SIZE(buf
), (void*)1, NULL
, 0);
2913 test_lcmapstring_unicode(LCMapStringEx_wrapper
, "LCMapStringEx:");
2916 struct neutralsublang_name_t
{
2922 static const struct neutralsublang_name_t neutralsublang_names
[] = {
2923 { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_SAUDI_ARABIA
), SORT_DEFAULT
) },
2924 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI
, SUBLANG_AZERI_LATIN
), SORT_DEFAULT
) },
2925 { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN
, SUBLANG_GERMAN
), SORT_DEFAULT
) },
2926 { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
) },
2927 { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH
, SUBLANG_SPANISH_MODERN
), SORT_DEFAULT
) },
2928 { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH
, SUBLANG_IRISH_IRELAND
), SORT_DEFAULT
) },
2929 { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN
, SUBLANG_ITALIAN
), SORT_DEFAULT
) },
2930 { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY
, SUBLANG_MALAY_MALAYSIA
), SORT_DEFAULT
) },
2931 { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH
), SORT_DEFAULT
) },
2932 { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE
, SUBLANG_PORTUGUESE_BRAZILIAN
), SORT_DEFAULT
) },
2933 { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_LATIN
), SORT_DEFAULT
) },
2934 { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH
, SUBLANG_SWEDISH
), SORT_DEFAULT
) },
2935 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK
, SUBLANG_UZBEK_LATIN
), SORT_DEFAULT
) },
2936 { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
), SORT_DEFAULT
) },
2940 static void test_LocaleNameToLCID(void)
2945 WCHAR buffer
[LOCALE_NAME_MAX_LENGTH
];
2946 WCHAR expbuff
[LOCALE_NAME_MAX_LENGTH
];
2947 const struct neutralsublang_name_t
*ptr
;
2949 if (!pLocaleNameToLCID
)
2951 win_skip( "LocaleNameToLCID not available\n" );
2957 SetLastError(0xdeadbeef);
2958 lcid
= pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT
, 0);
2959 ok(lcid
== GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER
/* Vista */),
2960 "Expected lcid == %08lx, got %08lx, error %ld\n", GetUserDefaultLCID(), lcid
, GetLastError());
2961 ret
= pLCIDToLocaleName(lcid
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2962 ok(ret
> 0, "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2963 trace("%08lx, %s\n", lcid
, wine_dbgstr_w(buffer
));
2966 SetLastError(0xdeadbeef);
2967 lcid
= LocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT
, 0);
2968 ok(lcid
== GetSystemDefaultLCID(),
2969 "Expected lcid == %08lx, got %08lx, error %ld\n", GetSystemDefaultLCID(), lcid
, GetLastError());
2970 ret
= pLCIDToLocaleName(lcid
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2971 ok(ret
> 0, "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2972 trace("%08lx, %s\n", lcid
, wine_dbgstr_w(buffer
));
2975 SetLastError(0xdeadbeef);
2976 lcid
= pLocaleNameToLCID(LOCALE_NAME_INVARIANT
, 0);
2977 ok(lcid
== 0x7F, "Expected lcid = 0x7F, got %08lx, error %ld\n", lcid
, GetLastError());
2978 ret
= pLCIDToLocaleName(lcid
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2979 ok(ret
> 0, "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2980 trace("%08lx, %s\n", lcid
, wine_dbgstr_w(buffer
));
2982 pLCIDToLocaleName(GetUserDefaultLCID(), expbuff
, LOCALE_NAME_MAX_LENGTH
, 0);
2983 ret
= pLCIDToLocaleName(LOCALE_NEUTRAL
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2984 ok(ret
> 0, "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2985 ok( !wcscmp( buffer
, expbuff
), "got %s / %s\n", debugstr_w(buffer
), debugstr_w(expbuff
));
2987 ret
= pLCIDToLocaleName(LOCALE_CUSTOM_DEFAULT
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2988 ok(ret
> 0, "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2989 ok( !wcscmp( buffer
, expbuff
), "got %s / %s\n", debugstr_w(buffer
), debugstr_w(expbuff
));
2991 SetLastError( 0xdeadbeef );
2992 ret
= pLCIDToLocaleName(LOCALE_CUSTOM_UNSPECIFIED
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2993 ok(ret
> 0 || broken(!ret
), /* <= win8 */ "Expected ret > 0, got %d, error %ld\n", ret
, GetLastError());
2994 if (ret
) ok( !wcscmp( buffer
, expbuff
), "got %s / %s\n", debugstr_w(buffer
), debugstr_w(expbuff
));
2996 SetLastError( 0xdeadbeef );
2997 ret
= pLCIDToLocaleName(LOCALE_CUSTOM_UI_DEFAULT
, buffer
, LOCALE_NAME_MAX_LENGTH
, 0);
2998 if (ret
) trace("%08x, %s\n", GetUserDefaultUILanguage(), wine_dbgstr_w(buffer
));
2999 else ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError());
3002 SetLastError(0xdeadbeef);
3003 lcid
= pLocaleNameToLCID(invalidW
, 0);
3004 ok(!lcid
&& GetLastError() == ERROR_INVALID_PARAMETER
,
3005 "Expected lcid == 0, got %08lx, error %ld\n", lcid
, GetLastError());
3008 lcid
= pLocaleNameToLCID(L
"es-es", 0);
3009 ok(lcid
== MAKELCID(MAKELANGID(LANG_SPANISH
, SUBLANG_SPANISH_MODERN
), SORT_DEFAULT
), "Got wrong lcid for es-es: 0x%lx\n", lcid
);
3011 /* english neutral name */
3012 lcid
= pLocaleNameToLCID(L
"en", LOCALE_ALLOW_NEUTRAL_NAMES
);
3013 ok(lcid
== MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), SORT_DEFAULT
) ||
3014 broken(lcid
== 0) /* Vista */, "got 0x%04lx\n", lcid
);
3015 lcid
= pLocaleNameToLCID(L
"en", 0);
3016 ok(lcid
== MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
) ||
3017 broken(lcid
== 0) /* Vista */, "got 0x%04lx\n", lcid
);
3020 for (ptr
= neutralsublang_names
; *ptr
->name
; ptr
++)
3022 lcid
= pLocaleNameToLCID(ptr
->name
, 0);
3023 ok(lcid
== ptr
->lcid
, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3024 wine_dbgstr_w(ptr
->name
), lcid
, ptr
->lcid
);
3027 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3028 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(ptr
->name
), ret
);
3029 ok(!lstrcmpW(ptr
->sname
, buffer
), "%s: got wrong locale name %s\n",
3030 wine_dbgstr_w(ptr
->name
), wine_dbgstr_w(buffer
));
3034 /* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
3035 lcid
= pLocaleNameToLCID(L
"zh-Hant", 0);
3036 ok(lcid
== MAKELCID(MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
), SORT_DEFAULT
),
3037 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L
"zh-Hant"), lcid
);
3038 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3039 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-Hant"), ret
);
3040 ok(!lstrcmpW(L
"zh-HK", buffer
), "%s: got wrong locale name %s\n",
3041 wine_dbgstr_w(L
"zh-Hant"), wine_dbgstr_w(buffer
));
3042 /* check that 0x7c04 also works and is mapped to zh-HK */
3043 ret
= pLCIDToLocaleName(MAKELANGID(LANG_CHINESE_TRADITIONAL
, SUBLANG_CHINESE_TRADITIONAL
),
3044 buffer
, ARRAY_SIZE(buffer
), 0);
3045 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-Hant"), ret
);
3046 ok(!lstrcmpW(L
"zh-HK", buffer
), "%s: got wrong locale name %s\n",
3047 wine_dbgstr_w(L
"zh-Hant"), wine_dbgstr_w(buffer
));
3050 lcid
= pLocaleNameToLCID(L
"zh-hant", 0);
3051 ok(lcid
== MAKELCID(MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
), SORT_DEFAULT
),
3052 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L
"zh-hant"), lcid
);
3053 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3054 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-hant"), ret
);
3055 ok(!lstrcmpW(L
"zh-HK", buffer
), "%s: got wrong locale name %s\n",
3056 wine_dbgstr_w(L
"zh-hant"), wine_dbgstr_w(buffer
));
3058 /* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */
3059 lcid
= pLocaleNameToLCID(L
"zh-Hans", 0);
3060 /* check that LocaleNameToLCID actually returns 0x0804 */
3061 ok(lcid
== MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED
, SUBLANG_CHINESE_SIMPLIFIED
), SORT_DEFAULT
),
3062 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L
"zh-Hans"), lcid
);
3063 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3064 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-Hans"), ret
);
3065 ok(!lstrcmpW(L
"zh-CN", buffer
), "%s: got wrong locale name %s\n",
3066 wine_dbgstr_w(L
"zh-Hans"), wine_dbgstr_w(buffer
));
3067 /* check that 0x0004 also works and is mapped to zh-CN */
3068 ret
= pLCIDToLocaleName(MAKELANGID(LANG_CHINESE
, SUBLANG_NEUTRAL
), buffer
, ARRAY_SIZE(buffer
), 0);
3069 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-Hans"), ret
);
3070 ok(!lstrcmpW(L
"zh-CN", buffer
), "%s: got wrong locale name %s\n",
3071 wine_dbgstr_w(L
"zh-Hans"), wine_dbgstr_w(buffer
));
3074 lcid
= pLocaleNameToLCID(L
"zh-hans", 0);
3075 ok(lcid
== MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED
, SUBLANG_CHINESE_SIMPLIFIED
), SORT_DEFAULT
),
3076 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L
"zh-hans"), lcid
);
3077 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3078 ok(ret
> 0, "%s: got %d\n", wine_dbgstr_w(L
"zh-hans"), ret
);
3079 ok(!lstrcmpW(L
"zh-CN", buffer
), "%s: got wrong locale name %s\n",
3080 wine_dbgstr_w(L
"zh-hans"), wine_dbgstr_w(buffer
));
3083 lcid
= pLocaleNameToLCID(L
"de-DE_phoneb", 0);
3084 ok(lcid
== MAKELCID(MAKELANGID(LANG_GERMAN
, SUBLANG_DEFAULT
), SORT_GERMAN_PHONE_BOOK
),
3085 "%s: got wrong lcid 0x%04lx\n", wine_dbgstr_w(L
"zh-hans"), lcid
);
3086 ret
= pLCIDToLocaleName(lcid
, buffer
, ARRAY_SIZE(buffer
), 0);
3087 ok(!lstrcmpW(L
"de-DE_phoneb", buffer
), "got wrong locale name %s\n",
3088 wine_dbgstr_w(buffer
));
3091 if (pRtlLocaleNameToLcid
)
3093 status
= pRtlLocaleNameToLcid( LOCALE_NAME_USER_DEFAULT
, &lcid
, 0 );
3094 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3095 status
= pRtlLocaleNameToLcid( LOCALE_NAME_SYSTEM_DEFAULT
, &lcid
, 0 );
3096 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3097 status
= pRtlLocaleNameToLcid( invalidW
, &lcid
, 0 );
3098 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3101 status
= pRtlLocaleNameToLcid( LOCALE_NAME_INVARIANT
, &lcid
, 0 );
3102 ok( !status
, "failed error %lx\n", status
);
3103 ok( lcid
== LANG_INVARIANT
, "got %08lx\n", lcid
);
3106 status
= pRtlLocaleNameToLcid( localeW
, &lcid
, 0 );
3107 ok( !status
, "failed error %lx\n", status
);
3108 ok( lcid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), "got %08lx\n", lcid
);
3111 status
= pRtlLocaleNameToLcid( L
"es-es", &lcid
, 0 );
3112 ok( !status
, "failed error %lx\n", status
);
3113 ok( lcid
== MAKELANGID(LANG_SPANISH
, SUBLANG_SPANISH_MODERN
), "got %08lx\n", lcid
);
3116 status
= pRtlLocaleNameToLcid( L
"de-DE_phoneb", &lcid
, 0 );
3117 ok( !status
, "failed error %lx\n", status
);
3118 ok( lcid
== 0x00010407, "got %08lx\n", lcid
);
3121 status
= pRtlLocaleNameToLcid( L
"DE_de-PHONEB", &lcid
, 0 );
3122 ok( !status
|| broken( status
== STATUS_INVALID_PARAMETER_1
), "failed error %lx\n", status
);
3123 if (!status
) ok( lcid
== 0x00010407, "got %08lx\n", lcid
);
3126 status
= pRtlLocaleNameToLcid( L
"de+de+phoneb", &lcid
, 0 );
3127 ok( status
== STATUS_INVALID_PARAMETER_1
, "failed error %lx\n", status
);
3128 ok( lcid
== 0xdeadbeef, "got %08lx\n", lcid
);
3131 status
= pRtlLocaleNameToLcid( L
"en", &lcid
, 0 );
3132 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3133 status
= pRtlLocaleNameToLcid( L
"en", &lcid
, 1 );
3134 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3135 status
= pRtlLocaleNameToLcid( L
"en", &lcid
, 2 );
3136 ok( !status
, "failed error %lx\n", status
);
3137 ok( lcid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), "got %08lx\n", lcid
);
3138 status
= pRtlLocaleNameToLcid( L
"en-RR", &lcid
, 2 );
3139 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3140 status
= pRtlLocaleNameToLcid( L
"en-Latn-RR", &lcid
, 2 );
3141 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3143 for (ptr
= neutralsublang_names
; *ptr
->name
; ptr
++)
3145 switch (LANGIDFROMLCID(ptr
->lcid
))
3147 case MAKELANGID( LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_LATIN
): expect
= LANG_SERBIAN_NEUTRAL
; break;
3148 case MAKELANGID( LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_CYRILLIC
): expect
= 0x6c1a; break;
3149 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
): expect
= 0x7804; break;
3150 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
): expect
= LANG_CHINESE_TRADITIONAL
; break;
3151 default: expect
= MAKELANGID( PRIMARYLANGID(ptr
->lcid
), SUBLANG_NEUTRAL
); break;
3154 status
= pRtlLocaleNameToLcid( ptr
->name
, &lcid
, 2 );
3155 ok( !status
|| broken(ptr
->lcid
== MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
)), /* vista */
3156 "%s failed error %lx\n", wine_dbgstr_w(ptr
->name
), status
);
3157 if (!status
) ok( lcid
== expect
, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3158 wine_dbgstr_w(ptr
->name
), lcid
, expect
);
3159 status
= pRtlLocaleNameToLcid( ptr
->sname
, &lcid
, 0 );
3160 ok( !status
|| broken(ptr
->lcid
== MAKELANGID(LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_LATIN
)), /* vista */
3161 "%s failed error %lx\n", wine_dbgstr_w(ptr
->name
), status
);
3162 if (!status
) ok( lcid
== ptr
->lcid
, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n",
3163 wine_dbgstr_w(ptr
->name
), lcid
, ptr
->lcid
);
3166 else win_skip( "RtlLocaleNameToLcid not available\n" );
3168 if (pRtlLcidToLocaleName
)
3170 WCHAR buffer
[128], expect
[128];
3173 str
.Buffer
= buffer
;
3174 str
.MaximumLength
= sizeof( buffer
);
3175 memset( buffer
, 0xcc, sizeof(buffer
) );
3177 ok( !IsValidLocale( LOCALE_NEUTRAL
, 0 ), "expected invalid\n" );
3178 status
= pRtlLcidToLocaleName( LOCALE_NEUTRAL
, &str
, 0, 0 );
3179 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3180 status
= pRtlLcidToLocaleName( LOCALE_NEUTRAL
, &str
, 2, 0 );
3181 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3182 status
= pRtlLcidToLocaleName( LOCALE_INVARIANT
, NULL
, 0, 0 );
3183 ok( status
== STATUS_INVALID_PARAMETER_2
, "wrong error %lx\n", status
);
3185 memset( buffer
, 0xcc, sizeof(buffer
) );
3186 status
= pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), &str
, 0, 0 );
3187 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3188 ok( !wcscmp( buffer
, L
"en-US" ), "wrong name %s\n", debugstr_w(buffer
) );
3189 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3190 ok( str
.MaximumLength
== sizeof(buffer
), "wrong max len %u\n", str
.MaximumLength
);
3192 status
= pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), &str
, 0, 0 );
3193 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3195 memset( buffer
, 0xcc, sizeof(buffer
) );
3196 status
= pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), &str
, 2, 0 );
3197 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3198 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3199 ok( !wcscmp( buffer
, L
"en" ), "wrong name %s\n", debugstr_w(buffer
) );
3201 ok( IsValidLocale( 0x00010407, 0 ), "expected valid\n" );
3202 memset( buffer
, 0xcc, sizeof(buffer
) );
3203 status
= pRtlLcidToLocaleName( 0x00010407, &str
, 0, 0 );
3204 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3205 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3206 ok( !wcscmp( buffer
, L
"de-DE_phoneb" ), "wrong name %s\n", debugstr_w(buffer
) );
3208 ok( !IsValidLocale( LOCALE_SYSTEM_DEFAULT
, 0 ), "expected invalid\n" );
3209 memset( buffer
, 0xcc, sizeof(buffer
) );
3210 status
= pRtlLcidToLocaleName( LOCALE_SYSTEM_DEFAULT
, &str
, 0, 0 );
3211 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3212 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3213 LCIDToLocaleName( GetSystemDefaultLCID(), expect
, ARRAY_SIZE(expect
), 0 );
3214 ok( !wcscmp( buffer
, expect
), "wrong name %s / %s\n", debugstr_w(buffer
), debugstr_w(expect
) );
3216 ok( !IsValidLocale( LOCALE_USER_DEFAULT
, 0 ), "expected invalid\n" );
3217 memset( buffer
, 0xcc, sizeof(buffer
) );
3218 status
= pRtlLcidToLocaleName( LOCALE_USER_DEFAULT
, &str
, 0, 0 );
3219 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3220 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3221 LCIDToLocaleName( GetUserDefaultLCID(), expect
, ARRAY_SIZE(expect
), 0 );
3222 ok( !wcscmp( buffer
, expect
), "wrong name %s / %s\n", debugstr_w(buffer
), debugstr_w(expect
) );
3224 ok( IsValidLocale( LOCALE_INVARIANT
, 0 ), "expected valid\n" );
3225 memset( buffer
, 0xcc, sizeof(buffer
) );
3226 status
= pRtlLcidToLocaleName( LOCALE_INVARIANT
, &str
, 0, 0 );
3227 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3228 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3229 ok( !wcscmp( buffer
, L
"" ), "wrong name %s\n", debugstr_w(buffer
) );
3231 memset( buffer
, 0xcc, sizeof(buffer
) );
3232 status
= pRtlLcidToLocaleName( LOCALE_CUSTOM_DEFAULT
, &str
, 0, 0 );
3233 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3234 ok( str
.Length
== wcslen(buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3235 LCIDToLocaleName( GetUserDefaultLCID(), expect
, ARRAY_SIZE(expect
), 0 );
3236 ok( !wcscmp( buffer
, expect
), "wrong name %s / %s\n", debugstr_w(buffer
), debugstr_w(expect
) );
3238 status
= pRtlLcidToLocaleName( LOCALE_CUSTOM_UI_DEFAULT
, &str
, 0, 0 );
3239 ok( status
== STATUS_SUCCESS
|| status
== STATUS_UNSUCCESSFUL
, "wrong error %lx\n", status
);
3241 status
= pRtlLcidToLocaleName( LOCALE_CUSTOM_UNSPECIFIED
, &str
, 0, 0 );
3242 ok( status
== STATUS_INVALID_PARAMETER_1
, "wrong error %lx\n", status
);
3244 memset( buffer
, 0xcc, sizeof(buffer
) );
3245 str
.Length
= 0xbeef;
3246 str
.MaximumLength
= 5 * sizeof(WCHAR
);
3247 status
= pRtlLcidToLocaleName( 0x00010407, &str
, 0, 0 );
3248 ok( status
== STATUS_BUFFER_TOO_SMALL
, "wrong error %lx\n", status
);
3249 ok( str
.Length
== 0xbeef, "wrong len %u\n", str
.Length
);
3250 ok( str
.MaximumLength
== 5 * sizeof(WCHAR
), "wrong len %u\n", str
.MaximumLength
);
3251 ok( buffer
[0] == 0xcccc, "wrong name %s\n", debugstr_w(buffer
) );
3253 memset( &str
, 0xcc, sizeof(str
) );
3254 status
= pRtlLcidToLocaleName( MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), &str
, 0, 1 );
3255 ok( status
== STATUS_SUCCESS
, "wrong error %lx\n", status
);
3256 ok( str
.Length
== wcslen(str
.Buffer
) * sizeof(WCHAR
), "wrong len %u\n", str
.Length
);
3257 ok( str
.MaximumLength
== str
.Length
+ sizeof(WCHAR
), "wrong max len %u\n", str
.MaximumLength
);
3258 ok( !wcscmp( str
.Buffer
, L
"en-US" ), "wrong name %s\n", debugstr_w(str
.Buffer
) );
3259 RtlFreeUnicodeString( &str
);
3261 else win_skip( "RtlLcidToLocaleName not available\n" );
3263 if (pNlsValidateLocale
)
3268 lcid
= LOCALE_NEUTRAL
;
3269 ret
= pNlsValidateLocale( &lcid
, 0 );
3270 ok( !!ret
, "failed for %04lx\n", lcid
);
3271 ok( lcid
== GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid
);
3273 lcid
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
3274 ret
= pNlsValidateLocale( &lcid
, 0 );
3275 ok( !!ret
, "failed for %04lx\n", lcid
);
3276 ok( lcid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), "wrong lcid %04lx\n", lcid
);
3278 lcid
= MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
);
3279 ret2
= pNlsValidateLocale( &lcid
, 0 );
3280 ok( !!ret2
, "failed for %04lx\n", lcid
);
3281 ok( ret
== ret2
, "got different pointer for neutral\n" );
3282 ok( lcid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), "wrong lcid %04lx\n", lcid
);
3284 lcid
= MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
);
3285 ret2
= pNlsValidateLocale( &lcid
, LOCALE_ALLOW_NEUTRAL_NAMES
);
3286 ok( !!ret2
, "failed for %04lx\n", lcid
);
3287 ok( ret
!= ret2
, "got same pointer for neutral\n" );
3288 ok( lcid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_NEUTRAL
), "wrong lcid %04lx\n", lcid
);
3291 ret
= pNlsValidateLocale( &lcid
, 0 );
3292 ok( !!ret
, "failed for %04lx\n", lcid
);
3293 ok( lcid
== 0x00010407, "wrong lcid %04lx\n", lcid
);
3295 lcid
= LOCALE_SYSTEM_DEFAULT
;
3296 ret
= pNlsValidateLocale( &lcid
, 0 );
3297 ok( !!ret
, "failed for %04lx\n", lcid
);
3298 ok( lcid
== GetSystemDefaultLCID(), "wrong lcid %04lx\n", lcid
);
3299 ret2
= pNlsValidateLocale( &lcid
, 0 );
3300 ok( ret
== ret2
, "got different pointer for system\n" );
3302 lcid
= LOCALE_USER_DEFAULT
;
3303 ret
= pNlsValidateLocale( &lcid
, 0 );
3304 ok( !!ret
, "failed for %04lx\n", lcid
);
3305 ok( lcid
== GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid
);
3306 ret2
= pNlsValidateLocale( &lcid
, 0 );
3307 ok( ret
== ret2
, "got different pointer for user\n" );
3309 lcid
= LOCALE_INVARIANT
;
3310 ret
= pNlsValidateLocale( &lcid
, 0 );
3311 ok( !!ret
, "failed for %04lx\n", lcid
);
3312 ok( lcid
== LOCALE_INVARIANT
, "wrong lcid %04lx\n", lcid
);
3313 ret2
= pNlsValidateLocale( &lcid
, 0 );
3314 ok( ret
== ret2
, "got different pointer for invariant\n" );
3316 lcid
= LOCALE_CUSTOM_DEFAULT
;
3317 ret
= pNlsValidateLocale( &lcid
, 0 );
3318 ok( !!ret
, "failed for %04lx\n", lcid
);
3319 ok( lcid
== GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid
);
3320 ret2
= pNlsValidateLocale( &lcid
, 0 );
3321 ok( ret
== ret2
, "got different pointer for custom default\n" );
3323 lcid
= LOCALE_CUSTOM_UNSPECIFIED
;
3324 ret
= pNlsValidateLocale( &lcid
, 0 );
3325 ok( ret
|| broken(!ret
), /* <= win8 */ "failed for %04lx\n", lcid
);
3326 if (ret
) ok( lcid
== GetUserDefaultLCID(), "wrong lcid %04lx\n", lcid
);
3328 SetLastError( 0xdeadbeef );
3329 lcid
= LOCALE_CUSTOM_UI_DEFAULT
;
3330 ret
= pNlsValidateLocale( &lcid
, 0 );
3331 if (!ret
) ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError());
3334 ret
= pNlsValidateLocale( &lcid
, 0 );
3335 ok( !ret
, "succeeded\n" );
3336 ok( lcid
== 0xbeef, "wrong lcid %04lx\n", lcid
);
3337 ok( GetLastError() == 0xdeadbeef, "error %lu\n", GetLastError());
3339 else win_skip( "NlsValidateLocale not available\n" );
3342 static const char * const strings_sorted
[] =
3374 static const char * const strings
[] =
3406 static int compare_string1(const void *e1
, const void *e2
)
3408 const char *s1
= *(const char *const *)e1
;
3409 const char *s2
= *(const char *const *)e2
;
3411 return lstrcmpA(s1
, s2
);
3414 static int compare_string2(const void *e1
, const void *e2
)
3416 const char *s1
= *(const char *const *)e1
;
3417 const char *s2
= *(const char *const *)e2
;
3419 return CompareStringA(0, 0, s1
, -1, s2
, -1) - 2;
3422 static int compare_string3(const void *e1
, const void *e2
)
3424 const char *s1
= *(const char *const *)e1
;
3425 const char *s2
= *(const char *const *)e2
;
3426 char key1
[256], key2
[256];
3428 int len1
= LCMapStringA(0, LCMAP_SORTKEY
, s1
, -1, key1
, sizeof(key1
));
3429 int len2
= LCMapStringA(0, LCMAP_SORTKEY
, s2
, -1, key2
, sizeof(key2
));
3430 int ret
= memcmp(key1
, key2
, min(len1
, len2
));
3431 if (!ret
) ret
= len1
- len2
;
3435 static void test_sorting(void)
3438 char **str_buf
= (char **)buf
;
3441 assert(sizeof(buf
) >= sizeof(strings
));
3443 /* 1. sort using lstrcmpA */
3444 memcpy(buf
, strings
, sizeof(strings
));
3445 qsort(buf
, ARRAY_SIZE(strings
), sizeof(strings
[0]), compare_string1
);
3446 for (i
= 0; i
< ARRAY_SIZE(strings
); i
++)
3448 ok(!strcmp(strings_sorted
[i
], str_buf
[i
]),
3449 "qsort using lstrcmpA failed for element %d\n", i
);
3451 /* 2. sort using CompareStringA */
3452 memcpy(buf
, strings
, sizeof(strings
));
3453 qsort(buf
, ARRAY_SIZE(strings
), sizeof(strings
[0]), compare_string2
);
3454 for (i
= 0; i
< ARRAY_SIZE(strings
); i
++)
3456 ok(!strcmp(strings_sorted
[i
], str_buf
[i
]),
3457 "qsort using CompareStringA failed for element %d\n", i
);
3459 /* 3. sort using sort keys */
3460 memcpy(buf
, strings
, sizeof(strings
));
3461 qsort(buf
, ARRAY_SIZE(strings
), sizeof(strings
[0]), compare_string3
);
3462 for (i
= 0; i
< ARRAY_SIZE(strings
); i
++)
3464 ok(!strcmp(strings_sorted
[i
], str_buf
[i
]),
3465 "qsort using sort keys failed for element %d\n", i
);
3469 struct sorting_test_entry
{
3470 const WCHAR
*locale
;
3475 const WCHAR
*second
;
3478 static const struct sorting_test_entry unicode_sorting_tests
[] =
3480 /* Normal character */
3481 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0037", L
"\x277c" },
3482 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1eca", L
"\x1ecb" },
3483 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1d05", L
"\x1d48" },
3484 /* Normal character diacritics */
3485 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x19d7", L
"\x096d" },
3486 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00f5", L
"\x1ecf" },
3487 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x2793", L
"\x0d70" },
3488 /* Normal character case weights */
3489 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"A", L
"a" },
3490 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"z", L
"Z" },
3492 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xe5a6", L
"\xe5a5\x0333" },
3493 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xe5d7", L
"\xe5d6\x0330" },
3494 /* Symbols add diacritic weight */
3495 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\u276a", L
"\u2768" },
3496 /* Symbols add case weight */
3497 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\u204d", L
"\uff02" },
3498 /* Default character, when there is main weight extra there must be no diacritic weight */
3499 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\ue6e3\u0a02", L
"\ue6e3\u20dc" },
3500 /* Unsortable characters */
3501 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"a \u2060 b", L
"a b" },
3502 /* Invalid/undefined characters */
3503 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"a \xfff0 b", L
"a b" },
3504 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"a\x139F a", L
"a a" },
3505 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"a\x139F a", L
"a b" },
3506 /* Default characters */
3507 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00fc", L
"\x016d" },
3508 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3fcb\x7fd5", L
"\x0006\x3032" },
3509 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00fc\x30fd", L
"\x00fa\x1833" },
3510 /* Diacritic is added */
3511 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1B56\x0330", L
"\x1096" },
3512 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1817\x0333", L
"\x19d7" },
3513 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x04de\x05ac", L
"\x0499" },
3514 /* Diacritic can overflow */
3515 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x01ba\x0654", L
"\x01b8" },
3516 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x06b7\x06eb", L
"\x06b6" },
3517 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x1420\x0333", L
"\x141f" },
3518 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1b56\x0654", L
"\x1b56\x0655" },
3519 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x1b56\x0654\x0654", L
"\x1b56\x0655" },
3520 /* Jamo case weight */
3521 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x11bc", L
"\x110b" },
3522 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x11c1", L
"\x1111" },
3523 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x11af", L
"\x1105" },
3524 /* Jamo main weight */
3525 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x11c2", L
"\x11f5" },
3526 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x1108", L
"\x1121" },
3527 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x1116", L
"\x11c7" },
3528 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x11b1", L
"\x11d1" },
3529 /* CJK main weight 1 */
3530 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x4550\x73d2", L
"\x3211\x23ad" },
3531 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x3265", L
"\x4079" },
3532 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x4c19\x68d0\x52d0", L
"\x316d" },
3533 /* CJK main weight 2 */
3534 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x72dd", L
"\x6b8a" },
3535 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x6785\x3bff\x6f83", L
"\x7550\x34c9\x71a7" },
3536 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x5d61", L
"\x3aef" },
3537 /* Symbols case weights */
3538 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x207a", L
"\xfe62" },
3539 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xfe65", L
"\xff1e" },
3540 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x2502", L
"\xffe8" },
3541 /* Symbols diacritic weights */
3542 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x21da", L
"\x21dc" },
3543 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x29fb", L
"\x2295" },
3544 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0092", L
"\x009c" },
3545 /* NORM_IGNORESYMBOLS */
3546 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x21da", L
"\x21dc" },
3547 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x29fb", L
"\x2295" },
3548 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x0092", L
"\x009c" },
3549 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"\x3099", L
"\x309b" }, /* Small diacritic weights at the end get ignored */
3550 /* Main weights have priority over diacritic weights */
3551 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"a b", L
"\x0103 a" },
3552 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"a", L
"\x0103" },
3553 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"e x", L
"\x0113 v" },
3554 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"e", L
"\x0113" },
3555 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"c s", L
"\x0109 r" },
3556 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"c", L
"\x0109" },
3557 /* Diacritic weights have priority over case weights */
3558 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"a \x0103", L
"A a" },
3559 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"a", L
"A" },
3560 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"e \x0113", L
"E e" },
3561 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"e", L
"E" },
3562 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"c \x0109", L
"C c" },
3563 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"c", L
"C" },
3564 /* Diacritic values for Jamo are not ignored */
3565 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORENONSPACE
, L
"\x1152", L
"\x1153" },
3566 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORENONSPACE
, L
"\x1143", L
"\x1145" },
3567 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORENONSPACE
, L
"\x1196", L
"\x1174" },
3568 /* Jungseong < PUA */
3569 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x318e", L
"\x382a" },
3570 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xffcb", L
"\x3d13" },
3571 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xffcc", L
"\x8632" },
3572 /* Surrogate > PUA */
3573 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xd847", L
"\x382a" },
3574 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xd879", L
"\x3d13" },
3575 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xd850", L
"\x8632" },
3576 /* Unsortable combined with diacritics */
3577 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"A\x0301\x0301", L
"A\x0301\x00ad\x0301" },
3578 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"b\x07f2\x07f2", L
"b\x07f2\x2064\x07f2" },
3579 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"X\x0337\x0337", L
"X\x0337\xfffd\x0337" },
3580 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORECASE
, L
"c", L
"C" },
3581 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORECASE
, L
"e", L
"E" },
3582 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORECASE
, L
"A", L
"a" },
3583 /* Punctuation primary weight */
3584 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x001b", L
"\x001c" },
3585 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0005", L
"\x0006" },
3586 /* Punctuation diacritic/case weight */
3587 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0027", L
"\xff07" },
3588 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x07f4", L
"\x07f5" },
3589 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x207b", L
"\x0008" },
3590 /* Punctuation primary weight has priority */
3591 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xff07", L
"\x07f4" },
3592 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xfe32", L
"\x2014" },
3593 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x058a", L
"\x2027" },
3595 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x207b", L
"\x0008" },
3596 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0004", L
"\x0011" },
3597 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x207b", L
"\x0008" },
3598 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x0004", L
"\x0011" },
3599 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x207b", L
"\x0008" },
3600 { L
"en-US", -1, CSTR_LESS_THAN
, SORT_STRINGSORT
, L
"\x0004", L
"\x0011" },
3601 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
| SORT_STRINGSORT
, L
"\x207b", L
"\x0008" },
3602 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
| SORT_STRINGSORT
, L
"\x0004", L
"\x0011" },
3603 /* Punctuation main weight */
3604 { L
"en-US", -1, CSTR_LESS_THAN
, SORT_STRINGSORT
, L
"\x001a", L
"\x001b" },
3605 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x2027", L
"\x2011" },
3606 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x3030", L
"\x301c" },
3607 /* Punctuation diacritic weight */
3608 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x058a", L
"\x2010" },
3609 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x07F5", L
"\x07F4" },
3610 /* Punctuation case weight */
3611 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xfe32", L
"\x2013" },
3612 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xfe31", L
"\xfe58" },
3613 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xff07", L
"\x0027" },
3614 /* Punctuation NORM_IGNORESYMBOLS */
3615 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x207b", L
"\x0008" },
3616 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
, L
"\x0004", L
"\x0011" },
3617 /* Punctuation NORM_IGNORESYMBOLS SORT_STRINGSORT */
3618 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
| SORT_STRINGSORT
, L
"\x207b", L
"\x0008" },
3619 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORESYMBOLS
| SORT_STRINGSORT
, L
"\x0004", L
"\x0011" },
3620 /* Punctuation SORT_STRINGSORT main weight */
3621 { L
"en-US", -1, CSTR_LESS_THAN
, SORT_STRINGSORT
, L
"\x001a", L
"\x001b" },
3622 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x2027", L
"\x2011", },
3623 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x3030", L
"\x301c", },
3624 /* Punctuation SORT_STRINGSORT diacritic weight */
3625 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x058a", L
"\x2010" },
3626 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\x07F5", L
"\x07F4" },
3627 /* Punctuation SORT_STRINGSORT case weight */
3628 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xfe32", L
"\x2013" },
3629 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xfe31", L
"\xfe58" },
3630 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_STRINGSORT
, L
"\xff07", L
"\x0027" },
3631 /* Japanese main weight */
3632 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x04b0", L
"\x32db" },
3633 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3093", L
"\x1e62\x013f" },
3634 /* Japanese diacritic weight */
3635 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30d3", L
"\x30d4" },
3636 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x307b", L
"\x307c" },
3637 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30ea", L
"\x32f7" },
3638 /* Japanese case weight small */
3639 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x31fb", L
"\x30e9" },
3640 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30db", L
"\x31f9" },
3641 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xff6d", L
"\xff95" },
3642 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\x31fb", L
"\x30e9" },
3643 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\x30db", L
"\x31f9" },
3644 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\xff6d", L
"\xff95" },
3645 /* Japanese case weight kana */
3646 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30d5", L
"\x3075" },
3647 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x306a", L
"\x30ca" },
3648 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x305a", L
"\x30ba" },
3649 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x30d5", L
"\x3075" },
3650 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x306a", L
"\x30ca" },
3651 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x305a", L
"\x30ba" },
3652 /* Japanese case weight width */
3653 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30bf", L
"\xff80" },
3654 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30ab", L
"\xff76" },
3655 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30a2", L
"\xff71" },
3656 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\x30bf", L
"\xff80" },
3657 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\x30ab", L
"\xff76" },
3658 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\x30a2", L
"\xff71" },
3659 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\x31a2", L
"\x3110" },
3660 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\x1342", L
"\x133a" },
3661 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNORENONSPACE
, L
"\x16a4", L
"\x16a5" },
3662 /* Kana small data must have priority over width data */
3663 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30b1\x30f6", L
"\xff79\x30b1" },
3664 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30a6\x30a5", L
"\xff73\x30a6" },
3665 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30a8\x30a7", L
"\xff74\x30a8" },
3666 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30b1", L
"\xff79" },
3667 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30a6", L
"\xff73" },
3668 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30a8", L
"\xff74" },
3669 /* Kana small data must have priority over kana type data */
3670 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x3046\x30a9", L
"\x30a6\x30aa" },
3671 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x304a\x3041", L
"\x30aa\x3042" },
3672 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x3059\x30a7", L
"\x30b9\x30a8" },
3673 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3046", L
"\x30a6" },
3674 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x304a", L
"\x30aa" },
3675 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3059", L
"\x30b9" },
3676 /* Kana type data must have priority over width data */
3677 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30a6\x30a8", L
"\xff73\x3048" },
3678 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30ab\x30a3", L
"\xff76\x3043" },
3679 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30b5\x30ac", L
"\xff7b\x304c" },
3680 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30a6", L
"\xff73" },
3681 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30ab", L
"\xff76" },
3682 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30b5", L
"\xff7b" },
3683 /* Case weights have priority over extra weights */
3684 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x305a a", L
"\x30ba A" },
3685 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30c1 b", L
"\xff81 B" },
3686 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xff8b x", L
"\x31f6 X" },
3687 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x305a", L
"\x30ba" },
3688 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30c1", L
"\xff81" },
3689 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xff8b", L
"\x31f6" },
3690 /* Extra weights have priority over special weights */
3691 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0027\x31ff", L
"\x007f\xff9b" },
3692 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x07f5\x30f3", L
"\x07f4\x3093" },
3693 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xfe63\x30e0", L
"\xff0d\x3080" },
3694 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x0027", L
"\x007f" },
3695 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x07f5", L
"\x07f4" },
3696 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xfe63", L
"\xff0d" },
3697 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\xff68", L
"\x30a3" },
3698 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\xff75", L
"\x30aa" },
3699 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\x30e2", L
"\xff93" },
3700 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xff68", L
"\x30a3" },
3701 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\xff75", L
"\x30aa" },
3702 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x30e2", L
"\xff93" },
3703 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x30a8", L
"\x3048" },
3704 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x30af", L
"\x304f" },
3705 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREKANATYPE
, L
"\x3067", L
"\x30c7" },
3706 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30a8", L
"\x3048" },
3707 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30af", L
"\x304f" },
3708 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3067", L
"\x30c7" },
3709 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\xffb7", L
"\x3147" },
3710 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\xffb6", L
"\x3146" },
3711 { L
"en-US", 0, CSTR_EQUAL
, NORM_IGNOREWIDTH
, L
"\x3145", L
"\xffb5" },
3712 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORECASE
, L
"\xffb7", L
"\x3147" },
3713 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORECASE
, L
"\xffb6", L
"\x3146" },
3714 { L
"en-US", 1, CSTR_GREATER_THAN
, NORM_IGNORECASE
, L
"\x3145", L
"\xffb5" },
3715 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x3075\x30fc", L
"\x30d5\x30fc" },
3716 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x30a1\x30fc", L
"\x30a2\x30fc" },
3717 /* Coptic < Japanese */
3718 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORECASE
, L
"\x2cff", L
"\x30ba" },
3719 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORECASE
, L
"\x2cdb", L
"\x32de" },
3720 { L
"en-US", -1, CSTR_LESS_THAN
, NORM_IGNORECASE
, L
"\x2ce0", L
"\x30c6" },
3721 /* Hebrew > Japanese */
3722 { L
"en-US", 1, CSTR_GREATER_THAN
, NORM_IGNORECASE
, L
"\x05d3", L
"\x30ba" },
3723 { L
"en-US", 1, CSTR_GREATER_THAN
, NORM_IGNORECASE
, L
"\x05e3", L
"\x32de" },
3724 { L
"en-US", 1, CSTR_GREATER_THAN
, NORM_IGNORECASE
, L
"\x05d7", L
"\x30c6" },
3726 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"\x00c6", L
"\x0041\x0045" },
3727 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"\x0f5c", L
"\x0f5b\x0fb7" },
3728 { L
"en-US", 0, CSTR_EQUAL
, 0, L
"\x05f0", L
"\x05d5\x05d5" },
3729 { L
"en-US", -1, CSTR_EQUAL
, 0, L
"\x0f75", L
"\x0f71\x0f74" },
3730 { L
"en-US", -1, CSTR_EQUAL
, 0, L
"\xfc5e", L
"\x064c\x0651" },
3731 { L
"en-US", -1, CSTR_EQUAL
, 0, L
"\xfb2b", L
"\x05e9\x05c2" },
3732 { L
"en-US", -1, CSTR_EQUAL
, 0, L
"\xfe71", L
"\x0640\x064b" },
3733 /* Japanese locale */
3734 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x6df8", L
"\x654b\x29e9" },
3735 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x685d\x1239\x1b61", L
"\x59b6\x6542\x2a62\x04a7" },
3736 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x62f3\x43e9", L
"\x5760" },
3737 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x634c", L
"\x2f0d\x5f1c\x7124" },
3738 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x69e7\x0502", L
"\x57cc" },
3739 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x7589", L
"\x67c5" },
3740 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x5ede\x765c", L
"\x7324" },
3741 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x5c7f\x5961", L
"\x7cbe" },
3742 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x3162", L
"\x6a84\x1549\x0b60" },
3743 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x769e\x448e", L
"\x4e6e" },
3744 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x59a4", L
"\x5faa\x607c" },
3745 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x529b", L
"\x733f" },
3746 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x6ff8\x2a0a", L
"\x7953\x6712" },
3747 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x6dfb", L
"\x6793" },
3748 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x67ed", L
"\x6aa2" },
3749 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x4e61", L
"\x6350\x6b08" },
3750 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x5118", L
"\x53b3\x75b4" },
3751 { L
"ja-JP", -1, CSTR_LESS_THAN
, 0, L
"\x6bbf", L
"\x65a3" },
3752 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x5690", L
"\x5fa8" },
3753 { L
"ja-JP", 1, CSTR_GREATER_THAN
, 0, L
"\x61e2", L
"\x76e5" },
3755 { L
"ko-KR", -1, CSTR_LESS_THAN
, 0, L
"\x8db6", L
"\xd198" },
3756 { L
"ko-KR", -1, CSTR_LESS_THAN
, 0, L
"\x8f72", L
"\xd2b9" },
3757 { L
"ko-KR", -1, CSTR_LESS_THAN
, 0, L
"\x91d8", L
"\xd318" },
3758 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x8db6", L
"\xd198" },
3759 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x8f72", L
"\xd2b9" },
3760 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x91d8", L
"\xd318" },
3761 { L
"cs-CZ", 1, CSTR_GREATER_THAN
, 0, L
"\x0160", L
"\x0219" },
3762 { L
"cs-CZ", 1, CSTR_GREATER_THAN
, 0, L
"\x059a", L
"\x0308" },
3763 { L
"cs-CZ", 1, CSTR_GREATER_THAN
, 0, L
"\x013a", L
"\x013f" },
3764 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x0160", L
"\x0219" },
3765 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x059a", L
"\x0308" },
3766 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x013a", L
"\x013f" },
3767 { L
"vi-VN", -1, CSTR_LESS_THAN
, 0, L
"\x1d8f", L
"\x1ea8" },
3768 { L
"vi-VN", -1, CSTR_LESS_THAN
, 0, L
"\x0323", L
"\xfe26" },
3769 { L
"vi-VN", 1, CSTR_GREATER_THAN
, 0, L
"R", L
"\xff32" },
3770 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x1d8f", L
"\x1ea8" },
3771 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x0323", L
"\xfe26" },
3772 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"R", L
"\xff32" },
3773 { L
"zh-HK", -1, CSTR_LESS_THAN
, 0, L
"\x83ae", L
"\x71b9" },
3774 { L
"zh-HK", -1, CSTR_LESS_THAN
, 0, L
"\x7e50", L
"\xc683" },
3775 { L
"zh-HK", 1, CSTR_GREATER_THAN
, 0, L
"\x6c69", L
"\x7f8a" },
3776 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x83ae", L
"\x71b9" },
3777 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x7e50", L
"\xc683" },
3778 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x6c69", L
"\x7f8a" },
3779 { L
"tr-TR", 1, CSTR_GREATER_THAN
, 0, L
"\x00dc", L
"\x1ee9" },
3780 { L
"tr-TR", 1, CSTR_GREATER_THAN
, 0, L
"\x00fc", L
"\x1ee6" },
3781 { L
"tr-TR", -1, CSTR_LESS_THAN
, 0, L
"\x0152", L
"\x00d6" },
3782 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00dc", L
"\x1ee9" },
3783 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00fc", L
"\x1ee6" },
3784 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\x0152", L
"\x00d6" },
3785 /* Diacritic is added */
3786 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xa042\x09bc", L
"\xa042" },
3787 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xa063\x302b", L
"\xa063" },
3788 { L
"en-US", 1, CSTR_GREATER_THAN
, 0, L
"\xa07e\x0c56", L
"\xa07e" },
3789 /* Reversed diacritics */
3790 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"\x00e9\x00e8", L
"\x00e8\x00e9" },
3791 { L
"fr-FR", 1, CSTR_GREATER_THAN
, 0, L
"\x00e9\x00e8", L
"\x00e8\x00e9" },
3793 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"1230", L
"321" },
3794 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_DIGITSASNUMBERS
, L
"1230", L
"321" },
3795 { L
"en-US", 1, CSTR_GREATER_THAN
, SORT_DIGITSASNUMBERS
, L
"\xc6f\xc6c\xc6a", L
"\xc6f\xc6e" },
3797 { L
"en-US", -1, CSTR_LESS_THAN
, 0, L
"E\x0300", L
"F" },
3798 { L
"rm-CH", 1, CSTR_GREATER_THAN
, 0, L
"E\x0300", L
"F" },
3801 static void test_unicode_sorting(void)
3807 if (!pLCMapStringEx
)
3809 win_skip("LCMapStringEx not available\n");
3812 for (i
= 0; i
< ARRAY_SIZE(unicode_sorting_tests
); i
++)
3818 const struct sorting_test_entry
*entry
= &unicode_sorting_tests
[i
];
3820 len1
= pLCMapStringEx(entry
->locale
, LCMAP_SORTKEY
| entry
->flags
, entry
->first
, -1, (WCHAR
*)buff1
, ARRAY_SIZE(buff1
), NULL
, NULL
, 0);
3821 len2
= pLCMapStringEx(entry
->locale
, LCMAP_SORTKEY
| entry
->flags
, entry
->second
, -1, (WCHAR
*)buff2
, ARRAY_SIZE(buff2
), NULL
, NULL
, 0);
3823 result
= memcmp(buff1
, buff2
, min(len1
, len2
));
3824 if (result
< 0) result
= -1;
3825 else if (result
> 0) result
= 1;
3826 else if (len1
< len2
) result
= -1;
3827 else if (len1
> len2
) result
= 1;
3829 ok (result
== entry
->result_sortkey
, "Test %d (%s, %s) - Expected %d, got %d\n",
3830 i
, wine_dbgstr_w(entry
->first
), wine_dbgstr_w(entry
->second
), entry
->result_sortkey
, result
);
3832 result
= CompareStringEx(entry
->locale
, entry
->flags
, entry
->first
, -1, entry
->second
, -1, NULL
, NULL
, 0);
3833 ok (result
== entry
->result_compare
, "Test %d (%s, %s) - Expected %d, got %d\n",
3834 i
, wine_dbgstr_w(entry
->first
), wine_dbgstr_w(entry
->second
), entry
->result_compare
, result
);
3836 /* Test diacritics when buffer is short */
3837 ret1
= pLCMapStringEx(L
"en-US", LCMAP_SORTKEY
, L
"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR
*)buffer
, 20, NULL
, NULL
, 0);
3838 ret2
= pLCMapStringEx(L
"en-US", LCMAP_SORTKEY
, L
"\x0e49\x0e49\x0e49\x0e49\x0e49", -1, (WCHAR
*)buffer
, 0, NULL
, NULL
, 0);
3839 ok(ret1
== ret2
, "Got ret1=%d, ret2=%d\n", ret1
, ret2
);
3842 static void test_FoldStringA(void)
3846 char src
[256], dst
[256];
3847 static const char digits_src
[] = { 0xB9,0xB2,0xB3,'\0' };
3848 static const char digits_dst
[] = { '1','2','3','\0' };
3849 static const char composite_src
[] =
3851 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
3852 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
3853 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
3854 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
3855 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
3856 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
3857 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
3858 0xfb,0xfc,0xfd,0xff,'\0'
3860 static const char composite_dst
[] =
3862 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3863 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3864 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3865 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3866 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3867 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3868 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
3869 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
3870 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
3871 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
3872 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
3873 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
3874 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
3875 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
3876 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3878 static const char composite_dst_alt
[] =
3880 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3881 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3882 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3883 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3884 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3885 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3886 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
3887 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
3888 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
3889 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
3890 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
3891 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
3892 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
3893 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3894 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3896 static const char ligatures_src
[] =
3898 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3900 static const char ligatures_dst
[] =
3902 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3904 static const struct special
3908 } foldczone_special
[] =
3911 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3912 { 0x98, { 0x20, 0x7e, 0x00 } },
3913 { 0x99, { 0x54, 0x4d, 0x00 } },
3914 { 0xa0, { 0x20, 0x00 } },
3915 { 0xa8, { 0x20, 0xa8, 0x00 } },
3916 { 0xaa, { 0x61, 0x00 } },
3917 { 0xaf, { 0x20, 0xaf, 0x00 } },
3918 { 0xb2, { 0x32, 0x00 } },
3919 { 0xb3, { 0x33, 0x00 } },
3920 { 0xb4, { 0x20, 0xb4, 0x00 } },
3921 { 0xb8, { 0x20, 0xb8, 0x00 } },
3922 { 0xb9, { 0x31, 0x00 } },
3923 { 0xba, { 0x6f, 0x00 } },
3924 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3925 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
3926 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
3930 /* these tests are locale specific */
3931 if (GetACP() != 1252)
3933 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
3937 /* MAP_FOLDDIGITS */
3938 SetLastError(0xdeadbeef);
3939 ret
= FoldStringA(MAP_FOLDDIGITS
, digits_src
, -1, dst
, 256);
3940 ok(ret
== 4, "Expected ret == 4, got %d, error %ld\n", ret
, GetLastError());
3941 ok(strcmp(dst
, digits_dst
) == 0,
3942 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst
, dst
);
3943 for (i
= 1; i
< 256; i
++)
3945 if (!strchr(digits_src
, i
))
3949 ret
= FoldStringA(MAP_FOLDDIGITS
, src
, -1, dst
, 256);
3950 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
3951 ok(dst
[0] == src
[0],
3952 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src
, dst
);
3956 /* MAP_EXPAND_LIGATURES */
3957 SetLastError(0xdeadbeef);
3958 ret
= FoldStringA(MAP_EXPAND_LIGATURES
, ligatures_src
, -1, dst
, 256);
3959 ok(ret
== sizeof(ligatures_dst
), "Got %d, error %ld\n", ret
, GetLastError());
3960 ok(strcmp(dst
, ligatures_dst
) == 0,
3961 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst
, dst
);
3962 for (i
= 1; i
< 256; i
++)
3964 if (!strchr(ligatures_src
, i
))
3968 ret
= FoldStringA(MAP_EXPAND_LIGATURES
, src
, -1, dst
, 256);
3972 ok((i
== 0xDC && lstrcmpA(dst
, "UE") == 0) ||
3973 (i
== 0xFC && lstrcmpA(dst
, "ue") == 0),
3974 "Got %s for %d\n", dst
, i
);
3978 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
3979 ok(dst
[0] == src
[0],
3980 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src
, dst
);
3986 SetLastError(0xdeadbeef);
3987 ret
= FoldStringA(MAP_COMPOSITE
, composite_src
, -1, dst
, 256);
3988 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
3989 ok( GetLastError() == 0xdeadbeef || broken(!GetLastError()), /* vista */
3990 "wrong error %lu\n", GetLastError());
3991 ok(ret
== 121 || ret
== 119, "Expected 121 or 119, got %d\n", ret
);
3992 ok(strcmp(dst
, composite_dst
) == 0 || strcmp(dst
, composite_dst_alt
) == 0,
3993 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst
);
3995 for (i
= 1; i
< 256; i
++)
3997 if (!strchr(composite_src
, i
))
4001 ret
= FoldStringA(MAP_COMPOSITE
, src
, -1, dst
, 256);
4002 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
4003 ok(dst
[0] == src
[0],
4004 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src
[0],
4005 (unsigned char)dst
[0],(unsigned char)dst
[1],(unsigned char)dst
[2]);
4010 for (i
= 1; i
< 256; i
++)
4014 SetLastError(0xdeadbeef);
4015 ret
= FoldStringA(MAP_FOLDCZONE
, src
, -1, dst
, 256);
4017 for (j
= 0; foldczone_special
[j
].src
!= 0 && ! is_special
; j
++)
4019 if (foldczone_special
[j
].src
== src
[0])
4021 ok(ret
== 2 || ret
== lstrlenA(foldczone_special
[j
].dst
) + 1,
4022 "Expected ret == 2 or %d, got %d, error %ld\n",
4023 lstrlenA(foldczone_special
[j
].dst
) + 1, ret
, GetLastError());
4024 ok(src
[0] == dst
[0] || lstrcmpA(foldczone_special
[j
].dst
, dst
) == 0,
4025 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
4026 (unsigned char)src
[0]);
4032 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
4033 ok(src
[0] == dst
[0],
4034 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
4035 (unsigned char)src
[0], (unsigned char)dst
[0]);
4039 /* MAP_PRECOMPOSED */
4040 for (i
= 1; i
< 256; i
++)
4044 ret
= FoldStringA(MAP_PRECOMPOSED
, src
, -1, dst
, 256);
4045 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
4046 ok(src
[0] == dst
[0],
4047 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
4048 (unsigned char)src
[0], (unsigned char)dst
[0]);
4052 static void test_FoldStringW(void)
4056 unsigned int i
, j
, len
;
4057 WCHAR src
[256], dst
[256];
4058 UINT ch
, prev_ch
= 1;
4059 static const DWORD badFlags
[] =
4062 MAP_PRECOMPOSED
|MAP_COMPOSITE
,
4063 MAP_PRECOMPOSED
|MAP_EXPAND_LIGATURES
,
4064 MAP_COMPOSITE
|MAP_EXPAND_LIGATURES
4066 /* Ranges of digits 0-9 : Must be sorted! */
4067 static const struct { UINT ch
, first
, last
; int broken
; } digitRanges
[] =
4069 { 0x0030, 0, 9 }, /* '0'-'9' */
4070 { 0x00b2, 2, 3 }, /* Superscript 2, 3 */
4071 { 0x00b9, 1, 1 }, /* Superscript 1 */
4072 { 0x0660, 0, 9 }, /* Eastern Arabic */
4073 { 0x06f0, 0, 9 }, /* Arabic - Hindu */
4074 { 0x07c0, 0, 9 }, /* Nko */
4075 { 0x0966, 0, 9 }, /* Devengari */
4076 { 0x09e6, 0, 9 }, /* Bengalii */
4077 { 0x0a66, 0, 9 }, /* Gurmukhi */
4078 { 0x0ae6, 0, 9 }, /* Gujarati */
4079 { 0x0b66, 0, 9 }, /* Oriya */
4080 { 0x0be6, 0, 9 }, /* Tamil */
4081 { 0x0c66, 0, 9 }, /* Telugu */
4082 { 0x0c78, 0, 3, TRUE
/*win7*/ }, /* Telugu Fraction */
4083 { 0x0c7c, 1, 3, TRUE
/*win7*/ }, /* Telugu Fraction */
4084 { 0x0ce6, 0, 9 }, /* Kannada */
4085 { 0x0d66, 0, 9 }, /* Maylayalam */
4086 { 0x0de6, 0, 9, TRUE
/*win10*/ }, /* Sinhala Lith */
4087 { 0x0e50, 0, 9 }, /* Thai */
4088 { 0x0ed0, 0, 9 }, /* Laos */
4089 { 0x0f20, 0, 9 }, /* Tibet */
4090 { 0x1040, 0, 9 }, /* Myanmar */
4091 { 0x1090, 0, 9 }, /* Myanmar Shan */
4092 { 0x1369, 1, 9 }, /* Ethiopic */
4093 { 0x17e0, 0, 9 }, /* Khmer */
4094 { 0x1810, 0, 9 }, /* Mongolian */
4095 { 0x1946, 0, 9 }, /* Limbu */
4096 { 0x19d0, 0, 9 }, /* New Tai Lue */
4097 { 0x19da, 1, 1, TRUE
/*win7*/ }, /* New Tai Lue Tham 1 */
4098 { 0x1a80, 0, 9, TRUE
/*win7*/ }, /* Tai Tham Hora */
4099 { 0x1a90, 0, 9, TRUE
/*win7*/ }, /* Tai Tham Tham */
4100 { 0x1b50, 0, 9 }, /* Balinese */
4101 { 0x1bb0, 0, 9 }, /* Sundanese */
4102 { 0x1c40, 0, 9 }, /* Lepcha */
4103 { 0x1c50, 0, 9 }, /* Ol Chiki */
4104 { 0x2070, 0, 0 }, /* Superscript 0 */
4105 { 0x2074, 4, 9 }, /* Superscript 4-9 */
4106 { 0x2080, 0, 9 }, /* Subscript */
4107 { 0x2460, 1, 9 }, /* Circled */
4108 { 0x2474, 1, 9 }, /* Bracketed */
4109 { 0x2488, 1, 9 }, /* Full stop */
4110 { 0x24ea, 0, 0 }, /* Circled 0 */
4111 { 0x24f5, 1, 9 }, /* Double Circled */
4112 { 0x24ff, 0, 0 }, /* Negative Circled 0 */
4113 { 0x2776, 1, 9 }, /* Inverted Circled */
4114 { 0x2780, 1, 9 }, /* Patterned Circled */
4115 { 0x278a, 1, 9 }, /* Inverted Patterned Circled */
4116 { 0x3007, 0, 0 }, /* Ideographic Number 0 */
4117 { 0x3021, 1, 9 }, /* Hangzhou */
4118 { 0xa620, 0, 9 }, /* Vai */
4119 { 0xa8d0, 0, 9 }, /* Saurashtra */
4120 { 0xa8e0, 0, 9, TRUE
/*win7*/ }, /* Combining Devanagari */
4121 { 0xa900, 0, 9 }, /* Kayah Li */
4122 { 0xa9d0, 0, 9, TRUE
/*win7*/ }, /* Javanese */
4123 { 0xa9f0, 0, 9, TRUE
/*win10*/ }, /* Myanmar Tai Laing */
4124 { 0xaa50, 0, 9 }, /* Cham */
4125 { 0xabf0, 0, 9, TRUE
/*win7*/ }, /* Meetei Mayek */
4126 { 0xff10, 0, 9 }, /* Full Width */
4127 { 0x10107, 1, 9 }, /* Aegean */
4128 { 0x10320, 1, 1 }, /* Old Italic Numeral 1 */
4129 { 0x10321, 5, 5 }, /* Old Italic Numeral 5 */
4130 { 0x104a0, 0, 9 }, /* Osmanya */
4131 { 0x10a40, 1, 4, TRUE
/*win10*/ }, /* Kharoshthi */
4132 { 0x10d30, 0, 9, TRUE
/*win10*/ }, /* Hanifi Rohingya */
4133 { 0x10e60, 1, 9, TRUE
/*win10*/ }, /* Rumi */
4134 { 0x11052, 1, 9, TRUE
/*win10*/ }, /* Brahmi Number */
4135 { 0x11066, 0, 9, TRUE
/*win10*/ }, /* Brahmi Digit */
4136 { 0x110f0, 0, 9, TRUE
/*win10*/ }, /* Sora Sompeng */
4137 { 0x11136, 0, 9, TRUE
/*win10*/ }, /* Chakma */
4138 { 0x111d0, 0, 9, TRUE
/*win10*/ }, /* Sharada */
4139 { 0x112f0, 0, 9, TRUE
/*win10*/ }, /* Khudawadi */
4140 { 0x11450, 0, 9, TRUE
/*win10*/ }, /* Newa */
4141 { 0x114d0, 0, 9, TRUE
/*win10*/ }, /* Tirhuta */
4142 { 0x11650, 0, 9, TRUE
/*win10*/ }, /* Modi */
4143 { 0x116c0, 0, 9, TRUE
/*win10*/ }, /* Takri */
4144 { 0x11730, 0, 9, TRUE
/*win10*/ }, /* Ahom */
4145 { 0x118e0, 0, 9, TRUE
/*win10*/ }, /* Warang */
4146 { 0x11950, 0, 9, TRUE
/*win10*/ }, /* Dives Akuru */
4147 { 0x11c50, 0, 9, TRUE
/*win10*/ }, /* Bhaiksuki */
4148 { 0x11d50, 0, 9, TRUE
/*win10*/ }, /* Masaram Gondi */
4149 { 0x11da0, 0, 9, TRUE
/*win10*/ }, /* Gunjala Gondi */
4150 { 0x11f50, 0, 9, TRUE
/*win10*/ }, /* Kawi */
4151 { 0x16a60, 0, 9, TRUE
/*win10*/ }, /* Mro */
4152 { 0x16ac0, 0, 9, TRUE
/*win10*/ }, /* Tangsa */
4153 { 0x16b50, 0, 9, TRUE
/*win10*/ }, /* Pahawh Hmong */
4154 { 0x1d7ce, 0, 9 }, /* Mathematical Bold */
4155 { 0x1d7d8, 0, 9 }, /* Mathematical Double Struck */
4156 { 0x1d7e2, 0, 9 }, /* Mathematical Sans Serif */
4157 { 0x1d7ec, 0, 9 }, /* Mathematical Sans Serif Bold */
4158 { 0x1d7f6, 0, 9 }, /* Mathematical Monospace */
4159 { 0x1e140, 0, 9, TRUE
/*win10*/ }, /* Nyiakeng Puachue Hmong */
4160 { 0x1e2f0, 0, 9, TRUE
/*win10*/ }, /* Wancho */
4161 { 0x1e4f0, 0, 9, TRUE
/*win10*/ }, /* Nag Mundari */
4162 { 0x1e950, 0, 9, TRUE
/*win10*/ }, /* Adlam */
4163 { 0x1f100, 0, 0, TRUE
/*win10*/ }, /* Full Stop */
4164 { 0x1f101, 0, 9, TRUE
/*win10*/ }, /* Comma */
4165 { 0x1fbf0, 0, 9, TRUE
/*win10*/ }, /* Segmented */
4166 { 0x10ffff } /* Terminator */
4168 static const WCHAR foldczone_src
[] =
4170 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
4171 0xff37, 0xff49, 0xff4e, 0xff45, 0x3c5, 0x308, 0x6a, 0x30c, 0xa0, 0xaa, 0
4173 static const WCHAR foldczone_dst
[] =
4175 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x3cb,0x1f0,' ','a',0
4177 static const WCHAR foldczone_broken_dst
[] =
4179 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e',0x03c5,0x0308,'j',0x030c,0x00a0,0x00aa,0
4181 static const WCHAR ligatures_src
[] =
4183 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
4184 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
4185 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
4186 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
4187 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
4188 0xfb04, 0xfb05, 0xfb06, '\0'
4190 static const WCHAR ligatures_dst
[] =
4192 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
4193 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
4194 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
4195 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
4196 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
4197 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
4200 /* Invalid flag combinations */
4201 for (i
= 0; i
< ARRAY_SIZE(badFlags
); i
++)
4203 src
[0] = dst
[0] = '\0';
4204 SetLastError(0xdeadbeef);
4205 ret
= FoldStringW(badFlags
[i
], src
, 256, dst
, 256);
4206 ok(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
,
4207 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
4210 /* src & dst cannot be the same */
4211 SetLastError(0xdeadbeef);
4212 ret
= FoldStringW(MAP_FOLDCZONE
, src
, -1, src
, 256);
4213 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4214 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4216 /* src can't be NULL */
4217 SetLastError(0xdeadbeef);
4218 ret
= FoldStringW(MAP_FOLDCZONE
, NULL
, -1, dst
, 256);
4219 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4220 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4222 /* srclen can't be 0 */
4223 SetLastError(0xdeadbeef);
4224 ret
= FoldStringW(MAP_FOLDCZONE
, src
, 0, dst
, 256);
4225 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4226 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4228 /* dstlen can't be < 0 */
4229 SetLastError(0xdeadbeef);
4230 ret
= FoldStringW(MAP_FOLDCZONE
, src
, -1, dst
, -1);
4231 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4232 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4234 /* Ret includes terminating NUL which is appended if srclen = -1 */
4235 SetLastError(0xdeadbeef);
4239 ret
= FoldStringW(MAP_FOLDCZONE
, src
, -1, dst
, 256);
4240 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
4241 ok(dst
[0] == 'A' && dst
[1] == '\0',
4242 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
4243 'A', '\0', ret
, dst
[0], dst
[1], GetLastError());
4245 /* If size is given, result is not NUL terminated */
4246 SetLastError(0xdeadbeef);
4251 ret
= FoldStringW(MAP_FOLDCZONE
, src
, 1, dst
, 256);
4252 ok(ret
== 1, "Expected ret == 1, got %d, error %ld\n", ret
, GetLastError());
4253 ok(dst
[0] == 'A' && dst
[1] == 'X',
4254 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
4255 'A','X', ret
, dst
[0], dst
[1], GetLastError());
4257 /* MAP_FOLDDIGITS */
4258 for (j
= 0; j
< ARRAY_SIZE(digitRanges
); j
++)
4260 /* Check everything before this range */
4261 for (ch
= prev_ch
; ch
< digitRanges
[j
].ch
; ch
++)
4263 len
= put_utf16( src
, ch
);
4265 SetLastError(0xdeadbeef);
4266 ret
= FoldStringW(MAP_FOLDDIGITS
, src
, -1, dst
, 256);
4269 ok( !wcscmp( src
, dst
), "%s changed to %s\n", debugstr_w(src
), debugstr_w(dst
) );
4272 ok(ret
== 2, "Expected ret == 2, got %d, error %ld\n", ret
, GetLastError());
4273 ok(dst
[0] == ch
, "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch
, dst
[0]);
4277 GetStringTypeW( CT_CTYPE1
, &wch
, 1, &type
);
4278 ok(!(type
& C1_DIGIT
), "char %04x should not be a digit\n", wch
);
4281 if (digitRanges
[j
].ch
== 0x10ffff)
4282 break; /* Finished the whole code point space */
4284 for (ch
= digitRanges
[j
].ch
; ch
<= digitRanges
[j
].ch
+ digitRanges
[j
].last
- digitRanges
[j
].first
; ch
++)
4286 UINT exp
= '0' + digitRanges
[j
].first
+ ch
- digitRanges
[j
].ch
;
4288 SetLastError(0xdeadbeef);
4289 len
= put_utf16( src
, ch
);
4291 ret
= FoldStringW(MAP_FOLDDIGITS
, src
, -1, dst
, 256);
4292 ok(ret
== 2 || broken( digitRanges
[j
].broken
&& ch
>= 0x10000 ),
4293 "%04x: Expected ret == 2, got %d, error %ld\n", ch
, ret
, GetLastError());
4294 ok((dst
[0] == exp
&& dst
[1] == '\0') || broken( digitRanges
[j
].broken
),
4295 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n", ch
, exp
, dst
[0]);
4301 SetLastError(0xdeadbeef);
4302 ret
= FoldStringW(MAP_FOLDCZONE
, foldczone_src
, -1, dst
, 256);
4303 ok(ret
== ARRAY_SIZE(foldczone_dst
)
4304 || broken(ret
== ARRAY_SIZE(foldczone_broken_dst
)), /* winxp, win2003 */
4305 "Got %d, error %ld.\n", ret
, GetLastError());
4306 ok(!memcmp(dst
, foldczone_dst
, sizeof(foldczone_dst
))
4307 || broken(!memcmp(dst
, foldczone_broken_dst
, sizeof(foldczone_broken_dst
))), /* winxp, win2003 */
4308 "Got unexpected string %s.\n", wine_dbgstr_w(dst
));
4310 /* MAP_EXPAND_LIGATURES */
4311 SetLastError(0xdeadbeef);
4312 ret
= FoldStringW(MAP_EXPAND_LIGATURES
, ligatures_src
, -1, dst
, 256);
4313 ok(ret
== ARRAY_SIZE(ligatures_dst
), "Got %d, error %ld\n", ret
, GetLastError());
4314 ok(!memcmp(dst
, ligatures_dst
, sizeof(ligatures_dst
)),
4315 "Got unexpected string %s.\n", wine_dbgstr_w(dst
));
4317 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
4322 #define LCID_OK(l) \
4323 ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
4324 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
4325 #define LCID_RES(src, res) do { lcid = ConvertDefaultLocale(src); LCID_OK(res); } while (0)
4326 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
4327 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
4329 static void test_ConvertDefaultLocale(void)
4331 /* some languages use a different default than SUBLANG_DEFAULT */
4332 static const struct { WORD lang
, sublang
; } nondefault_langs
[] =
4334 { LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
},
4335 { LANG_SPANISH
, SUBLANG_SPANISH_MODERN
},
4336 { LANG_IRISH
, SUBLANG_IRISH_IRELAND
},
4337 { LANG_BENGALI
, SUBLANG_BENGALI_BANGLADESH
},
4338 { LANG_SINDHI
, SUBLANG_SINDHI_AFGHANISTAN
},
4339 { LANG_INUKTITUT
, SUBLANG_INUKTITUT_CANADA_LATIN
},
4340 { LANG_TAMAZIGHT
, SUBLANG_TAMAZIGHT_ALGERIA_LATIN
},
4341 { LANG_FULAH
, SUBLANG_FULAH_SENEGAL
},
4342 { LANG_TIGRINYA
, SUBLANG_TIGRINYA_ERITREA
}
4347 /* Doesn't change lcid, even if non default sublang/sort used */
4348 TEST_LCID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
, SORT_DEFAULT
);
4349 TEST_LCID(LANG_ENGLISH
, SUBLANG_ENGLISH_UK
, SORT_DEFAULT
);
4350 TEST_LCID(LANG_JAPANESE
, SUBLANG_DEFAULT
, SORT_DEFAULT
);
4351 TEST_LCID(LANG_JAPANESE
, SUBLANG_DEFAULT
, SORT_JAPANESE_UNICODE
);
4352 lcid
= ConvertDefaultLocale( MKLCID( LANG_JAPANESE
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
));
4353 ok( lcid
== MKLCID( LANG_JAPANESE
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
) ||
4354 broken( lcid
== MKLCID( LANG_JAPANESE
, SUBLANG_DEFAULT
, SORT_JAPANESE_UNICODE
)), /* <= vista */
4355 "Expected lcid = %08lx got %08lx\n",
4356 MKLCID( LANG_JAPANESE
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
), lcid
);
4357 lcid
= ConvertDefaultLocale( MKLCID( LANG_IRISH
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
));
4358 ok( lcid
== MKLCID( LANG_IRISH
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
) ||
4359 broken( lcid
== MKLCID( LANG_IRISH
, SUBLANG_DEFAULT
, SORT_JAPANESE_UNICODE
)), /* <= vista */
4360 "Expected lcid = %08lx got %08lx\n",
4361 MKLCID( LANG_IRISH
, SUBLANG_NEUTRAL
, SORT_JAPANESE_UNICODE
), lcid
);
4363 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
4364 LCID_RES(MKLCID(LANG_ENGLISH
, SUBLANG_NEUTRAL
, SORT_DEFAULT
),
4365 MKLCID(LANG_ENGLISH
, SUBLANG_DEFAULT
, SORT_DEFAULT
));
4366 LCID_RES(MKLCID(LANG_JAPANESE
, SUBLANG_NEUTRAL
, SORT_DEFAULT
),
4367 MKLCID(LANG_JAPANESE
, SUBLANG_DEFAULT
, SORT_DEFAULT
));
4368 for (i
= 0; i
< ARRAY_SIZE(nondefault_langs
); i
++)
4370 lcid
= ConvertDefaultLocale( MAKELANGID( nondefault_langs
[i
].lang
, SUBLANG_NEUTRAL
));
4371 ok( lcid
== MAKELANGID( nondefault_langs
[i
].lang
, nondefault_langs
[i
].sublang
) ||
4372 broken( lcid
== MAKELANGID( nondefault_langs
[i
].lang
, SUBLANG_DEFAULT
)) || /* <= vista */
4373 broken( lcid
== MAKELANGID( nondefault_langs
[i
].lang
, SUBLANG_NEUTRAL
)), /* w7 */
4374 "Expected lcid = %08x got %08lx\n",
4375 MAKELANGID( nondefault_langs
[i
].lang
, nondefault_langs
[i
].sublang
), lcid
);
4377 lcid
= ConvertDefaultLocale( 0x7804 );
4378 ok( lcid
== MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
) ||
4379 broken( lcid
== 0x7804 ), /* <= vista */
4380 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_SIMPLIFIED
), lcid
);
4381 lcid
= ConvertDefaultLocale( 0x7c04 );
4382 ok( lcid
== MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
) ||
4383 broken( lcid
== 0x7c04 ) || /* winxp */
4384 broken( lcid
== 0x0404 ), /* vista */
4385 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
), lcid
);
4386 lcid
= ConvertDefaultLocale( LANG_SERBIAN_NEUTRAL
);
4387 ok( lcid
== MAKELANGID( LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_LATIN
) ||
4388 broken( lcid
== MAKELANGID( LANG_SERBIAN
, SUBLANG_SERBIAN_LATIN
) ), /* <= vista */
4389 "Expected lcid = %08x got %08lx\n", MAKELANGID( LANG_SERBIAN
, SUBLANG_SERBIAN_SERBIA_LATIN
), lcid
);
4391 /* Invariant language is not treated specially */
4392 TEST_LCID(LANG_INVARIANT
, SUBLANG_DEFAULT
, SORT_DEFAULT
);
4394 /* User/system default languages alone are not mapped */
4395 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT
, SORT_JAPANESE_UNICODE
);
4396 TEST_LCIDLANG(LANG_USER_DEFAULT
, SORT_JAPANESE_UNICODE
);
4399 LCID_RES(LOCALE_SYSTEM_DEFAULT
, GetSystemDefaultLCID());
4400 LCID_RES(LOCALE_USER_DEFAULT
, GetUserDefaultLCID());
4401 LCID_RES(LOCALE_NEUTRAL
, GetUserDefaultLCID());
4402 LCID_RES(LOCALE_CUSTOM_DEFAULT
, GetUserDefaultLCID());
4403 lcid
= ConvertDefaultLocale( LOCALE_CUSTOM_UNSPECIFIED
);
4404 ok( lcid
== GetUserDefaultLCID() || broken(lcid
== LOCALE_CUSTOM_UNSPECIFIED
), /* <= win8 */
4405 "wrong lcid %04lx\n", lcid
);
4406 lcid
= ConvertDefaultLocale( LOCALE_CUSTOM_UI_DEFAULT
);
4407 ok( lcid
== GetUserDefaultUILanguage() || lcid
== LOCALE_CUSTOM_UI_DEFAULT
, "wrong lcid %04lx\n", lcid
);
4408 lcid
= ConvertDefaultLocale(LOCALE_INVARIANT
);
4409 ok(lcid
== LOCALE_INVARIANT
|| broken(lcid
== 0x47f) /* win2k[3]/winxp */,
4410 "Expected lcid = %08lx, got %08lx\n", LOCALE_INVARIANT
, lcid
);
4413 static BOOL CALLBACK
langgrp_procA(LGRPID lgrpid
, LPSTR lpszNum
, LPSTR lpszName
,
4414 DWORD dwFlags
, LONG_PTR lParam
)
4416 if (winetest_debug
> 1)
4417 trace("%08lx, %s, %s, %08lx, %08Ix\n",
4418 lgrpid
, lpszNum
, lpszName
, dwFlags
, lParam
);
4420 ok(pIsValidLanguageGroup(lgrpid
, dwFlags
) == TRUE
,
4421 "Enumerated grp %ld not valid (flags %ld)\n", lgrpid
, dwFlags
);
4423 /* If lParam is one, we are calling with flags defaulted from 0 */
4424 ok(!lParam
|| (dwFlags
== LGRPID_INSTALLED
|| dwFlags
== LGRPID_SUPPORTED
),
4425 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags
);
4430 static void test_EnumSystemLanguageGroupsA(void)
4434 if (!pEnumSystemLanguageGroupsA
|| !pIsValidLanguageGroup
)
4436 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
4440 /* No enumeration proc */
4442 ret
= pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED
, 0);
4443 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4445 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
4448 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4449 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4453 pEnumSystemLanguageGroupsA(langgrp_procA
, LGRPID_INSTALLED
|LGRPID_SUPPORTED
, 0);
4454 ok(GetLastError() == ERROR_INVALID_FLAGS
, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
4456 /* No flags - defaults to LGRPID_INSTALLED */
4457 SetLastError(0xdeadbeef);
4458 pEnumSystemLanguageGroupsA(langgrp_procA
, 0, 1);
4459 ok(GetLastError() == 0xdeadbeef, "got error %ld\n", GetLastError());
4461 pEnumSystemLanguageGroupsA(langgrp_procA
, LGRPID_INSTALLED
, 0);
4462 pEnumSystemLanguageGroupsA(langgrp_procA
, LGRPID_SUPPORTED
, 0);
4465 static BOOL CALLBACK
enum_func( LPWSTR name
, DWORD flags
, LPARAM lparam
)
4467 if (winetest_debug
> 1)
4468 trace( "%s %lx\n", wine_dbgstr_w(name
), flags
);
4472 static void test_EnumSystemLocalesEx(void)
4476 if (!pEnumSystemLocalesEx
)
4478 win_skip( "EnumSystemLocalesEx not available\n" );
4481 SetLastError( 0xdeadbeef );
4482 ret
= pEnumSystemLocalesEx( enum_func
, LOCALE_ALL
, 0, (void *)1 );
4483 ok( !ret
, "should have failed\n" );
4484 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
4485 SetLastError( 0xdeadbeef );
4486 ret
= pEnumSystemLocalesEx( enum_func
, 0, 0, NULL
);
4487 ok( ret
, "failed err %lu\n", GetLastError() );
4490 static BOOL CALLBACK
lgrplocale_procA(LGRPID lgrpid
, LCID lcid
, LPSTR lpszNum
,
4493 if (winetest_debug
> 1)
4494 trace("%08lx, %08lx, %s, %08Ix\n", lgrpid
, lcid
, lpszNum
, lParam
);
4496 /* invalid locale enumerated on some platforms */
4500 ok(pIsValidLanguageGroup(lgrpid
, LGRPID_SUPPORTED
) == TRUE
,
4501 "Enumerated grp %ld not valid\n", lgrpid
);
4502 ok(IsValidLocale(lcid
, LCID_SUPPORTED
) == TRUE
,
4503 "Enumerated grp locale %04lx not valid\n", lcid
);
4507 static void test_EnumLanguageGroupLocalesA(void)
4511 if (!pEnumLanguageGroupLocalesA
|| !pIsValidLanguageGroup
)
4513 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
4517 /* No enumeration proc */
4519 ret
= pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE
, 0, 0);
4520 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4522 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
4525 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4526 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4528 /* lgrpid too small */
4530 ret
= pEnumLanguageGroupLocalesA(lgrplocale_procA
, 0, 0, 0);
4531 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4532 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4534 /* lgrpid too big */
4536 ret
= pEnumLanguageGroupLocalesA(lgrplocale_procA
, LGRPID_ARMENIAN
+ 1, 0, 0);
4537 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4538 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4540 /* dwFlags is reserved */
4542 ret
= pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE
, 0x1, 0);
4543 ok( !ret
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4544 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4546 pEnumLanguageGroupLocalesA(lgrplocale_procA
, LGRPID_WESTERN_EUROPE
, 0, 0);
4549 static void test_SetLocaleInfo(void)
4552 LCID lcid
= GetUserDefaultLCID();
4556 SetLastError(0xdeadbeef);
4557 bRet
= SetLocaleInfoA(lcid
, LOCALE_SSHORTDATE
, NULL
);
4558 ok( !bRet
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4559 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4561 SetLastError(0xdeadbeef);
4562 bRet
= SetLocaleInfoW(lcid
, LOCALE_SSHORTDATE
, NULL
);
4563 ok( !bRet
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4564 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4566 SetLastError(0xdeadbeef);
4567 bRet
= SetLocaleInfoW(lcid
, LOCALE_SDAYNAME1
, NULL
);
4568 ok( !bRet
&& GetLastError() == ERROR_INVALID_PARAMETER
,
4569 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4571 for (i
= 0; i
<= 0x1014; i
++)
4574 if (!GetLocaleInfoW( LOCALE_USER_DEFAULT
, i
, buffer
, ARRAY_SIZE(buffer
) )) continue;
4575 SetLastError(0xdeadbeef);
4576 bRet
= SetLocaleInfoW(lcid
, i
, buffer
);
4579 case LOCALE_ICALENDARTYPE
:
4580 case LOCALE_ICURRDIGITS
:
4581 case LOCALE_ICURRENCY
:
4582 case LOCALE_IDIGITS
:
4583 case LOCALE_IDIGITSUBSTITUTION
:
4584 case LOCALE_IFIRSTDAYOFWEEK
:
4585 case LOCALE_IFIRSTWEEKOFYEAR
:
4587 case LOCALE_IMEASURE
:
4588 case LOCALE_INEGCURR
:
4589 case LOCALE_INEGNUMBER
:
4590 case LOCALE_IPAPERSIZE
:
4594 case LOCALE_SCURRENCY
:
4596 case LOCALE_SDECIMAL
:
4597 case LOCALE_SGROUPING
:
4599 case LOCALE_SLONGDATE
:
4600 case LOCALE_SMONDECIMALSEP
:
4601 case LOCALE_SMONGROUPING
:
4602 case LOCALE_SMONTHOUSANDSEP
:
4603 case LOCALE_SNATIVEDIGITS
:
4604 case LOCALE_SNEGATIVESIGN
:
4605 case LOCALE_SPOSITIVESIGN
:
4606 case LOCALE_SSHORTDATE
:
4607 case LOCALE_SSHORTTIME
:
4608 case LOCALE_STHOUSAND
:
4610 case LOCALE_STIMEFORMAT
:
4611 case LOCALE_SYEARMONTH
:
4612 ok( bRet
, "%04x: failed err %lu\n", i
, GetLastError() );
4614 case LOCALE_SINTLSYMBOL
:
4615 ok( bRet
|| broken(!bRet
), /* win10 <= 1507 */
4616 "%04x: failed err %lu\n", i
, GetLastError() );
4619 ok( !bRet
, "%04x: succeeded\n", i
);
4620 ok( GetLastError() == ERROR_INVALID_FLAGS
, "%04x: wrong error %lu\n", i
, GetLastError() );
4626 static BOOL CALLBACK
luilocale_proc1A(LPSTR value
, LONG_PTR lParam
)
4628 if (winetest_debug
> 1)
4629 trace("%s %08Ix\n", value
, lParam
);
4633 static BOOL CALLBACK
luilocale_proc2A(LPSTR value
, LONG_PTR lParam
)
4635 ok(!enumCount
, "callback called again unexpected\n");
4640 static BOOL CALLBACK
luilocale_proc3A(LPSTR value
, LONG_PTR lParam
)
4642 ok(0,"callback called unexpected\n");
4646 static void test_EnumUILanguageA(void)
4649 if (!pEnumUILanguagesA
) {
4650 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
4654 SetLastError(ERROR_SUCCESS
);
4655 ret
= pEnumUILanguagesA(luilocale_proc1A
, 0, 0);
4656 if (ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4658 win_skip("EnumUILanguagesA is not implemented\n");
4661 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
4663 SetLastError(0xdeadbeef);
4664 ret
= pEnumUILanguagesA(luilocale_proc1A
, MUI_LANGUAGE_NAME
, 0);
4665 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
4668 SetLastError(ERROR_SUCCESS
);
4669 ret
= pEnumUILanguagesA(luilocale_proc2A
, 0, 0);
4670 ok(ret
, "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
4671 ok(enumCount
== 1, "enumCount = %u\n", enumCount
);
4674 SetLastError(ERROR_SUCCESS
);
4675 ret
= pEnumUILanguagesA(luilocale_proc2A
, MUI_LANGUAGE_ID
, 0);
4676 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
), /* winxp */
4677 "Expected ret != 0, got %d, error %ld\n", ret
, GetLastError());
4678 if (ret
) ok(enumCount
== 1, "enumCount = %u\n", enumCount
);
4680 SetLastError(ERROR_SUCCESS
);
4681 ret
= pEnumUILanguagesA(NULL
, 0, 0);
4682 ok(!ret
, "Expected return value FALSE, got %u\n", ret
);
4683 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4684 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4686 SetLastError(ERROR_SUCCESS
);
4687 ret
= pEnumUILanguagesA(luilocale_proc3A
, 0x5a5a5a5a, 0);
4688 ok(!ret
, "Expected return value FALSE, got %u\n", ret
);
4689 ok(GetLastError() == ERROR_INVALID_FLAGS
, "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
4691 SetLastError(ERROR_SUCCESS
);
4692 ret
= pEnumUILanguagesA(NULL
, 0x5a5a5a5a, 0);
4693 ok(!ret
, "Expected return value FALSE, got %u\n", ret
);
4694 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4695 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
4698 static char date_fmt_buf
[1024];
4699 static WCHAR date_fmt_bufW
[1024];
4701 static BOOL CALLBACK
enum_datetime_procA(LPSTR fmt
)
4703 lstrcatA(date_fmt_buf
, fmt
);
4704 lstrcatA(date_fmt_buf
, "\n");
4708 static BOOL CALLBACK
enum_datetime_procW(WCHAR
*fmt
)
4710 lstrcatW(date_fmt_bufW
, fmt
);
4714 static void test_EnumDateFormatsA(void)
4718 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
4720 date_fmt_buf
[0] = 0;
4721 SetLastError(0xdeadbeef);
4722 ret
= EnumDateFormatsA(enum_datetime_procA
, lcid
, 0);
4723 if (!ret
&& (GetLastError() == ERROR_INVALID_FLAGS
))
4725 win_skip("0 for dwFlags is not supported\n");
4729 ok(ret
, "EnumDateFormatsA(0) error %ld\n", GetLastError());
4730 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf
);
4731 /* test the 1st enumerated format */
4732 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4733 ret
= GetLocaleInfoA(lcid
, LOCALE_SSHORTDATE
, buf
, sizeof(buf
));
4734 ok(ret
, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
4735 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4738 date_fmt_buf
[0] = 0;
4739 SetLastError(0xdeadbeef);
4740 ret
= EnumDateFormatsA(enum_datetime_procA
, lcid
, LOCALE_USE_CP_ACP
);
4741 if (!ret
&& (GetLastError() == ERROR_INVALID_FLAGS
))
4743 win_skip("LOCALE_USE_CP_ACP is not supported\n");
4747 ok(ret
, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
4748 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf
);
4749 /* test the 1st enumerated format */
4750 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4751 ret
= GetLocaleInfoA(lcid
, LOCALE_SSHORTDATE
, buf
, sizeof(buf
));
4752 ok(ret
, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
4753 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4756 date_fmt_buf
[0] = 0;
4757 ret
= EnumDateFormatsA(enum_datetime_procA
, lcid
, DATE_SHORTDATE
);
4758 ok(ret
, "EnumDateFormatsA(DATE_SHORTDATE) error %ld\n", GetLastError());
4759 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf
);
4760 /* test the 1st enumerated format */
4761 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4762 ret
= GetLocaleInfoA(lcid
, LOCALE_SSHORTDATE
, buf
, sizeof(buf
));
4763 ok(ret
, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %ld\n", GetLastError());
4764 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4766 date_fmt_buf
[0] = 0;
4767 ret
= EnumDateFormatsA(enum_datetime_procA
, lcid
, DATE_LONGDATE
);
4768 ok(ret
, "EnumDateFormatsA(DATE_LONGDATE) error %ld\n", GetLastError());
4769 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf
);
4770 /* test the 1st enumerated format */
4771 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4772 ret
= GetLocaleInfoA(lcid
, LOCALE_SLONGDATE
, buf
, sizeof(buf
));
4773 ok(ret
, "GetLocaleInfoA(LOCALE_SLONGDATE) error %ld\n", GetLastError());
4774 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4776 date_fmt_buf
[0] = 0;
4777 SetLastError(0xdeadbeef);
4778 ret
= EnumDateFormatsA(enum_datetime_procA
, lcid
, DATE_YEARMONTH
);
4779 if (!ret
&& (GetLastError() == ERROR_INVALID_FLAGS
))
4781 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
4784 ok(ret
, "EnumDateFormatsA(DATE_YEARMONTH) error %ld\n", GetLastError());
4785 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf
);
4786 /* test the 1st enumerated format */
4787 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4788 ret
= GetLocaleInfoA(lcid
, LOCALE_SYEARMONTH
, buf
, sizeof(buf
));
4789 ok(ret
, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %ld\n", GetLastError());
4790 ok(!lstrcmpA(date_fmt_buf
, buf
) || broken(!buf
[0]) /* win9x */,
4791 "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4794 static void test_EnumTimeFormatsA(void)
4798 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
4800 date_fmt_buf
[0] = 0;
4801 ret
= EnumTimeFormatsA(enum_datetime_procA
, lcid
, 0);
4802 ok(ret
, "EnumTimeFormatsA(0) error %ld\n", GetLastError());
4803 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf
);
4804 /* test the 1st enumerated format */
4805 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4806 ret
= GetLocaleInfoA(lcid
, LOCALE_STIMEFORMAT
, buf
, sizeof(buf
));
4807 ok(ret
, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
4808 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4810 date_fmt_buf
[0] = 0;
4811 ret
= EnumTimeFormatsA(enum_datetime_procA
, lcid
, LOCALE_USE_CP_ACP
);
4812 ok(ret
, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
4813 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf
);
4814 /* test the 1st enumerated format */
4815 if ((p
= strchr(date_fmt_buf
, '\n'))) *p
= 0;
4816 ret
= GetLocaleInfoA(lcid
, LOCALE_STIMEFORMAT
, buf
, sizeof(buf
));
4817 ok(ret
, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
4818 ok(!lstrcmpA(date_fmt_buf
, buf
), "expected \"%s\" got \"%s\"\n", date_fmt_buf
, buf
);
4821 static void test_EnumTimeFormatsW(void)
4823 LCID lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
4827 date_fmt_bufW
[0] = 0;
4828 ret
= EnumTimeFormatsW(enum_datetime_procW
, lcid
, 0);
4829 ok(ret
, "EnumTimeFormatsW(0) error %ld\n", GetLastError());
4830 ret
= GetLocaleInfoW(lcid
, LOCALE_STIMEFORMAT
, bufW
, ARRAY_SIZE(bufW
));
4831 ok(ret
, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
4832 ok(!lstrcmpW(date_fmt_bufW
, bufW
), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW
),
4833 wine_dbgstr_w(bufW
));
4835 date_fmt_bufW
[0] = 0;
4836 ret
= EnumTimeFormatsW(enum_datetime_procW
, lcid
, LOCALE_USE_CP_ACP
);
4837 ok(ret
, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %ld\n", GetLastError());
4838 ret
= GetLocaleInfoW(lcid
, LOCALE_STIMEFORMAT
, bufW
, ARRAY_SIZE(bufW
));
4839 ok(ret
, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %ld\n", GetLastError());
4840 ok(!lstrcmpW(date_fmt_bufW
, bufW
), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW
),
4841 wine_dbgstr_w(bufW
));
4843 /* TIME_NOSECONDS is Win7+ feature */
4844 date_fmt_bufW
[0] = 0;
4845 ret
= EnumTimeFormatsW(enum_datetime_procW
, lcid
, TIME_NOSECONDS
);
4846 if (!ret
&& GetLastError() == ERROR_INVALID_FLAGS
)
4847 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
4851 ok(ret
, "EnumTimeFormatsW(TIME_NOSECONDS) error %ld\n", GetLastError());
4852 ret
= GetLocaleInfoW(lcid
, LOCALE_SSHORTTIME
, bufW
, ARRAY_SIZE(bufW
));
4853 ok(ret
, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %ld\n", GetLastError());
4854 ok(!lstrcmpW(date_fmt_bufW
, bufW
), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW
),
4855 wine_dbgstr_w(bufW
));
4857 /* EnumTimeFormatsA doesn't support this flag */
4858 ret
= EnumTimeFormatsA(enum_datetime_procA
, lcid
, TIME_NOSECONDS
);
4859 ok(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret
,
4862 ret
= EnumTimeFormatsA(NULL
, lcid
, TIME_NOSECONDS
);
4863 ok(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %ld\n", ret
,
4866 /* And it's not supported by GetLocaleInfoA either */
4867 ret
= GetLocaleInfoA(lcid
, LOCALE_SSHORTTIME
, buf
, ARRAY_SIZE(buf
));
4868 ok(!ret
&& GetLastError() == ERROR_INVALID_FLAGS
, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %ld\n", ret
,
4873 static void test_GetCPInfo(void)
4879 SetLastError(0xdeadbeef);
4880 ret
= GetCPInfo(CP_SYMBOL
, &cpinfo
);
4881 ok(!ret
, "GetCPInfo(CP_SYMBOL) should fail\n");
4882 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4883 "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError());
4885 memset(cpinfo
.LeadByte
, '-', ARRAY_SIZE(cpinfo
.LeadByte
));
4886 SetLastError(0xdeadbeef);
4887 ret
= GetCPInfo(CP_UTF7
, &cpinfo
);
4888 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
4890 win_skip("Codepage CP_UTF7 is not installed/available\n");
4896 ok(ret
, "GetCPInfo(CP_UTF7) error %lu\n", GetLastError());
4897 ok(cpinfo
.DefaultChar
[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo
.DefaultChar
[0]);
4898 ok(cpinfo
.DefaultChar
[1] == 0, "expected 0, got 0x%x\n", cpinfo
.DefaultChar
[1]);
4899 for (i
= 0; i
< sizeof(cpinfo
.LeadByte
); i
++)
4900 ok(!cpinfo
.LeadByte
[i
], "expected NUL byte in index %u\n", i
);
4901 ok(cpinfo
.MaxCharSize
== 5, "expected 5, got 0x%x\n", cpinfo
.MaxCharSize
);
4903 memset( &cpiw
, 0xcc, sizeof(cpiw
) );
4904 ret
= GetCPInfoExW( CP_UTF7
, 0, &cpiw
);
4905 ok( ret
, "GetCPInfoExW failed err %lu\n", GetLastError() );
4906 ok( cpiw
.DefaultChar
[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw
.DefaultChar
[0] );
4907 ok( cpiw
.DefaultChar
[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw
.DefaultChar
[1] );
4908 for (i
= 0; i
< 12; i
++) ok( cpiw
.LeadByte
[i
] == 0, "wrong LeadByte[%u] %02x\n", i
, cpiw
.LeadByte
[i
] );
4909 ok( cpiw
.MaxCharSize
== 5, "wrong MaxCharSize %02x\n", cpiw
.MaxCharSize
);
4910 ok( cpiw
.CodePage
== CP_UTF7
, "wrong CodePage %02x\n", cpiw
.CodePage
);
4911 ok( cpiw
.UnicodeDefaultChar
== 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw
.UnicodeDefaultChar
);
4912 ok( !wcscmp( cpiw
.CodePageName
, L
"65000 (UTF-7)" ),
4913 "wrong CodePageName %s\n", debugstr_w(cpiw
.CodePageName
) );
4916 memset(cpinfo
.LeadByte
, '-', ARRAY_SIZE(cpinfo
.LeadByte
));
4917 SetLastError(0xdeadbeef);
4918 ret
= GetCPInfo(CP_UTF8
, &cpinfo
);
4919 if (!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
)
4921 win_skip("Codepage CP_UTF8 is not installed/available\n");
4927 ok(ret
, "GetCPInfo(CP_UTF8) error %lu\n", GetLastError());
4928 ok(cpinfo
.DefaultChar
[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo
.DefaultChar
[0]);
4929 ok(cpinfo
.DefaultChar
[1] == 0, "expected 0, got 0x%x\n", cpinfo
.DefaultChar
[1]);
4930 for (i
= 0; i
< sizeof(cpinfo
.LeadByte
); i
++)
4931 ok(!cpinfo
.LeadByte
[i
], "expected NUL byte in index %u\n", i
);
4932 ok(cpinfo
.MaxCharSize
== 4, "expected 4, got %u\n", cpinfo
.MaxCharSize
);
4934 memset( &cpiw
, 0xcc, sizeof(cpiw
) );
4935 ret
= GetCPInfoExW( CP_UTF8
, 0, &cpiw
);
4936 ok( ret
, "GetCPInfoExW failed err %lu\n", GetLastError() );
4937 ok( cpiw
.DefaultChar
[0] == 0x3f, "wrong DefaultChar[0] %02x\n", cpiw
.DefaultChar
[0] );
4938 ok( cpiw
.DefaultChar
[1] == 0, "wrong DefaultChar[1] %02x\n", cpiw
.DefaultChar
[1] );
4939 for (i
= 0; i
< 12; i
++) ok( cpiw
.LeadByte
[i
] == 0, "wrong LeadByte[%u] %02x\n", i
, cpiw
.LeadByte
[i
] );
4940 ok( cpiw
.MaxCharSize
== 4, "wrong MaxCharSize %02x\n", cpiw
.MaxCharSize
);
4941 ok( cpiw
.CodePage
== CP_UTF8
, "wrong CodePage %02x\n", cpiw
.CodePage
);
4942 ok( cpiw
.UnicodeDefaultChar
== 0xfffd, "wrong UnicodeDefaultChar %02x\n", cpiw
.UnicodeDefaultChar
);
4943 ok( !wcscmp( cpiw
.CodePageName
, L
"65001 (UTF-8)" ),
4944 "wrong CodePageName %s\n", debugstr_w(cpiw
.CodePageName
) );
4948 SetLastError( 0xdeadbeef );
4949 ret
= GetCPInfoExW( 0xbeef, 0, &cpiw
);
4950 ok( !ret
, "GetCPInfoExW succeeeded\n" );
4951 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
4953 if (pNtGetNlsSectionPtr
)
4961 for (i
= 0; i
< 100; i
++)
4965 status
= pNtGetNlsSectionPtr( i
, 9999, NULL
, &ptr
, &size
);
4968 case 9: /* sortkeys */
4969 case 13: /* unknown */
4970 ok( status
== STATUS_INVALID_PARAMETER_1
|| status
== STATUS_INVALID_PARAMETER_3
, /* vista */
4971 "%u: failed %lx\n", i
, status
);
4973 case 10: /* casemap */
4974 ok( status
== STATUS_INVALID_PARAMETER_1
|| status
== STATUS_UNSUCCESSFUL
,
4975 "%u: failed %lx\n", i
, status
);
4977 case 11: /* codepage */
4978 case 12: /* normalization */
4979 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "%u: failed %lx\n", i
, status
);
4981 case 14: /* unknown */
4982 ok( status
== STATUS_INVALID_PARAMETER_1
||
4983 status
== STATUS_SUCCESS
, /* win11 */
4984 "%u: failed %lx\n", i
, status
);
4987 ok( status
== STATUS_INVALID_PARAMETER_1
, "%u: failed %lx\n", i
, status
);
4994 status
= pNtGetNlsSectionPtr( 10, 0, NULL
, &ptr
, &size
);
4995 if (status
!= STATUS_INVALID_PARAMETER_1
)
4997 ok( !status
, "failed %lx\n", status
);
4998 ok( size
> 0x1000 && size
<= 0x8000 , "wrong size %Ix\n", size
);
4999 status
= pNtGetNlsSectionPtr( 10, 0, NULL
, &ptr2
, &size
);
5000 ok( !status
, "failed %lx\n", status
);
5001 ok( ptr
!= ptr2
, "got same pointer\n" );
5002 ret
= UnmapViewOfFile( ptr
);
5003 ok( ret
, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5004 ret
= UnmapViewOfFile( ptr2
);
5005 ok( ret
, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5008 /* codepage tables */
5010 ptr
= (void *)0xdeadbeef;
5012 status
= pNtGetNlsSectionPtr( 11, 437, NULL
, &ptr
, &size
);
5013 ok( !status
, "failed %lx\n", status
);
5014 ok( size
> 0x10000 && size
<= 0x20000, "wrong size %Ix\n", size
);
5015 memset( &table
, 0xcc, sizeof(table
) );
5016 if (pRtlInitCodePageTable
)
5018 pRtlInitCodePageTable( ptr
, &table
);
5019 ok( table
.CodePage
== 437, "wrong codepage %u\n", table
.CodePage
);
5020 ok( table
.MaximumCharacterSize
== 1, "wrong char size %u\n", table
.MaximumCharacterSize
);
5021 ok( table
.DefaultChar
== '?', "wrong default char %x\n", table
.DefaultChar
);
5022 ok( !table
.DBCSCodePage
, "wrong dbcs %u\n", table
.DBCSCodePage
);
5024 ret
= UnmapViewOfFile( ptr
);
5025 ok( ret
, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5027 status
= pNtGetNlsSectionPtr( 11, 936, NULL
, &ptr
, &size
);
5028 ok( !status
, "failed %lx\n", status
);
5029 ok( size
> 0x30000 && size
<= 0x40000, "wrong size %Ix\n", size
);
5030 memset( &table
, 0xcc, sizeof(table
) );
5031 if (pRtlInitCodePageTable
)
5033 pRtlInitCodePageTable( ptr
, &table
);
5034 ok( table
.CodePage
== 936, "wrong codepage %u\n", table
.CodePage
);
5035 ok( table
.MaximumCharacterSize
== 2, "wrong char size %u\n", table
.MaximumCharacterSize
);
5036 ok( table
.DefaultChar
== '?', "wrong default char %x\n", table
.DefaultChar
);
5037 ok( table
.DBCSCodePage
== TRUE
, "wrong dbcs %u\n", table
.DBCSCodePage
);
5039 if (pRtlCustomCPToUnicodeN
)
5041 static const unsigned char buf
[] = { 0xbf, 0xb4, 0xc7, 0, 0x78 };
5042 static const WCHAR expect
[][4] = { { 0xcccc, 0xcccc, 0xcccc, 0xcccc },
5043 { 0x0000, 0xcccc, 0xcccc, 0xcccc },
5044 { 0x770b, 0xcccc, 0xcccc, 0xcccc },
5045 { 0x770b, 0x0000, 0xcccc, 0xcccc },
5046 { 0x770b, 0x003f, 0xcccc, 0xcccc },
5047 { 0x770b, 0x003f, 0x0078, 0xcccc } };
5051 for (i
= 0; i
<= sizeof(buf
); i
++)
5053 memset( wbuf
, 0xcc, sizeof(wbuf
) );
5054 pRtlCustomCPToUnicodeN( &table
, wbuf
, sizeof(wbuf
), &reslen
, (char *)buf
, i
);
5055 for (j
= 0; j
< 4; j
++) if (expect
[i
][j
] == 0xcccc) break;
5056 ok( reslen
== j
* sizeof(WCHAR
), "%lu: wrong len %lu\n", i
, reslen
);
5057 for (j
= 0; j
< 4; j
++)
5058 ok( wbuf
[j
] == expect
[i
][j
], "%lu: char %lu got %04x\n", i
, j
, wbuf
[j
] );
5062 ret
= UnmapViewOfFile( ptr
);
5063 ok( ret
, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5065 status
= pNtGetNlsSectionPtr( 11, 65001, NULL
, &ptr
, &size
);
5066 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
|| broken(!status
), /* win10 1709 */
5067 "failed %lx\n", status
);
5068 if (!status
) UnmapViewOfFile( ptr
);
5069 if (pRtlInitCodePageTable
)
5071 static USHORT utf8
[20] = { 0, CP_UTF8
};
5073 memset( &table
, 0xcc, sizeof(table
) );
5074 pRtlInitCodePageTable( utf8
, &table
);
5075 ok( table
.CodePage
== CP_UTF8
, "wrong codepage %u\n", table
.CodePage
);
5076 if (table
.MaximumCharacterSize
)
5078 ok( table
.MaximumCharacterSize
== 4, "wrong char size %u\n", table
.MaximumCharacterSize
);
5079 ok( table
.DefaultChar
== '?', "wrong default char %x\n", table
.DefaultChar
);
5080 ok( table
.UniDefaultChar
== 0xfffd, "wrong default char %x\n", table
.UniDefaultChar
);
5081 ok( table
.TransDefaultChar
== '?', "wrong default char %x\n", table
.TransDefaultChar
);
5082 ok( table
.TransUniDefaultChar
== '?', "wrong default char %x\n", table
.TransUniDefaultChar
);
5083 ok( !table
.DBCSCodePage
, "wrong dbcs %u\n", table
.DBCSCodePage
);
5084 ok( !table
.MultiByteTable
, "wrong mbtable %p\n", table
.MultiByteTable
);
5085 ok( !table
.WideCharTable
, "wrong wctable %p\n", table
.WideCharTable
);
5086 ok( !table
.DBCSRanges
, "wrong ranges %p\n", table
.DBCSRanges
);
5087 ok( !table
.DBCSOffsets
, "wrong offsets %p\n", table
.DBCSOffsets
);
5089 else win_skip( "utf-8 codepage not supported\n" );
5092 /* normalization tables */
5094 for (i
= 0; i
< 100; i
++)
5096 status
= pNtGetNlsSectionPtr( 12, i
, NULL
, &ptr
, &size
);
5099 case NormalizationC
:
5100 case NormalizationD
:
5101 case NormalizationKC
:
5102 case NormalizationKD
:
5104 ok( !status
, "%u: failed %lx\n", i
, status
);
5106 ok( size
> 0x8000 && size
<= 0x30000 , "wrong size %Ix\n", size
);
5107 ret
= UnmapViewOfFile( ptr
);
5108 ok( ret
, "UnmapViewOfFile failed err %lu\n", GetLastError() );
5111 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "%u: failed %lx\n", i
, status
);
5116 else win_skip( "NtGetNlsSectionPtr not supported\n" );
5120 * The CT_TYPE1 has varied over windows version.
5121 * The current target for correct behavior is windows 7.
5122 * There was a big shift between windows 2000 (first introduced) and windows Xp
5123 * Most of the old values below are from windows 2000.
5124 * A smaller subset of changes happened between windows Xp and Window vista/7
5126 static void test_GetStringTypeW(void)
5128 static const WCHAR blanks
[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
5129 static const WORD blanks_new
[] = {C1_SPACE
| C1_CNTRL
| C1_BLANK
| C1_DEFINED
,
5130 C1_SPACE
| C1_BLANK
| C1_DEFINED
,
5131 C1_SPACE
| C1_BLANK
| C1_DEFINED
,
5132 C1_SPACE
| C1_BLANK
| C1_DEFINED
,
5133 C1_CNTRL
| C1_BLANK
| C1_DEFINED
};
5134 static const WORD blanks_old
[] ={C1_SPACE
| C1_CNTRL
| C1_BLANK
,
5135 C1_SPACE
| C1_BLANK
,
5136 C1_SPACE
| C1_BLANK
,
5137 C1_SPACE
| C1_BLANK
,
5138 C1_SPACE
| C1_BLANK
};
5140 static const WCHAR undefined
[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
5143 static const WCHAR alpha
[] = {0x47, 0x67, 0x1c5};
5144 static const WORD alpha_old
[] = {C1_UPPER
| C1_ALPHA
,
5145 C1_LOWER
| C1_ALPHA
,
5146 C1_UPPER
| C1_LOWER
| C1_ALPHA
,
5149 /* Sk, Sk, Mn, So, Me */
5150 static const WCHAR oldpunc
[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
5152 0xffe0, 0xffe9, 0x2153};
5154 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
5155 static const WCHAR changed
[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
5156 static const WORD changed_old
[] = { C1_PUNCT
, C1_PUNCT
, 0, C1_PUNCT
, C1_UPPER
| C1_ALPHA
, C1_ALPHA
, C1_PUNCT
};
5157 static const WORD changed_xp
[] = {C1_ALPHA
| C1_DEFINED
,
5158 C1_ALPHA
| C1_DEFINED
,
5159 C1_CNTRL
| C1_DEFINED
,
5160 C1_PUNCT
| C1_DEFINED
,
5161 C1_UPPER
| C1_LOWER
| C1_ALPHA
| C1_DEFINED
,
5162 C1_ALPHA
| C1_LOWER
| C1_DEFINED
,
5163 C1_ALPHA
| C1_DEFINED
};
5164 static const WORD changed_new
[] = { C1_ALPHA
| C1_DEFINED
,
5165 C1_ALPHA
| C1_DEFINED
,
5166 C1_CNTRL
| C1_DEFINED
,
5167 C1_PUNCT
| C1_CNTRL
| C1_DEFINED
,
5168 C1_UPPER
| C1_LOWER
| C1_ALPHA
| C1_DEFINED
,
5169 C1_ALPHA
| C1_DEFINED
,
5172 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
5173 static const WCHAR punct
[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
5175 static const WCHAR punct_special
[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
5176 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
5177 static const WCHAR digit_special
[] = {0xb2, 0xb3, 0xb9};
5178 static const WCHAR lower_special
[] = {0x2071, 0x207f};
5179 static const WCHAR cntrl_special
[] = {0x070f, 0x200c, 0x200d,
5180 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
5181 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
5182 0xfff9, 0xfffa, 0xfffb};
5183 static const WCHAR space_special
[] = {0x09, 0x0d, 0x85};
5191 SetLastError(0xdeadbeef);
5192 ret
= GetStringTypeW(CT_CTYPE1
, NULL
, 0, NULL
);
5193 ok(!ret
, "got %d\n", ret
);
5194 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "got error %ld\n", GetLastError());
5196 SetLastError(0xdeadbeef);
5197 ret
= GetStringTypeW(CT_CTYPE1
, NULL
, 0, types
);
5198 ok(!ret
, "got %d\n", ret
);
5199 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "got error %ld\n", GetLastError());
5201 SetLastError(0xdeadbeef);
5202 ret
= GetStringTypeW(CT_CTYPE1
, NULL
, 5, types
);
5203 ok(!ret
, "got %d\n", ret
);
5204 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "got error %ld\n", GetLastError());
5206 memset(types
,0,sizeof(types
));
5207 GetStringTypeW(CT_CTYPE1
, blanks
, 5, types
);
5208 for (i
= 0; i
< 5; i
++)
5209 ok(types
[i
] == blanks_new
[i
] || broken(types
[i
] == blanks_old
[i
] || broken(types
[i
] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks
[i
],types
[i
],blanks_new
[i
]);
5211 memset(types
,0,sizeof(types
));
5212 GetStringTypeW(CT_CTYPE1
, alpha
, 3, types
);
5213 for (i
= 0; i
< 3; i
++)
5214 ok(types
[i
] == (C1_DEFINED
| alpha_old
[i
]) || broken(types
[i
] == alpha_old
[i
]) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha
[i
], types
[i
],(C1_DEFINED
| alpha_old
[i
]));
5215 memset(types
,0,sizeof(types
));
5216 GetStringTypeW(CT_CTYPE1
, undefined
, 5, types
);
5217 for (i
= 0; i
< 5; i
++)
5218 ok(types
[i
] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined
[i
], types
[i
]);
5220 memset(types
,0,sizeof(types
));
5221 GetStringTypeW(CT_CTYPE1
, oldpunc
, 8, types
);
5222 for (i
= 0; i
< 8; i
++)
5223 ok(types
[i
] == C1_DEFINED
|| broken(types
[i
] == C1_PUNCT
) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc
[i
], types
[i
], C1_DEFINED
);
5225 memset(types
,0,sizeof(types
));
5226 GetStringTypeW(CT_CTYPE1
, changed
, 7, types
);
5227 for (i
= 0; i
< 7; i
++)
5228 ok(types
[i
] == changed_new
[i
] || broken(types
[i
] == changed_old
[i
]) || broken(types
[i
] == changed_xp
[i
]) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed
[i
], types
[i
], changed_new
[i
]);
5230 memset(types
,0,sizeof(types
));
5231 GetStringTypeW(CT_CTYPE1
, punct
, 7, types
);
5232 for (i
= 0; i
< 7; i
++)
5233 ok(types
[i
] == (C1_PUNCT
| C1_DEFINED
) || broken(types
[i
] == C1_PUNCT
) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct
[i
], types
[i
], (C1_PUNCT
| C1_DEFINED
));
5236 memset(types
,0,sizeof(types
));
5237 GetStringTypeW(CT_CTYPE1
, punct_special
, 12, types
);
5238 for (i
= 0; i
< 12; i
++)
5239 ok(types
[i
] & C1_PUNCT
|| broken(types
[i
] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special
[i
], types
[i
], C1_PUNCT
);
5241 memset(types
,0,sizeof(types
));
5242 GetStringTypeW(CT_CTYPE1
, digit_special
, 3, types
);
5243 for (i
= 0; i
< 3; i
++)
5244 ok(types
[i
] & C1_DIGIT
|| broken(types
[i
] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special
[i
], types
[i
], C1_DIGIT
);
5246 memset(types
,0,sizeof(types
));
5247 GetStringTypeW(CT_CTYPE1
, lower_special
, 2, types
);
5248 for (i
= 0; i
< 2; i
++)
5249 ok(types
[i
] & C1_LOWER
|| broken(types
[i
] == C1_PUNCT
) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special
[i
], types
[i
], C1_LOWER
);
5251 memset(types
,0,sizeof(types
));
5252 GetStringTypeW(CT_CTYPE1
, cntrl_special
, 20, types
);
5253 for (i
= 0; i
< 20; i
++)
5254 ok(types
[i
] & C1_CNTRL
|| broken(types
[i
] == (C1_BLANK
|C1_SPACE
)) || broken(types
[i
] == C1_PUNCT
) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special
[i
], types
[i
], C1_CNTRL
);
5256 memset(types
,0,sizeof(types
));
5257 GetStringTypeW(CT_CTYPE1
, space_special
, 3, types
);
5258 for (i
= 0; i
< 3; i
++)
5259 ok(types
[i
] & C1_SPACE
|| broken(types
[i
] == C1_CNTRL
) || broken(types
[i
] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special
[i
], types
[i
], C1_SPACE
);
5261 /* surrogate pairs */
5263 memset(types
, 0, sizeof(types
));
5264 GetStringTypeW(CT_CTYPE3
, ch
, 1, types
);
5265 if (types
[0] == C3_NOTAPPLICABLE
)
5266 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
5268 ok(types
[0] == C3_HIGHSURROGATE
, "got %x\n", types
[0]);
5271 memset(types
, 0, sizeof(types
));
5272 GetStringTypeW(CT_CTYPE3
, ch
, 1, types
);
5273 ok(types
[0] == C3_LOWSURROGATE
, "got %x\n", types
[0]);
5276 /* Zl, Zp categories */
5279 memset(types
, 0, sizeof(types
));
5280 GetStringTypeW(CT_CTYPE1
, ch
, 2, types
);
5281 ok(types
[0] == (C1_DEFINED
|C1_SPACE
), "got %x\n", types
[0]);
5282 ok(types
[1] == (C1_DEFINED
|C1_SPACE
), "got %x\n", types
[1]);
5284 /* check Arabic range for kashida flag */
5285 for (ch
[0] = 0x600; ch
[0] <= 0x6ff; ch
[0] += 1)
5288 ret
= GetStringTypeW(CT_CTYPE3
, ch
, 1, types
);
5289 ok(ret
, "%#x: failed %d\n", ch
[0], ret
);
5290 if (ch
[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
5291 ok(types
[0] & C3_KASHIDA
, "%#x: type %#x\n", ch
[0], types
[0]);
5293 ok(!(types
[0] & C3_KASHIDA
), "%#x: type %#x\n", ch
[0], types
[0]);
5297 static void test_IdnToNameprepUnicode(void)
5305 const WCHAR out
[80];
5307 NTSTATUS broken_status
;
5310 { 5, L
"test", 0, 5, 5, L
"test" },
5311 { 3, L
"a\xe111z", 0, 0, 0, L
"a\xe111z", 0, STATUS_NO_UNICODE_TRANSLATION
},
5312 { 4, L
"t\0e", 0, 0, 0, {0}, STATUS_NO_UNICODE_TRANSLATION
, STATUS_NO_UNICODE_TRANSLATION
},
5313 { 1, L
"T", 0, 1, 1, L
"T" },
5316 { 6, L
" -/[]", 0, 6, 6, L
" -/[]" },
5317 { 3, L
"a-a", IDN_USE_STD3_ASCII_RULES
, 3, 3, L
"a-a" },
5318 { 3, L
"aa-", IDN_USE_STD3_ASCII_RULES
, 0, 0, L
"aa-" },
5319 { -1, L
"T\xdf\x130\x143\x37a\x6a\x30c \xaa", 0, 12, 12, L
"tssi\x307\x144 \x3b9\x1f0 a" },
5320 { 11, L
"t\xad\x34f\x1806\x180b\x180c\x180d\x200b\x200c\x200d", 0, 0, 2, L
"t",
5321 STATUS_NO_UNICODE_TRANSLATION
},
5323 { 2, {0x3b0}, 0, 2, 2, {0x3b0} },
5324 { 2, {0x380}, 0, 0, 2, {0x380} },
5325 { 2, {0x380}, IDN_ALLOW_UNASSIGNED
, 2, 2, {0x380} },
5326 { 5, L
"a..a", 0, 0, 0, L
"a..a" },
5327 { 3, L
"a.", 0, 3, 3, L
"a." },
5329 { 5, L
"T.\x105.A", 0, 5, 5, L
"t.\x105.a" },
5330 { 5, L
"T.*.A", 0, 5, 5, L
"T.*.A" },
5331 { 5, L
"X\xff0e.Z", 0, 0, 0, L
"x..z" },
5332 { 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5333 63, 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5334 { 64, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5335 0, 0, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5341 ret
= pIdnToNameprepUnicode(0, test_data
[0].in
,
5342 test_data
[0].in_len
, NULL
, 0);
5343 ok(ret
== test_data
[0].ret
, "ret = %ld\n", ret
);
5345 SetLastError(0xdeadbeef);
5346 ret
= pIdnToNameprepUnicode(0, test_data
[1].in
,
5347 test_data
[1].in_len
, NULL
, 0);
5348 err
= GetLastError();
5349 ok(ret
== test_data
[1].ret
, "ret = %ld\n", ret
);
5350 ok(err
== ret
? 0xdeadbeef : ERROR_INVALID_NAME
, "err = %ld\n", err
);
5352 SetLastError(0xdeadbeef);
5353 ret
= pIdnToNameprepUnicode(0, test_data
[0].in
, -1, buf
, ARRAY_SIZE(buf
));
5354 err
= GetLastError();
5355 ok(ret
== test_data
[0].ret
, "ret = %ld\n", ret
);
5356 ok(err
== 0xdeadbeef, "err = %ld\n", err
);
5358 SetLastError(0xdeadbeef);
5359 ret
= pIdnToNameprepUnicode(0, test_data
[0].in
, -2, buf
, ARRAY_SIZE(buf
));
5360 err
= GetLastError();
5361 ok(ret
== 0, "ret = %ld\n", ret
);
5362 ok(err
== ERROR_INVALID_PARAMETER
, "err = %ld\n", err
);
5364 SetLastError(0xdeadbeef);
5365 ret
= pIdnToNameprepUnicode(0, test_data
[0].in
, 0, buf
, ARRAY_SIZE(buf
));
5366 err
= GetLastError();
5367 ok(ret
== 0, "ret = %ld\n", ret
);
5368 ok(err
== ERROR_INVALID_NAME
, "err = %ld\n", err
);
5370 ret
= pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED
|IDN_USE_STD3_ASCII_RULES
,
5371 test_data
[0].in
, -1, buf
, ARRAY_SIZE(buf
));
5372 ok(ret
== test_data
[0].ret
, "ret = %ld\n", ret
);
5374 SetLastError(0xdeadbeef);
5375 ret
= pIdnToNameprepUnicode(0, NULL
, 0, NULL
, 0);
5376 err
= GetLastError();
5377 ok(ret
== 0, "ret = %ld\n", ret
);
5378 ok(err
== ERROR_INVALID_PARAMETER
, "err = %ld\n", err
);
5380 SetLastError(0xdeadbeef);
5381 ret
= pIdnToNameprepUnicode(4, NULL
, 0, NULL
, 0);
5382 err
= GetLastError();
5383 ok(ret
== 0, "ret = %ld\n", ret
);
5384 ok(err
== ERROR_INVALID_FLAGS
|| err
== ERROR_INVALID_PARAMETER
/* Win8 */,
5385 "err = %ld\n", err
);
5387 for (i
=0; i
<ARRAY_SIZE(test_data
); i
++)
5389 SetLastError(0xdeadbeef);
5390 memset( buf
, 0xcc, sizeof(buf
) );
5391 ret
= pIdnToNameprepUnicode(test_data
[i
].flags
, test_data
[i
].in
, test_data
[i
].in_len
,
5392 buf
, ARRAY_SIZE(buf
));
5393 err
= GetLastError();
5395 ok(ret
== test_data
[i
].ret
|| broken(ret
== test_data
[i
].broken_ret
), "%ld: ret = %ld\n", i
, ret
);
5397 if (ret
== test_data
[i
].ret
)
5399 ok(err
== ret
? 0xdeadbeef : ERROR_INVALID_NAME
, "%ld: err = %ld\n", i
, err
);
5400 ok(!wcsncmp(test_data
[i
].out
, buf
, ret
), "%ld: buf = %s\n", i
, wine_dbgstr_wn(buf
, ret
));
5402 if (pRtlNormalizeString
)
5405 int len
= ARRAY_SIZE(buf
);
5406 memset( buf
, 0xcc, sizeof(buf
) );
5407 status
= pRtlNormalizeString( 13, test_data
[i
].in
, test_data
[i
].in_len
, buf
, &len
);
5408 ok( status
== test_data
[i
].status
|| broken(status
== test_data
[i
].broken_status
),
5409 "%ld: failed %lx\n", i
, status
);
5410 if (!status
) ok( !wcsnicmp(test_data
[i
].out
, buf
, len
), "%ld: buf = %s\n", i
, wine_dbgstr_wn(buf
, len
));
5415 static void test_IdnToAscii(void)
5423 const WCHAR out
[80];
5426 { 5, L
"Test", 0, 5, 5, L
"Test" },
5427 { 5, L
"Te\x017cst", 0, 12, 12, L
"xn--test-cbb" },
5428 { 12, L
"te\x0105st.te\x017cst", 0, 26, 26, L
"xn--test-cta.xn--test-cbb" },
5429 { 3, {0x0105,'.',0}, 0, 9, 9, L
"xn--2da." },
5430 { 10, L
"http://t\x106", 0, 17, 17, L
"xn--http://t-78a" },
5432 { -1, L
"\x4e3a\x8bf4\x4e0d\x4ed6\x5011\x10d\x11b\x305c\x306a", 0,
5433 35, 35, L
"xn--bea2a1631avbav44tyha32b91egs2t" },
5434 { 2, L
"\x380", IDN_ALLOW_UNASSIGNED
, 8, 8, L
"xn--7va" },
5435 { 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5436 63, 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5437 { 64, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0 },
5438 { -1, L
"\xe4z123456789012345678901234567890123456789012345678901234", 0,
5439 64, 64, L
"xn--z123456789012345678901234567890123456789012345678901234-9te" },
5441 { -1, L
"\xd803\xde78\x46b5-\xa861.\x2e87", 0, 28, 0, L
"xn----bm3an932a1l5d.xn--xvj" },
5442 { -1, L
"\x06ef\x06ef", 0, 9, 0, L
"xn--cmba" },
5443 { -1, L
"-\x07e1\xff61\x2184", 0, 18, 0, L
"xn----8cd.xn--r5g" },
5449 for (i
=0; i
<ARRAY_SIZE(test_data
); i
++)
5451 SetLastError(0xdeadbeef);
5452 ret
= pIdnToAscii(test_data
[i
].flags
, test_data
[i
].in
, test_data
[i
].in_len
, buf
, ARRAY_SIZE(buf
));
5453 err
= GetLastError();
5454 ok(ret
== test_data
[i
].ret
|| broken(ret
== test_data
[i
].broken_ret
), "%ld: ret = %ld\n", i
, ret
);
5455 ok(err
== ret
? 0xdeadbeef : ERROR_INVALID_NAME
, "%ld: err = %ld\n", i
, err
);
5456 ok(!wcsnicmp(test_data
[i
].out
, buf
, ret
), "%ld: buf = %s\n", i
, wine_dbgstr_wn(buf
, ret
));
5460 static void test_IdnToUnicode(void)
5468 const WCHAR out
[80];
5471 { 5, L
"Tes.", 0, 5, 5, L
"Tes." },
5472 { 2, L
"\x105", 0, 0 },
5473 { 33, L
"xn--4dbcagdahymbxekheh6e0a7fei0b", 0,
5474 23, 23, L
"\x05dc\x05de\x05d4\x05d4\x05dd\x05e4\x05e9\x05d5\x05d8\x05dc\x05d0\x05de\x05d3\x05d1\x05e8\x05d9\x05dd\x05e2\x05d1\x05e8\x05d9\x05ea" },
5475 { 34, L
"test.xn--kda9ag5e9jnfsj.xn--pz-fna", 0,
5476 16, 16, L
"test.\x0105\x0119\x015b\x0107\x0142\x00f3\x017c.p\x0119z" },
5477 { 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
5478 63, 63, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
5480 { 64, L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, 0 },
5481 { 8, L
"xn--7va", IDN_ALLOW_UNASSIGNED
, 2, 2, L
"\x380" },
5482 { 8, L
"xn--7va", 0, 0, 0, L
"\x380" },
5483 { -1, L
"xn----bm3an932a1l5d.xn--xvj", 0, 8, 0, L
"\xd803\xde78\x46b5-\xa861.\x2e87" },
5484 { -1, L
"xn--z123456789012345678901234567890123456789012345678901234-9te", 0,
5485 57, 57, L
"\xe4z123456789012345678901234567890123456789012345678901234" },
5487 { -1, L
"foo.bar", 0, 8, 8, L
"foo.bar" },
5488 { -1, L
"d.xn----dha", 0, 5, 5, L
"d.\x00fc-" },
5494 for (i
=0; i
<ARRAY_SIZE(test_data
); i
++)
5496 ret
= pIdnToUnicode(test_data
[i
].flags
, test_data
[i
].in
, test_data
[i
].in_len
, NULL
, 0);
5497 ok(ret
== test_data
[i
].ret
|| broken(ret
== test_data
[i
].broken_ret
), "%ld: ret = %ld\n", i
, ret
);
5499 SetLastError(0xdeadbeef);
5500 ret
= pIdnToUnicode(test_data
[i
].flags
, test_data
[i
].in
, test_data
[i
].in_len
, buf
, ARRAY_SIZE(buf
));
5501 err
= GetLastError();
5502 ok(ret
== test_data
[i
].ret
|| broken(ret
== test_data
[i
].broken_ret
), "%ld: ret = %ld\n", i
, ret
);
5503 ok(err
== ret
? 0xdeadbeef : ERROR_INVALID_NAME
, "%ld: err = %ld\n", i
, err
);
5504 ok(!wcsncmp(test_data
[i
].out
, buf
, ret
), "%ld: buf = %s\n", i
, wine_dbgstr_wn(buf
, ret
));
5508 static BOOL
is_idn_error( const WCHAR
*str
)
5511 lstrcpyW( err
, str
);
5512 for (p
= wcstok( err
, L
" []" ); p
; p
= wcstok( NULL
, L
" []" ) )
5514 if (*p
== 'B' || !wcscmp( p
, L
"V8" )) continue; /* BiDi */
5515 if (!wcscmp( p
, L
"V2" )) continue; /* CheckHyphens */
5516 if (!wcscmp( p
, L
"V5" )) continue; /* Combining marks */
5522 static void test_Idn(void)
5526 if (!pIdnToAscii
|| !pIdnToUnicode
|| !pIdnToNameprepUnicode
)
5528 win_skip("Idn support is not available\n");
5532 test_IdnToNameprepUnicode();
5534 test_IdnToUnicode();
5536 /* optionally run the full test file from Unicode.org
5537 * available at https://www.unicode.org/Public/idna/latest/IdnaTestV2.txt
5539 if ((f
= fopen( "IdnaTestV2.txt", "r" )))
5541 char *p
, *end
, buffer
[2048];
5542 WCHAR columns
[7][256], dst
[256], *expect
, *error
;
5543 int i
, ret
, line
= 0;
5545 while (fgets( buffer
, sizeof(buffer
), f
))
5548 if ((p
= strchr( buffer
, '#' ))) *p
= 0;
5549 if (!(p
= strtok( buffer
, ";" ))) continue;
5550 for (i
= 0; i
< 7 && p
; i
++)
5552 while (*p
== ' ') p
++;
5553 for (end
= p
+ strlen(p
); end
> p
; end
--) if (end
[-1] != ' ') break;
5555 MultiByteToWideChar( CP_UTF8
, 0, p
, -1, columns
[i
], 256 );
5556 p
= strtok( NULL
, ";" );
5558 if (i
< 7) continue;
5560 expect
= columns
[5];
5561 if (!*expect
) expect
= columns
[3];
5562 if (!*expect
) expect
= columns
[1];
5563 if (!*expect
) expect
= columns
[0];
5565 if (!*error
) error
= columns
[4];
5566 if (!*error
) error
= columns
[2];
5567 SetLastError( 0xdeadbeef );
5568 memset( dst
, 0xcc, sizeof(dst
) );
5569 ret
= pIdnToAscii( 0, columns
[0], -1, dst
, ARRAY_SIZE(dst
) );
5570 if (!is_idn_error( error
))
5572 ok( ret
, "line %u: toAscii failed for %s expected %s\n", line
,
5573 debugstr_w(columns
[0]), debugstr_w(expect
) );
5574 if (ret
) ok( !wcscmp( dst
, expect
), "line %u: got %s expected %s\n",
5575 line
, debugstr_w(dst
), debugstr_w(expect
) );
5579 ok( !ret
, "line %u: toAscii didn't fail for %s got %s expected error %s\n",
5580 line
, debugstr_w(columns
[0]), debugstr_w(dst
), debugstr_w(error
) );
5583 expect
= columns
[1];
5584 if (!*expect
) expect
= columns
[0];
5586 SetLastError( 0xdeadbeef );
5587 memset( dst
, 0xcc, sizeof(dst
) );
5588 ret
= pIdnToUnicode( IDN_USE_STD3_ASCII_RULES
, columns
[0], -1, dst
, ARRAY_SIZE(dst
) );
5589 for (i
= 0; columns
[0][i
]; i
++) if (columns
[0][i
] > 0x7f) break;
5592 ok( !ret
, "line %u: didn't fail for unicode chars in %s\n", line
, debugstr_w(columns
[0]) );
5594 else if (!is_idn_error( error
))
5596 ok( ret
, "line %u: toUnicode failed for %s expected %s\n", line
,
5597 debugstr_w(columns
[0]), debugstr_w(expect
) );
5598 if (ret
) ok( !wcscmp( dst
, expect
), "line %u: got %s expected %s\n",
5599 line
, debugstr_w(dst
), debugstr_w(expect
) );
5603 ok( !ret
, "line %u: toUnicode didn't fail for %s got %s expected error %s\n",
5604 line
, debugstr_w(columns
[0]), debugstr_w(dst
), debugstr_w(error
) );
5612 static void test_GetLocaleInfoEx(void)
5614 static const WCHAR enW
[] = {'e','n',0};
5615 WCHAR bufferW
[80], buffer2
[80];
5618 if (!pGetLocaleInfoEx
)
5620 win_skip("GetLocaleInfoEx not supported\n");
5624 ret
= pGetLocaleInfoEx(enW
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5625 ok(ret
|| broken(ret
== 0) /* Vista */, "got %d\n", ret
);
5628 static const WCHAR statesW
[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
5629 static const WCHAR dummyW
[] = {'d','u','m','m','y',0};
5630 static const WCHAR enusW
[] = {'e','n','-','U','S',0};
5631 static const WCHAR usaW
[] = {'U','S','A',0};
5632 static const WCHAR enuW
[] = {'E','N','U',0};
5633 const struct neutralsublang_name_t
*ptr
= neutralsublang_names
;
5636 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5637 ok(!lstrcmpW(bufferW
, enW
), "got %s\n", wine_dbgstr_w(bufferW
));
5639 SetLastError(0xdeadbeef);
5640 ret
= pGetLocaleInfoEx(enW
, LOCALE_SNAME
, bufferW
, 2);
5641 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %d, %ld\n", ret
, GetLastError());
5643 SetLastError(0xdeadbeef);
5644 ret
= pGetLocaleInfoEx(enW
, LOCALE_SNAME
, NULL
, 0);
5645 ok(ret
== 3 && GetLastError() == 0xdeadbeef, "got %d, %ld\n", ret
, GetLastError());
5647 ret
= pGetLocaleInfoEx(enusW
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5648 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5649 ok(!lstrcmpW(bufferW
, enusW
), "got %s\n", wine_dbgstr_w(bufferW
));
5651 ret
= pGetLocaleInfoEx(enW
, LOCALE_SABBREVCTRYNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5652 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5653 ok(!lstrcmpW(bufferW
, usaW
), "got %s\n", wine_dbgstr_w(bufferW
));
5655 ret
= pGetLocaleInfoEx(enW
, LOCALE_SABBREVLANGNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5656 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5657 ok(!lstrcmpW(bufferW
, enuW
), "got %s\n", wine_dbgstr_w(bufferW
));
5659 ret
= pGetLocaleInfoEx(enusW
, LOCALE_SPARENT
, bufferW
, ARRAY_SIZE(bufferW
));
5660 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5661 ok(!lstrcmpW(bufferW
, enW
), "got %s\n", wine_dbgstr_w(bufferW
));
5663 ret
= pGetLocaleInfoEx(enW
, LOCALE_SPARENT
, bufferW
, ARRAY_SIZE(bufferW
));
5664 ok(ret
== 1, "got %d\n", ret
);
5665 ok(!bufferW
[0], "got %s\n", wine_dbgstr_w(bufferW
));
5667 ret
= pGetLocaleInfoEx(enW
, LOCALE_SPARENT
| LOCALE_NOUSEROVERRIDE
, bufferW
, ARRAY_SIZE(bufferW
));
5668 ok(ret
== 1, "got %d\n", ret
);
5669 ok(!bufferW
[0], "got %s\n", wine_dbgstr_w(bufferW
));
5671 ret
= pGetLocaleInfoEx(enW
, LOCALE_SCOUNTRY
, bufferW
, ARRAY_SIZE(bufferW
));
5672 ok(ret
== lstrlenW(bufferW
)+1, "got %d\n", ret
);
5673 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH
) ||
5674 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH
))
5676 skip("Non-English locale\n");
5679 ok(!lstrcmpW(bufferW
, statesW
), "got %s\n", wine_dbgstr_w(bufferW
));
5682 SetLastError(0xdeadbeef);
5683 ret
= pGetLocaleInfoEx(dummyW
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5684 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "got %d, error %ld\n", ret
, GetLastError());
5689 pGetLocaleInfoEx(ptr
->name
, LOCALE_ILANGUAGE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, sizeof(val
)/sizeof(WCHAR
));
5690 ok(val
== ptr
->lcid
, "%s: got wrong lcid 0x%04lx, expected 0x%04lx\n", wine_dbgstr_w(ptr
->name
), val
, ptr
->lcid
);
5692 ret
= pGetLocaleInfoEx(ptr
->name
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5693 ok(ret
== lstrlenW(bufferW
)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr
->name
), ret
);
5694 ok(!lstrcmpW(bufferW
, ptr
->name
), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr
->name
), wine_dbgstr_w(bufferW
));
5698 ret
= pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT
, LOCALE_SNAME
, bufferW
, ARRAY_SIZE(bufferW
));
5699 ok(ret
&& ret
== lstrlenW(bufferW
)+1, "got ret value %d\n", ret
);
5700 ret
= GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME
, buffer2
, ARRAY_SIZE(buffer2
));
5701 ok(ret
&& ret
== lstrlenW(buffer2
)+1, "got ret value %d\n", ret
);
5702 ok(!lstrcmpW(bufferW
, buffer2
), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW
), wine_dbgstr_w(buffer2
));
5706 static void test_IsValidLocaleName(void)
5710 if (!pIsValidLocaleName
)
5712 win_skip("IsValidLocaleName not supported\n");
5716 ret
= pIsValidLocaleName(L
"en-US");
5717 ok(ret
, "IsValidLocaleName failed\n");
5718 ret
= pIsValidLocaleName(L
"en");
5719 ok(ret
, "IsValidLocaleName failed\n");
5720 ret
= pIsValidLocaleName(L
"es-es");
5721 ok(ret
, "IsValidLocaleName failed\n");
5722 ret
= pIsValidLocaleName(L
"de-DE_phoneb");
5723 ok(ret
, "IsValidLocaleName failed\n");
5724 ret
= pIsValidLocaleName(L
"DE_de-phoneb");
5725 ok(ret
|| broken(!ret
), "IsValidLocaleName failed\n");
5726 ret
= pIsValidLocaleName(L
"DE_de_PHONEB");
5727 ok(ret
|| broken(!ret
), "IsValidLocaleName failed\n");
5728 ret
= pIsValidLocaleName(L
"DE_de+phoneb");
5729 ok(!ret
, "IsValidLocaleName should have failed\n");
5730 ret
= pIsValidLocaleName(L
"zz");
5731 ok(!ret
|| broken(ret
), "IsValidLocaleName should have failed\n");
5732 ret
= pIsValidLocaleName(L
"zz-ZZ");
5733 ok(!ret
|| broken(ret
), "IsValidLocaleName should have failed\n");
5734 ret
= pIsValidLocaleName(L
"zzz");
5735 ok(!ret
|| broken(ret
), "IsValidLocaleName should have failed\n");
5736 ret
= pIsValidLocaleName(L
"zzz-ZZZ");
5737 ok(!ret
, "IsValidLocaleName should have failed\n");
5738 ret
= pIsValidLocaleName(L
"zzzz");
5739 ok(!ret
, "IsValidLocaleName should have failed\n");
5740 ret
= pIsValidLocaleName(LOCALE_NAME_INVARIANT
);
5741 ok(ret
, "IsValidLocaleName failed\n");
5742 ret
= pIsValidLocaleName(LOCALE_NAME_USER_DEFAULT
);
5743 ok(!ret
, "IsValidLocaleName should have failed\n");
5744 ret
= pIsValidLocaleName(LOCALE_NAME_SYSTEM_DEFAULT
);
5745 ok(!ret
, "IsValidLocaleName should have failed\n");
5747 if (!pRtlIsValidLocaleName
)
5749 win_skip( "RtlIsValidLocaleName not available\n" );
5753 ret
= pRtlIsValidLocaleName( L
"en-US", 0 );
5754 ok(ret
, "RtlIsValidLocaleName failed\n");
5755 ret
= pRtlIsValidLocaleName( L
"en", 0 );
5756 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5757 ret
= pRtlIsValidLocaleName( L
"en", 1 );
5758 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5759 ret
= pRtlIsValidLocaleName( L
"en", 2 );
5760 ok(ret
, "RtlIsValidLocaleName failed\n");
5761 ret
= pRtlIsValidLocaleName( L
"en-RR", 2 );
5762 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5763 ret
= pRtlIsValidLocaleName( L
"es-es", 0 );
5764 ok(ret
, "RtlIsValidLocaleName failed\n");
5765 ret
= pRtlIsValidLocaleName( L
"de-DE_phoneb", 0 );
5766 ok(ret
, "RtlIsValidLocaleName failed\n");
5767 ret
= pRtlIsValidLocaleName( L
"DE_de_PHONEB", 0 );
5768 ok(ret
|| broken(!ret
), "RtlIsValidLocaleName failed\n");
5769 ret
= pRtlIsValidLocaleName( L
"DE_de+phoneb", 0 );
5770 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5771 ret
= pRtlIsValidLocaleName( L
"zz", 0 );
5772 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5773 ret
= pRtlIsValidLocaleName( L
"zz", 2 );
5774 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5775 ret
= pRtlIsValidLocaleName( L
"zz-ZZ", 0 );
5776 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5777 ret
= pRtlIsValidLocaleName( L
"zzz", 0 );
5778 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5779 ret
= pRtlIsValidLocaleName( L
"zzz-ZZZ", 0 );
5780 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5781 ret
= pRtlIsValidLocaleName( L
"zzzz", 0 );
5782 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5783 ret
= pRtlIsValidLocaleName( LOCALE_NAME_INVARIANT
, 0 );
5784 ok(ret
, "RtlIsValidLocaleName failed\n");
5785 ret
= pRtlIsValidLocaleName( LOCALE_NAME_USER_DEFAULT
, 0 );
5786 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5787 ret
= pRtlIsValidLocaleName( LOCALE_NAME_SYSTEM_DEFAULT
, 0 );
5788 ok(!ret
, "RtlIsValidLocaleName should have failed\n");
5791 static void test_ResolveLocaleName(void)
5793 static const struct { const WCHAR
*name
, *exp
; BOOL broken
; } tests
[] =
5795 { L
"en-US", L
"en-US" },
5796 { L
"en", L
"en-US" },
5797 { L
"en-RR", L
"en-US" },
5798 { L
"en-na", L
"en-NA", TRUE
/* <= win8 */ },
5799 { L
"EN-zz", L
"en-US" },
5800 { L
"en-US", L
"en-US" },
5801 { L
"de-DE_phoneb", L
"de-DE" },
5802 { L
"DE-de-phoneb", L
"de-DE" },
5803 { L
"fr-029", L
"fr-029", TRUE
/* <= win8 */ },
5804 { L
"fr-CH_XX", L
"fr-CH", TRUE
/* <= win10 1809 */ },
5805 { L
"fr-CHXX", L
"fr-FR" },
5806 { L
"zh", L
"zh-CN" },
5807 { L
"zh-Hant", L
"zh-HK" },
5808 { L
"zh-hans", L
"zh-CN" },
5809 { L
"ja-jp_radstr", L
"ja-JP" },
5810 { L
"az", L
"az-Latn-AZ" },
5811 { L
"uz", L
"uz-Latn-UZ" },
5812 { L
"uz-cyrl", L
"uz-Cyrl-UZ" },
5813 { L
"ia", L
"ia-001", TRUE
/* <= win10 1809 */ },
5815 { L
"zzz-ZZZ", L
"" },
5819 { LOCALE_NAME_INVARIANT
, L
"" },
5822 WCHAR buffer
[LOCALE_NAME_MAX_LENGTH
], system
[LOCALE_NAME_MAX_LENGTH
];
5824 if (!pResolveLocaleName
)
5826 win_skip( "ResolveLocaleName not available\n" );
5829 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
5831 SetLastError( 0xdeadbeef );
5832 memset( buffer
, 0xcc, sizeof(buffer
) );
5833 ret
= pResolveLocaleName( tests
[i
].name
, buffer
, ARRAY_SIZE(buffer
) );
5836 ok( !wcscmp( buffer
, tests
[i
].exp
) || broken( tests
[i
].broken
),
5837 "%s: got %s\n", debugstr_w(tests
[i
].name
), debugstr_w(buffer
) );
5838 ok( ret
== wcslen(buffer
) + 1, "%s: got %u\n", debugstr_w(tests
[i
].name
), ret
);
5842 ok( !ret
|| broken( ret
== 1 ) /* win7 */,
5843 "%s: got %s\n", debugstr_w(tests
[i
].name
), debugstr_w(buffer
) );
5845 ok( GetLastError() == ERROR_INVALID_PARAMETER
,
5846 "%s: wrong error %lu\n", debugstr_w(tests
[i
].name
), GetLastError() );
5849 SetLastError( 0xdeadbeef );
5850 memset( buffer
, 0xcc, sizeof(buffer
) );
5851 ret
= pResolveLocaleName( LOCALE_NAME_SYSTEM_DEFAULT
, buffer
, ARRAY_SIZE(buffer
) );
5852 ok( ret
, "failed err %lu\n", GetLastError() );
5853 GetSystemDefaultLocaleName( system
, ARRAY_SIZE(system
) );
5854 ok( !wcscmp( buffer
, system
), "got wrong syslocale %s / %s\n", debugstr_w(buffer
), debugstr_w(system
));
5855 ok( ret
== wcslen(system
) + 1, "wrong len %u / %Iu\n", ret
, wcslen(system
) + 1 );
5857 SetLastError( 0xdeadbeef );
5858 ret
= pResolveLocaleName( L
"en-US", buffer
, 4 );
5859 ok( !ret
, "got %u\n", ret
);
5860 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "wrong error %lu\n", GetLastError() );
5861 ok( !wcscmp( buffer
, L
"en-" ), "got %s\n", debugstr_w(buffer
) );
5863 SetLastError( 0xdeadbeef );
5864 ret
= pResolveLocaleName( L
"en-US", NULL
, 0 );
5865 ok( ret
== 6, "got %u\n", ret
);
5866 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
5869 static void test_CompareStringOrdinal(void)
5872 WCHAR test1
[] = { 't','e','s','t',0 };
5873 WCHAR test2
[] = { 'T','e','S','t',0 };
5874 WCHAR test3
[] = { 't','e','s','t','3',0 };
5875 WCHAR null1
[] = { 'a',0,'a',0 };
5876 WCHAR null2
[] = { 'a',0,'b',0 };
5877 WCHAR bills1
[] = { 'b','i','l','l','\'','s',0 };
5878 WCHAR bills2
[] = { 'b','i','l','l','s',0 };
5879 WCHAR coop1
[] = { 'c','o','-','o','p',0 };
5880 WCHAR coop2
[] = { 'c','o','o','p',0 };
5881 WCHAR nonascii1
[] = { 0x0102,0 };
5882 WCHAR nonascii2
[] = { 0x0201,0 };
5885 if (!pCompareStringOrdinal
)
5887 win_skip("CompareStringOrdinal not supported\n");
5892 SetLastError(0xdeadbeef);
5893 ret
= pCompareStringOrdinal(NULL
, 0, NULL
, 0, FALSE
);
5894 ok(!ret
, "Got %u, expected 0\n", ret
);
5895 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER
);
5896 SetLastError(0xdeadbeef);
5897 ret
= pCompareStringOrdinal(test1
, -1, NULL
, 0, FALSE
);
5898 ok(!ret
, "Got %u, expected 0\n", ret
);
5899 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER
);
5900 SetLastError(0xdeadbeef);
5901 ret
= pCompareStringOrdinal(NULL
, 0, test1
, -1, FALSE
);
5902 ok(!ret
, "Got %u, expected 0\n", ret
);
5903 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "Got %lx, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER
);
5906 ret
= pCompareStringOrdinal(test1
, -1, test1
, -1, FALSE
);
5907 ok(ret
== CSTR_EQUAL
, "Got %u, expected %u\n", ret
, CSTR_EQUAL
);
5908 ret
= pCompareStringOrdinal(test1
, -1, test2
, -1, FALSE
);
5909 ok(ret
== CSTR_GREATER_THAN
, "Got %u, expected %u\n", ret
, CSTR_GREATER_THAN
);
5910 ret
= pCompareStringOrdinal(test2
, -1, test1
, -1, FALSE
);
5911 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5912 ret
= pCompareStringOrdinal(test1
, -1, test2
, -1, TRUE
);
5913 ok(ret
== CSTR_EQUAL
, "Got %u, expected %u\n", ret
, CSTR_EQUAL
);
5915 /* Check different sizes */
5916 ret
= pCompareStringOrdinal(test1
, 3, test2
, -1, TRUE
);
5917 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5918 ret
= pCompareStringOrdinal(test1
, -1, test2
, 3, TRUE
);
5919 ok(ret
== CSTR_GREATER_THAN
, "Got %u, expected %u\n", ret
, CSTR_GREATER_THAN
);
5921 /* Check null character */
5922 ret
= pCompareStringOrdinal(null1
, 3, null2
, 3, FALSE
);
5923 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5924 ret
= pCompareStringOrdinal(null1
, 3, null2
, 3, TRUE
);
5925 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5926 ret
= pCompareStringOrdinal(test1
, 5, test3
, 5, FALSE
);
5927 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5928 ret
= pCompareStringOrdinal(test1
, 4, test1
, 5, FALSE
);
5929 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5931 /* Check ordinal behaviour */
5932 ret
= pCompareStringOrdinal(bills1
, -1, bills2
, -1, FALSE
);
5933 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5934 ret
= pCompareStringOrdinal(coop2
, -1, coop1
, -1, FALSE
);
5935 ok(ret
== CSTR_GREATER_THAN
, "Got %u, expected %u\n", ret
, CSTR_GREATER_THAN
);
5936 ret
= pCompareStringOrdinal(nonascii1
, -1, nonascii2
, -1, FALSE
);
5937 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5938 ret
= pCompareStringOrdinal(nonascii1
, -1, nonascii2
, -1, TRUE
);
5939 ok(ret
== CSTR_LESS_THAN
, "Got %u, expected %u\n", ret
, CSTR_LESS_THAN
);
5941 for (ch1
= 0; ch1
< 512; ch1
++)
5943 for (ch2
= 0; ch2
< 1024; ch2
++)
5945 int diff
= ch1
- ch2
;
5946 ret
= pCompareStringOrdinal( &ch1
, 1, &ch2
, 1, FALSE
);
5947 ok( ret
== (diff
> 0 ? CSTR_GREATER_THAN
: diff
< 0 ? CSTR_LESS_THAN
: CSTR_EQUAL
),
5948 "wrong result %d %04x %04x\n", ret
, ch1
, ch2
);
5949 diff
= pRtlUpcaseUnicodeChar( ch1
) - pRtlUpcaseUnicodeChar( ch2
);
5950 ret
= pCompareStringOrdinal( &ch1
, 1, &ch2
, 1, TRUE
);
5951 ok( ret
== (diff
> 0 ? CSTR_GREATER_THAN
: diff
< 0 ? CSTR_LESS_THAN
: CSTR_EQUAL
),
5952 "wrong result %d %04x %04x\n", ret
, ch1
, ch2
);
5957 static void test_GetGeoInfo(void)
5965 win_skip("GetGeoInfo is not available.\n");
5970 SetLastError(0xdeadbeef);
5971 ret
= pGetGeoInfoA(344, GEO_ISO2
, NULL
, 0, 0);
5972 ok(ret
== 0, "got %d\n", ret
);
5973 ok(GetLastError() == ERROR_INVALID_PARAMETER
||
5974 broken(GetLastError() == 0xdeadbeef /* Win10 */), "got %ld\n", GetLastError());
5976 ret
= pGetGeoInfoA(203, GEO_ISO2
, NULL
, 0, 0);
5977 ok(ret
== 3, "got %d\n", ret
);
5979 ret
= pGetGeoInfoA(203, GEO_ISO3
, NULL
, 0, 0);
5980 ok(ret
== 4, "got %d\n", ret
);
5982 ret
= pGetGeoInfoA(203, GEO_ISO2
, buffA
, 3, 0);
5983 ok(ret
== 3, "got %d\n", ret
);
5984 ok(!strcmp(buffA
, "RU"), "got %s\n", buffA
);
5986 /* buffer pointer not NULL, length is 0 - return required length */
5988 SetLastError(0xdeadbeef);
5989 ret
= pGetGeoInfoA(203, GEO_ISO2
, buffA
, 0, 0);
5990 ok(ret
== 3, "got %d\n", ret
);
5991 ok(buffA
[0] == 'a', "got %c\n", buffA
[0]);
5993 ret
= pGetGeoInfoA(203, GEO_ISO3
, buffA
, 4, 0);
5994 ok(ret
== 4, "got %d\n", ret
);
5995 ok(!strcmp(buffA
, "RUS"), "got %s\n", buffA
);
5997 /* shorter buffer */
5998 SetLastError(0xdeadbeef);
5999 buffA
[1] = buffA
[2] = 0;
6000 ret
= pGetGeoInfoA(203, GEO_ISO2
, buffA
, 2, 0);
6001 ok(ret
== 0, "got %d\n", ret
);
6002 ok(!strcmp(buffA
, "RU"), "got %s\n", buffA
);
6003 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got %ld\n", GetLastError());
6005 /* GEO_NATION returns GEOID in a string form, but only for GEOCLASS_NATION-type IDs */
6006 ret
= pGetGeoInfoA(203, GEO_NATION
, buffA
, 20, 0); /* GEOCLASS_NATION */
6007 ok(ret
== 4, "GEO_NATION of nation: expected 4, got %d\n", ret
);
6008 ok(!strcmp(buffA
, "203"), "GEO_NATION of nation: expected 203, got %s\n", buffA
);
6011 ret
= pGetGeoInfoA(39070, GEO_NATION
, buffA
, 20, 0); /* GEOCLASS_REGION */
6012 ok(ret
== 0, "GEO_NATION of region: expected 0, got %d\n", ret
);
6013 ok(*buffA
== 0, "GEO_NATION of region: expected empty string, got %s\n", buffA
);
6016 ret
= pGetGeoInfoA(333, GEO_NATION
, buffA
, 20, 0); /* LOCATION_BOTH internal Wine type */
6018 broken(ret
== 4) /* Win7 and older */,
6019 "GEO_NATION of LOCATION_BOTH: expected 0, got %d\n", ret
);
6021 broken(!strcmp(buffA
, "333")) /* Win7 and older */,
6022 "GEO_NATION of LOCATION_BOTH: expected empty string, got %s\n", buffA
);
6024 /* GEO_ID is like GEO_NATION but works for any ID */
6026 ret
= pGetGeoInfoA(203, GEO_ID
, buffA
, 20, 0); /* GEOCLASS_NATION */
6028 win_skip("GEO_ID not supported.\n");
6031 ok(ret
== 4, "GEO_ID: expected 4, got %d\n", ret
);
6032 ok(!strcmp(buffA
, "203"), "GEO_ID: expected 203, got %s\n", buffA
);
6034 ret
= pGetGeoInfoA(47610, GEO_ID
, buffA
, 20, 0); /* GEOCLASS_REGION */
6035 ok(ret
== 6, "got %d\n", ret
);
6036 ok(!strcmp(buffA
, "47610"), "got %s\n", buffA
);
6038 ret
= pGetGeoInfoA(333, GEO_ID
, buffA
, 20, 0); /* LOCATION_BOTH internal Wine type */
6039 ok(ret
== 4, "got %d\n", ret
);
6040 ok(!strcmp(buffA
, "333"), "got %s\n", buffA
);
6045 ret
= pGetGeoInfoA(203, GEO_PARENT
, buffA
, 20, 0);
6047 win_skip("GEO_PARENT not supported.\n");
6050 ok(ret
== 6, "got %d\n", ret
);
6051 ok(!strcmp(buffA
, "47609"), "got %s\n", buffA
);
6055 ret
= pGetGeoInfoA(203, GEO_ISO_UN_NUMBER
, buffA
, 20, 0);
6057 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
6060 ok(ret
== 4, "got %d\n", ret
);
6061 ok(!strcmp(buffA
, "643"), "got %s\n", buffA
);
6064 /* try invalid type value */
6065 SetLastError(0xdeadbeef);
6066 ret
= pGetGeoInfoA(203, GEO_ID
+ 1, NULL
, 0, 0);
6067 ok(ret
== 0, "got %d\n", ret
);
6068 ok(GetLastError() == ERROR_INVALID_FLAGS
, "got %ld\n", GetLastError());
6070 /* Test for GetGeoInfoEx */
6073 win_skip("GetGeoInfoEx is not available\n");
6077 /* Test with ISO 3166-1 */
6078 ret
= pGetGeoInfoEx(L
"AR", GEO_ISO3
, buffW
, ARRAYSIZE(buffW
));
6079 ok(ret
!= 0, "GetGeoInfoEx failed %ld.\n", GetLastError());
6080 ok(!wcscmp(buffW
, L
"ARG"), "expected string to be ARG, got %ls\n", buffW
);
6082 /* Test with UN M.49 */
6083 SetLastError(0xdeadbeef);
6084 ret
= pGetGeoInfoEx(L
"032", GEO_ISO3
, buffW
, ARRAYSIZE(buffW
));
6085 ok(ret
== 0, "expected GetGeoInfoEx to fail.\n");
6086 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
6087 "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError());
6090 ret
= pGetGeoInfoEx(L
"AR", GEO_ID
, buffW
, ARRAYSIZE(buffW
));
6091 ok(ret
!= 0, "GetGeoInfoEx failed %ld.\n", GetLastError());
6092 ok(!wcscmp(buffW
, L
"11"), "expected string to be 11, got %ls\n", buffW
);
6094 /* Test with invalid geo type */
6095 SetLastError(0xdeadbeef);
6096 ret
= pGetGeoInfoEx(L
"AR", GEO_LCID
, buffW
, ARRAYSIZE(buffW
));
6097 ok(ret
== 0, "expected GetGeoInfoEx to fail.\n");
6098 ok(GetLastError() == ERROR_INVALID_FLAGS
,
6099 "expected ERROR_INVALID_PARAMETER got %ld.\n", GetLastError());
6102 static int geoidenum_count
;
6103 static BOOL CALLBACK
test_geoid_enumproc(GEOID geoid
)
6105 INT ret
= pGetGeoInfoA(geoid
, GEO_ISO2
, NULL
, 0, 0);
6106 ok(ret
== 3, "got %d for %ld\n", ret
, geoid
);
6107 /* valid geoid starts at 2 */
6108 ok(geoid
>= 2, "got geoid %ld\n", geoid
);
6110 return geoidenum_count
++ < 5;
6113 static BOOL CALLBACK
test_geoid_enumproc2(GEOID geoid
)
6119 static void test_EnumSystemGeoID(void)
6123 if (!pEnumSystemGeoID
)
6125 win_skip("EnumSystemGeoID is not available.\n");
6129 SetLastError(0xdeadbeef);
6130 ret
= pEnumSystemGeoID(GEOCLASS_NATION
, 0, NULL
);
6131 ok(!ret
, "got %d\n", ret
);
6132 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "got %ld\n", GetLastError());
6134 SetLastError(0xdeadbeef);
6135 ret
= pEnumSystemGeoID(GEOCLASS_NATION
+1, 0, test_geoid_enumproc
);
6136 ok(!ret
, "got %d\n", ret
);
6137 ok(GetLastError() == ERROR_INVALID_FLAGS
, "got %ld\n", GetLastError());
6139 SetLastError(0xdeadbeef);
6140 ret
= pEnumSystemGeoID(GEOCLASS_NATION
+1, 0, NULL
);
6141 ok(!ret
, "got %d\n", ret
);
6142 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "got %ld\n", GetLastError());
6144 ret
= pEnumSystemGeoID(GEOCLASS_NATION
, 0, test_geoid_enumproc
);
6145 ok(ret
, "got %d\n", ret
);
6147 /* only the first level is enumerated, not the whole hierarchy */
6148 geoidenum_count
= 0;
6149 ret
= pEnumSystemGeoID(GEOCLASS_NATION
, 39070, test_geoid_enumproc2
);
6151 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
6153 ok(ret
&& geoidenum_count
> 0, "got %d, count %d\n", ret
, geoidenum_count
);
6155 geoidenum_count
= 0;
6156 ret
= pEnumSystemGeoID(GEOCLASS_REGION
, 39070, test_geoid_enumproc2
);
6158 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
6161 ok(ret
&& geoidenum_count
> 0, "got %d, count %d\n", ret
, geoidenum_count
);
6163 geoidenum_count
= 0;
6164 ret
= pEnumSystemGeoID(GEOCLASS_REGION
, 0, test_geoid_enumproc2
);
6165 ok(ret
&& geoidenum_count
> 0, "got %d, count %d\n", ret
, geoidenum_count
);
6168 geoidenum_count
= 0;
6169 ret
= pEnumSystemGeoID(GEOCLASS_ALL
, 39070, test_geoid_enumproc2
);
6171 win_skip("GEOCLASS_ALL is not supported in EnumSystemGeoID.\n");
6174 ok(ret
&& geoidenum_count
> 0, "got %d, count %d\n", ret
, geoidenum_count
);
6176 geoidenum_count
= 0;
6177 ret
= pEnumSystemGeoID(GEOCLASS_ALL
, 0, test_geoid_enumproc2
);
6178 ok(ret
&& geoidenum_count
> 0, "got %d, count %d\n", ret
, geoidenum_count
);
6182 struct invariant_entry
{
6185 const char *expect
, *expect2
;
6189 static const struct invariant_entry invariant_list
[] = {
6190 { X(LOCALE_ILANGUAGE
), "007f" },
6191 { X(LOCALE_SENGLANGUAGE
), "Invariant Language" },
6192 { X(LOCALE_SABBREVLANGNAME
), "IVL" },
6193 { X(LOCALE_SNATIVELANGNAME
), "Invariant Language" },
6194 { X(LOCALE_ICOUNTRY
), "1" },
6195 { X(LOCALE_SENGCOUNTRY
), "Invariant Country" },
6196 { X(LOCALE_SABBREVCTRYNAME
), "IVC", "" },
6197 { X(LOCALE_SNATIVECTRYNAME
), "Invariant Country" },
6198 { X(LOCALE_IDEFAULTLANGUAGE
), "0409" },
6199 { X(LOCALE_IDEFAULTCOUNTRY
), "1" },
6200 { X(LOCALE_IDEFAULTCODEPAGE
), "437" },
6201 { X(LOCALE_IDEFAULTANSICODEPAGE
), "1252" },
6202 { X(LOCALE_IDEFAULTMACCODEPAGE
), "10000" },
6203 { X(LOCALE_SLIST
), "," },
6204 { X(LOCALE_IMEASURE
), "0" },
6205 { X(LOCALE_SDECIMAL
), "." },
6206 { X(LOCALE_STHOUSAND
), "," },
6207 { X(LOCALE_SGROUPING
), "3;0" },
6208 { X(LOCALE_IDIGITS
), "2" },
6209 { X(LOCALE_ILZERO
), "1" },
6210 { X(LOCALE_INEGNUMBER
), "1" },
6211 { X(LOCALE_SNATIVEDIGITS
), "0123456789" },
6212 { X(LOCALE_SCURRENCY
), "\x00a4" },
6213 { X(LOCALE_SINTLSYMBOL
), "XDR" },
6214 { X(LOCALE_SMONDECIMALSEP
), "." },
6215 { X(LOCALE_SMONTHOUSANDSEP
), "," },
6216 { X(LOCALE_SMONGROUPING
), "3;0" },
6217 { X(LOCALE_ICURRDIGITS
), "2" },
6218 { X(LOCALE_IINTLCURRDIGITS
), "2" },
6219 { X(LOCALE_ICURRENCY
), "0" },
6220 { X(LOCALE_INEGCURR
), "0" },
6221 { X(LOCALE_SDATE
), "/" },
6222 { X(LOCALE_STIME
), ":" },
6223 { X(LOCALE_SSHORTDATE
), "MM/dd/yyyy" },
6224 { X(LOCALE_SLONGDATE
), "dddd, dd MMMM yyyy" },
6225 { X(LOCALE_STIMEFORMAT
), "HH:mm:ss" },
6226 { X(LOCALE_IDATE
), "0" },
6227 { X(LOCALE_ILDATE
), "1" },
6228 { X(LOCALE_ITIME
), "1" },
6229 { X(LOCALE_ITIMEMARKPOSN
), "0" },
6230 { X(LOCALE_ICENTURY
), "1" },
6231 { X(LOCALE_ITLZERO
), "1" },
6232 { X(LOCALE_IDAYLZERO
), "1" },
6233 { X(LOCALE_IMONLZERO
), "1" },
6234 { X(LOCALE_S1159
), "AM" },
6235 { X(LOCALE_S2359
), "PM" },
6236 { X(LOCALE_ICALENDARTYPE
), "1" },
6237 { X(LOCALE_IOPTIONALCALENDAR
), "0" },
6238 { X(LOCALE_IFIRSTDAYOFWEEK
), "6" },
6239 { X(LOCALE_IFIRSTWEEKOFYEAR
), "0" },
6240 { X(LOCALE_SDAYNAME1
), "Monday" },
6241 { X(LOCALE_SDAYNAME2
), "Tuesday" },
6242 { X(LOCALE_SDAYNAME3
), "Wednesday" },
6243 { X(LOCALE_SDAYNAME4
), "Thursday" },
6244 { X(LOCALE_SDAYNAME5
), "Friday" },
6245 { X(LOCALE_SDAYNAME6
), "Saturday" },
6246 { X(LOCALE_SDAYNAME7
), "Sunday" },
6247 { X(LOCALE_SABBREVDAYNAME1
), "Mon" },
6248 { X(LOCALE_SABBREVDAYNAME2
), "Tue" },
6249 { X(LOCALE_SABBREVDAYNAME3
), "Wed" },
6250 { X(LOCALE_SABBREVDAYNAME4
), "Thu" },
6251 { X(LOCALE_SABBREVDAYNAME5
), "Fri" },
6252 { X(LOCALE_SABBREVDAYNAME6
), "Sat" },
6253 { X(LOCALE_SABBREVDAYNAME7
), "Sun" },
6254 { X(LOCALE_SMONTHNAME1
), "January" },
6255 { X(LOCALE_SMONTHNAME2
), "February" },
6256 { X(LOCALE_SMONTHNAME3
), "March" },
6257 { X(LOCALE_SMONTHNAME4
), "April" },
6258 { X(LOCALE_SMONTHNAME5
), "May" },
6259 { X(LOCALE_SMONTHNAME6
), "June" },
6260 { X(LOCALE_SMONTHNAME7
), "July" },
6261 { X(LOCALE_SMONTHNAME8
), "August" },
6262 { X(LOCALE_SMONTHNAME9
), "September" },
6263 { X(LOCALE_SMONTHNAME10
), "October" },
6264 { X(LOCALE_SMONTHNAME11
), "November" },
6265 { X(LOCALE_SMONTHNAME12
), "December" },
6266 { X(LOCALE_SMONTHNAME13
), "" },
6267 { X(LOCALE_SABBREVMONTHNAME1
), "Jan" },
6268 { X(LOCALE_SABBREVMONTHNAME2
), "Feb" },
6269 { X(LOCALE_SABBREVMONTHNAME3
), "Mar" },
6270 { X(LOCALE_SABBREVMONTHNAME4
), "Apr" },
6271 { X(LOCALE_SABBREVMONTHNAME5
), "May" },
6272 { X(LOCALE_SABBREVMONTHNAME6
), "Jun" },
6273 { X(LOCALE_SABBREVMONTHNAME7
), "Jul" },
6274 { X(LOCALE_SABBREVMONTHNAME8
), "Aug" },
6275 { X(LOCALE_SABBREVMONTHNAME9
), "Sep" },
6276 { X(LOCALE_SABBREVMONTHNAME10
), "Oct" },
6277 { X(LOCALE_SABBREVMONTHNAME11
), "Nov" },
6278 { X(LOCALE_SABBREVMONTHNAME12
), "Dec" },
6279 { X(LOCALE_SABBREVMONTHNAME13
), "" },
6280 { X(LOCALE_SPOSITIVESIGN
), "+" },
6281 { X(LOCALE_SNEGATIVESIGN
), "-" },
6282 { X(LOCALE_IPOSSIGNPOSN
), "3" },
6283 { X(LOCALE_INEGSIGNPOSN
), "0" },
6284 { X(LOCALE_IPOSSYMPRECEDES
), "1" },
6285 { X(LOCALE_IPOSSEPBYSPACE
), "0" },
6286 { X(LOCALE_INEGSYMPRECEDES
), "1" },
6287 { X(LOCALE_INEGSEPBYSPACE
), "0" },
6288 { X(LOCALE_SISO639LANGNAME
), "iv" },
6289 { X(LOCALE_SISO3166CTRYNAME
), "IV" },
6290 { X(LOCALE_IDEFAULTEBCDICCODEPAGE
), "037" },
6291 { X(LOCALE_IPAPERSIZE
), "9" },
6292 { X(LOCALE_SENGCURRNAME
), "International Monetary Fund" },
6293 { X(LOCALE_SNATIVECURRNAME
), "International Monetary Fund" },
6294 { X(LOCALE_SYEARMONTH
), "yyyy MMMM" },
6295 { X(LOCALE_IDIGITSUBSTITUTION
), "1" },
6296 { X(LOCALE_SNAME
), "" },
6297 { X(LOCALE_SSCRIPTS
), "Latn;" },
6302 static void test_invariant(void)
6306 char buffer
[BUFFER_SIZE
];
6307 const struct invariant_entry
*ptr
= invariant_list
;
6309 if (!GetLocaleInfoA(LOCALE_INVARIANT
, NUO
|LOCALE_SLANGUAGE
, buffer
, sizeof(buffer
)))
6311 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
6317 ret
= GetLocaleInfoA(LOCALE_INVARIANT
, NUO
|ptr
->id
, buffer
, sizeof(buffer
));
6318 if (!ret
&& (ptr
->id
== LOCALE_SNAME
|| ptr
->id
== LOCALE_SSCRIPTS
))
6319 win_skip("not supported\n"); /* winxp/win2k3 */
6322 len
= strlen(ptr
->expect
)+1; /* include \0 */
6323 ok(ret
== len
|| (ptr
->expect2
&& ret
== strlen(ptr
->expect2
)+1),
6324 "For id %d, expected ret == %d, got %d, error %ld\n",
6325 ptr
->id
, len
, ret
, GetLastError());
6326 ok(!strcmp(buffer
, ptr
->expect
) || (ptr
->expect2
&& !strcmp(buffer
, ptr
->expect2
)),
6327 "For id %d, Expected %s, got '%s'\n",
6328 ptr
->id
, ptr
->expect
, buffer
);
6334 if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
)) ||
6335 (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
)))
6337 skip("Non US-English locale\n");
6341 /* some locales translate these */
6342 static const char lang
[] = "Invariant Language (Invariant Country)";
6343 static const char cntry
[] = "Invariant Country";
6344 static const char sortm
[] = "Math Alphanumerics";
6345 static const char sortms
[] = "Maths Alphanumerics";
6346 static const char sortd
[] = "Default"; /* win2k3 */
6348 ret
= GetLocaleInfoA(LOCALE_INVARIANT
, NUO
|LOCALE_SLANGUAGE
, buffer
, sizeof(buffer
));
6349 len
= lstrlenA(lang
) + 1;
6350 ok(ret
== len
, "Expected ret == %d, got %d, error %ld\n", len
, ret
, GetLastError());
6351 ok(!strcmp(buffer
, lang
), "Expected %s, got '%s'\n", lang
, buffer
);
6353 ret
= GetLocaleInfoA(LOCALE_INVARIANT
, NUO
|LOCALE_SCOUNTRY
, buffer
, sizeof(buffer
));
6354 len
= lstrlenA(cntry
) + 1;
6355 ok(ret
== len
, "Expected ret == %d, got %d, error %ld\n", len
, ret
, GetLastError());
6356 ok(!strcmp(buffer
, cntry
), "Expected %s, got '%s'\n", cntry
, buffer
);
6358 ret
= GetLocaleInfoA(LOCALE_INVARIANT
, NUO
|LOCALE_SSORTNAME
, buffer
, sizeof(buffer
));
6359 ok(ret
, "Failed err %ld\n", GetLastError());
6360 ok(!strcmp(buffer
, sortm
) || !strcmp(buffer
, sortd
) || !strcmp(buffer
, sortms
), "Got '%s'\n", buffer
);
6364 static void test_GetSystemPreferredUILanguages(void)
6368 ULONG i
, count
, size
, size_id
, size_name
, size_buffer
;
6371 if (!pGetSystemPreferredUILanguages
)
6373 win_skip("GetSystemPreferredUILanguages is not available.\n");
6377 /* (in)valid first parameter */
6380 SetLastError(0xdeadbeef);
6381 ret
= pGetSystemPreferredUILanguages(0, &count
, NULL
, &size
);
6382 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6383 ok(count
, "Expected count > 0\n");
6384 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6387 SetLastError(0xdeadbeef);
6388 ret
= pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE
, &count
, NULL
, &size
);
6389 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6390 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6391 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6394 SetLastError(0xdeadbeef);
6395 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
| MUI_FULL_LANGUAGE
, &count
, NULL
, &size
);
6396 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6397 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6398 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6401 SetLastError(0xdeadbeef);
6402 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
| MUI_LANGUAGE_NAME
, &count
, NULL
, &size
);
6403 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6404 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6405 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6409 SetLastError(0xdeadbeef);
6410 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
| MUI_MACHINE_LANGUAGE_SETTINGS
, &count
, NULL
, &size
);
6411 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6412 ok(count
, "Expected count > 0\n");
6413 ok(size
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size
);
6417 SetLastError(0xdeadbeef);
6418 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME
| MUI_MACHINE_LANGUAGE_SETTINGS
, &count
, NULL
, &size
);
6419 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6420 ok(count
, "Expected count > 0\n");
6421 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6424 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
6425 * -> unhandled exception c0000005
6428 /* invalid third parameter */
6430 SetLastError(0xdeadbeef);
6431 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size
);
6432 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6433 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6434 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6437 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
6438 * -> unhandled exception c0000005
6443 SetLastError(0xdeadbeef);
6444 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size_id
);
6445 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6446 ok(count
, "Expected count > 0\n");
6447 ok(size_id
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id
);
6451 SetLastError(0xdeadbeef);
6452 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME
, &count
, NULL
, &size_name
);
6453 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6454 ok(count
, "Expected count > 0\n");
6455 ok(size_name
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name
);
6457 size_buffer
= max(size_id
, size_name
);
6460 skip("No valid buffer size\n");
6464 buffer
= HeapAlloc(GetProcessHeap(), 0, size_buffer
* sizeof(WCHAR
));
6467 skip("Failed to allocate memory for %ld chars\n", size_buffer
);
6473 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6474 SetLastError(0xdeadbeef);
6475 ret
= pGetSystemPreferredUILanguages(0, &count
, buffer
, &size
);
6476 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6477 ok(count
, "Expected count > 0\n");
6478 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6479 if (ret
&& size
% 6 == 1)
6480 ok(!buffer
[size
-2] && !buffer
[size
-1],
6481 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6482 buffer
[size
-2], buffer
[size
-1]);
6486 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6487 SetLastError(0xdeadbeef);
6488 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6489 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6490 ok(count
, "Expected count > 0\n");
6491 ok(size
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size
);
6492 if (ret
&& size
% 5 == 1)
6493 ok(!buffer
[size
-2] && !buffer
[size
-1],
6494 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6495 buffer
[size
-2], buffer
[size
-1]);
6496 for (i
= 0; buffer
[i
]; i
++)
6497 ok(('0' <= buffer
[i
] && buffer
[i
] <= '9') ||
6498 ('A' <= buffer
[i
] && buffer
[i
] <= 'F'),
6499 "MUI_LANGUAGE_ID [%ld] is bad in %s\n", i
, wine_dbgstr_w(buffer
));
6503 SetLastError(0xdeadbeef);
6504 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME
, &count
, buffer
, &size
);
6505 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6506 ok(count
, "Expected count > 0\n");
6507 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6508 if (ret
&& size
% 5 == 1)
6509 ok(!buffer
[size
-2] && !buffer
[size
-1],
6510 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6511 buffer
[size
-2], buffer
[size
-1]);
6515 SetLastError(0xdeadbeef);
6516 ret
= pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS
, &count
, NULL
, &size
);
6517 ok(ret
, "Expected GetSystemPreferredUILanguages to succeed\n");
6518 ok(count
, "Expected count > 0\n");
6519 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6520 if (ret
&& size
% 6 == 1)
6521 ok(!buffer
[size
-2] && !buffer
[size
-1],
6522 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6523 buffer
[size
-2], buffer
[size
-1]);
6525 /* ntdll version is the same, but apparently takes an extra second parameter */
6528 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6529 status
= pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, 0, &count
, buffer
, &size
);
6530 ok(!status
, "got %lx\n", status
);
6531 ok(count
, "Expected count > 0\n");
6532 ok(size
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size
);
6533 if (ret
&& size
% 5 == 1)
6534 ok(!buffer
[size
-2] && !buffer
[size
-1],
6535 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6536 buffer
[size
-2], buffer
[size
-1]);
6540 status
= pRtlGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME
, 0, &count
, buffer
, &size
);
6541 ok(!status
, "got %lx\n", status
);
6542 ok(count
, "Expected count > 0\n");
6543 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6544 if (ret
&& size
% 5 == 1)
6545 ok(!buffer
[size
-2] && !buffer
[size
-1],
6546 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6547 buffer
[size
-2], buffer
[size
-1]);
6551 status
= pRtlGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS
, 0, &count
, NULL
, &size
);
6552 ok(!status
, "got %lx\n", status
);
6553 ok(count
, "Expected count > 0\n");
6554 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6555 if (ret
&& size
% 6 == 1)
6556 ok(!buffer
[size
-2] && !buffer
[size
-1],
6557 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6558 buffer
[size
-2], buffer
[size
-1]);
6561 SetLastError(0xdeadbeef);
6562 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6563 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6564 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6565 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6566 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6569 SetLastError(0xdeadbeef);
6570 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6571 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6572 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6573 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6574 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6577 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6578 SetLastError(0xdeadbeef);
6579 ret
= pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6580 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6581 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6582 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6583 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6586 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6587 SetLastError(0xdeadbeef);
6588 ret
= pGetSystemPreferredUILanguages(0, &count
, buffer
, &size
);
6589 ok(!ret
, "Expected GetSystemPreferredUILanguages to fail\n");
6590 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6591 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6592 ok(size
== size_id
+ 2 || size
== size_id
+ 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id
+ 2, size
);
6594 HeapFree(GetProcessHeap(), 0, buffer
);
6597 static void test_GetThreadPreferredUILanguages(void)
6601 ULONG count
, size
, size_id
;
6604 if (!pGetThreadPreferredUILanguages
)
6606 win_skip("GetThreadPreferredUILanguages is not available.\n");
6611 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
|MUI_UI_FALLBACK
, &count
, NULL
, &size
);
6612 ok(ret
, "got %lu\n", GetLastError());
6613 ok(count
, "expected count > 0\n");
6614 ok(size
, "expected size > 0\n");
6617 buf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
* sizeof(WCHAR
));
6618 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
|MUI_UI_FALLBACK
, &count
, buf
, &size
);
6619 ok(ret
, "got %lu\n", GetLastError());
6620 ok(count
, "expected count > 0\n");
6622 size_id
= count
= 0;
6623 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size_id
);
6624 ok(ret
, "got %lu\n", GetLastError());
6625 ok(count
, "expected count > 0\n");
6626 ok(size_id
, "expected size > 0\n");
6627 ok(size_id
<= size
, "expected size > 0\n");
6629 /* ntdll function is the same */
6630 size_id
= count
= 0;
6631 status
= pRtlGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size_id
);
6632 ok(!status
, "got %lx\n", status
);
6633 ok(count
, "expected count > 0\n");
6634 ok(size_id
, "expected size > 0\n");
6635 ok(size_id
<= size
, "expected size > 0\n");
6638 SetLastError(0xdeadbeef);
6639 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buf
, &size
);
6640 ok(!ret
, "Expected GetThreadPreferredUILanguages to fail\n");
6641 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
6642 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6643 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6646 SetLastError(0xdeadbeef);
6647 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buf
, &size
);
6648 ok(!ret
, "Expected GetThreadPreferredUILanguages to fail\n");
6649 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
6650 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6651 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6654 SetLastError(0xdeadbeef);
6655 ret
= pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buf
, &size
);
6656 ok(!ret
, "Expected GetThreadPreferredUILanguages to fail\n");
6657 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
6658 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6659 ok(size
== size_id
, "expected %lu, got %lu\n", size_id
, size
);
6662 SetLastError(0xdeadbeef);
6663 ret
= pGetThreadPreferredUILanguages(0, &count
, buf
, &size
);
6664 ok(!ret
, "Expected GetThreadPreferredUILanguages to fail\n");
6665 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
,
6666 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6668 ok(size
== size_id
|| size
== size_id
- 1 /* before win10 1809 */, "expected %lu, got %lu\n", size_id
, size
);
6670 HeapFree(GetProcessHeap(), 0, buf
);
6673 static void test_GetUserPreferredUILanguages(void)
6677 ULONG count
, size
, size_id
, size_name
, size_buffer
;
6680 if (!pGetUserPreferredUILanguages
)
6682 win_skip("GetUserPreferredUILanguages is not available.\n");
6687 SetLastError(0xdeadbeef);
6688 ret
= pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE
, &count
, NULL
, &size
);
6689 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6690 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6691 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6694 SetLastError(0xdeadbeef);
6695 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
| MUI_FULL_LANGUAGE
, &count
, NULL
, &size
);
6696 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6697 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6698 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6701 SetLastError(0xdeadbeef);
6702 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
| MUI_MACHINE_LANGUAGE_SETTINGS
, &count
, NULL
, &size
);
6703 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6704 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6705 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6708 SetLastError(0xdeadbeef);
6709 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size
);
6710 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6711 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6712 "Expected error ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
6716 SetLastError(0xdeadbeef);
6717 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, NULL
, &size_id
);
6718 ok(ret
, "Expected GetUserPreferredUILanguages to succeed\n");
6719 ok(count
, "Expected count > 0\n");
6720 ok(size_id
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id
);
6724 SetLastError(0xdeadbeef);
6725 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME
, &count
, NULL
, &size_name
);
6726 ok(ret
, "Expected GetUserPreferredUILanguages to succeed\n");
6727 ok(count
, "Expected count > 0\n");
6728 ok(size_name
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size_name
);
6730 size_buffer
= max(size_id
, size_name
);
6733 skip("No valid buffer size\n");
6737 /* ntdll version is the same, but apparently takes an extra second parameter */
6740 SetLastError(0xdeadbeef);
6741 status
= pRtlGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, 0, &count
, NULL
, &size_id
);
6742 ok(!status
, "got %lx\n", status
);
6743 ok(count
, "Expected count > 0\n");
6744 ok(size_id
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size_id
);
6746 buffer
= HeapAlloc(GetProcessHeap(), 0, size_buffer
* sizeof(WCHAR
));
6750 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6751 SetLastError(0xdeadbeef);
6752 ret
= pGetUserPreferredUILanguages(0, &count
, buffer
, &size
);
6753 ok(ret
, "Expected GetUserPreferredUILanguages to succeed\n");
6754 ok(count
, "Expected count > 0\n");
6755 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6756 if (ret
&& size
% 6 == 1)
6757 ok(!buffer
[size
-2] && !buffer
[size
-1],
6758 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6759 buffer
[size
-2], buffer
[size
-1]);
6763 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6764 SetLastError(0xdeadbeef);
6765 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6766 ok(ret
, "Expected GetUserPreferredUILanguages to succeed\n");
6767 ok(count
, "Expected count > 0\n");
6768 ok(size
% 5 == 1, "Expected size (%ld) %% 5 == 1\n", size
);
6769 if (ret
&& size
% 5 == 1)
6770 ok(!buffer
[size
-2] && !buffer
[size
-1],
6771 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6772 buffer
[size
-2], buffer
[size
-1]);
6776 SetLastError(0xdeadbeef);
6777 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME
, &count
, buffer
, &size
);
6778 ok(ret
, "Expected GetUserPreferredUILanguages to succeed\n");
6779 ok(count
, "Expected count > 0\n");
6780 ok(size
% 6 == 1, "Expected size (%ld) %% 6 == 1\n", size
);
6781 if (ret
&& size
% 5 == 1)
6782 ok(!buffer
[size
-2] && !buffer
[size
-1],
6783 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
6784 buffer
[size
-2], buffer
[size
-1]);
6787 SetLastError(0xdeadbeef);
6788 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6789 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6790 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6791 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6794 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6795 SetLastError(0xdeadbeef);
6796 ret
= pGetUserPreferredUILanguages(MUI_LANGUAGE_ID
, &count
, buffer
, &size
);
6797 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6798 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6799 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6803 memset(buffer
, 0x5a, size_buffer
* sizeof(WCHAR
));
6804 SetLastError(0xdeadbeef);
6805 ret
= pGetUserPreferredUILanguages(0, &count
, buffer
, &size
);
6806 ok(!ret
, "Expected GetUserPreferredUILanguages to fail\n");
6807 ok(ERROR_INSUFFICIENT_BUFFER
== GetLastError(),
6808 "Expected error ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError());
6810 HeapFree(GetProcessHeap(), 0, buffer
);
6813 static void test_FindNLSStringEx(void)
6816 static const WCHAR comb_s_accent1W
[] = {0x1e69, 'o','u','r','c','e',0};
6817 static const WCHAR comb_s_accent2W
[] = {0x0073,0x323,0x307,'o','u','r','c','e',0};
6818 static const WCHAR comb_q_accent1W
[] = {'a','b',0x0071,0x0307,0x323,'u','o','t','e','\n',0};
6819 static const WCHAR comb_q_accent2W
[] = {0x0071,0x0323,0x307,'u','o','t','e',0};
6821 const WCHAR
*locale
;
6829 static struct test_data tests
[] =
6831 { localeW
, FIND_FROMSTART
, L
"SimpleSimple", L
"Simple", 0, 6},
6832 { localeW
, FIND_FROMEND
, L
"SimpleSimple", L
"Simp", 6, 4},
6833 { localeW
, FIND_STARTSWITH
, L
"SimpleSimple", L
"Simp", 0, 4},
6834 { localeW
, FIND_ENDSWITH
, L
"SimpleSimple", L
"Simple", 6, 6},
6835 { localeW
, FIND_ENDSWITH
, L
"SimpleSimple", L
"Simp", -1, 0xdeadbeef},
6836 { localeW
, FIND_FROMSTART
, comb_s_accent1W
, comb_s_accent2W
, 0, 6 },
6837 { localeW
, FIND_FROMSTART
, comb_q_accent1W
, comb_q_accent2W
, 2, 7 },
6838 { localeW
, FIND_STARTSWITH
, L
"--Option", L
"--", 0, 2},
6839 { localeW
, FIND_ENDSWITH
, L
"Option--", L
"--", 6, 2},
6840 { localeW
, FIND_FROMSTART
, L
"----", L
"--", 0, 2},
6841 { localeW
, FIND_FROMEND
, L
"----", L
"--", 2, 2},
6842 { localeW
, FIND_FROMSTART
, L
"opt1--opt2--opt3", L
"--", 4, 2},
6843 { localeW
, FIND_FROMEND
, L
"opt1--opt2--opt3", L
"--", 10, 2},
6844 { localeW
, FIND_FROMSTART
, L
"x-oss-security", L
"x-oss-", 0, 6},
6845 { localeW
, FIND_FROMSTART
, L
"x-oss-security", L
"-oss", 1, 4},
6846 { localeW
, FIND_FROMSTART
, L
"x-oss-security", L
"-oss--", -1, 0xdeadbeef},
6847 { localeW
, FIND_FROMEND
, L
"x-oss-oss2", L
"-oss", 5, 4},
6851 if (!pFindNLSStringEx
)
6853 win_skip("FindNLSStringEx is not available.\n");
6857 SetLastError( 0xdeadbeef );
6858 res
= pFindNLSStringEx(invalidW
, FIND_FROMSTART
, fooW
, 3, fooW
,
6859 3, NULL
, NULL
, NULL
, 0);
6860 ok(res
, "Expected failure of FindNLSStringEx. Return value was %d\n", res
);
6861 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6862 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
6864 SetLastError( 0xdeadbeef );
6865 res
= pFindNLSStringEx(localeW
, FIND_FROMSTART
, NULL
, 3, fooW
, 3,
6866 NULL
, NULL
, NULL
, 0);
6867 ok(res
, "Expected failure of FindNLSStringEx. Return value was %d\n", res
);
6868 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6869 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
6871 SetLastError( 0xdeadbeef );
6872 res
= pFindNLSStringEx(localeW
, FIND_FROMSTART
, fooW
, -5, fooW
, 3,
6873 NULL
, NULL
, NULL
, 0);
6874 ok(res
, "Expected failure of FindNLSStringEx. Return value was %d\n", res
);
6875 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6876 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
6878 SetLastError( 0xdeadbeef );
6879 res
= pFindNLSStringEx(localeW
, FIND_FROMSTART
, fooW
, 3, NULL
, 3,
6880 NULL
, NULL
, NULL
, 0);
6881 ok(res
, "Expected failure of FindNLSStringEx. Return value was %d\n", res
);
6882 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6883 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
6885 SetLastError( 0xdeadbeef );
6886 res
= pFindNLSStringEx(localeW
, FIND_FROMSTART
, fooW
, 3, fooW
, -5,
6887 NULL
, NULL
, NULL
, 0);
6888 ok(res
, "Expected failure of FindNLSStringEx. Return value was %d\n", res
);
6889 ok(ERROR_INVALID_PARAMETER
== GetLastError(),
6890 "Expected ERROR_INVALID_PARAMETER as last error; got %ld\n", GetLastError());
6892 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
6894 int found
= 0xdeadbeef;
6895 res
= pFindNLSStringEx(tests
[i
].locale
, tests
[i
].flags
, tests
[i
].src
, -1,
6896 tests
[i
].value
, -1, &found
, NULL
, NULL
, 0);
6897 ok(res
== tests
[i
].expected_ret
,
6898 "%u: Expected FindNLSStringEx to return %d. Returned value was %d\n", i
,
6899 tests
[i
].expected_ret
, res
);
6900 ok(found
== tests
[i
].expected_found
,
6901 "%u: Expected FindNLSStringEx to output %d. Value was %d\n", i
,
6902 tests
[i
].expected_found
, found
);
6906 static void test_FindStringOrdinal(void)
6908 static const WCHAR abc123aBcW
[] = {'a', 'b', 'c', '1', '2', '3', 'a', 'B', 'c', 0};
6909 static const WCHAR abcW
[] = {'a', 'b', 'c', 0};
6910 static const WCHAR aBcW
[] = {'a', 'B', 'c', 0};
6911 static const WCHAR aaaW
[] = {'a', 'a', 'a', 0};
6926 {1, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1, ERROR_INVALID_FLAGS
},
6927 {FIND_FROMSTART
, NULL
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1,
6928 ERROR_INVALID_PARAMETER
},
6929 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, NULL
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1,
6930 ERROR_INVALID_PARAMETER
},
6931 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, NULL
, 0, FALSE
, -1, ERROR_INVALID_PARAMETER
},
6932 {FIND_FROMSTART
, NULL
, 0, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1, ERROR_INVALID_PARAMETER
},
6933 {FIND_FROMSTART
, NULL
, 0, NULL
, 0, FALSE
, -1, ERROR_INVALID_PARAMETER
},
6934 /* Case-insensitive */
6935 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, 0, NO_ERROR
},
6936 {FIND_FROMEND
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, 0, NO_ERROR
},
6937 {FIND_STARTSWITH
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, 0, NO_ERROR
},
6938 {FIND_ENDSWITH
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1, NO_ERROR
},
6939 /* Case-sensitive */
6940 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, aBcW
, ARRAY_SIZE(aBcW
) - 1, TRUE
, 0, NO_ERROR
},
6941 {FIND_FROMEND
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, aBcW
, ARRAY_SIZE(aBcW
) - 1, TRUE
, 6, NO_ERROR
},
6942 {FIND_STARTSWITH
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, aBcW
, ARRAY_SIZE(aBcW
) - 1, TRUE
, 0, NO_ERROR
},
6943 {FIND_ENDSWITH
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, aBcW
, ARRAY_SIZE(aBcW
) - 1, TRUE
, 6, NO_ERROR
},
6945 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, aaaW
, ARRAY_SIZE(aaaW
) - 1, FALSE
, -1, NO_ERROR
},
6946 {FIND_FROMSTART
, abc123aBcW
, -1, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, 0, NO_ERROR
},
6947 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, -1, FALSE
, 0, NO_ERROR
},
6948 {FIND_FROMSTART
, abc123aBcW
, 0, abcW
, ARRAY_SIZE(abcW
) - 1, FALSE
, -1, NO_ERROR
},
6949 {FIND_FROMSTART
, abc123aBcW
, ARRAY_SIZE(abc123aBcW
) - 1, abcW
, 0, FALSE
, 0, NO_ERROR
},
6950 {FIND_FROMSTART
, abc123aBcW
, 0, abcW
, 0, FALSE
, 0, NO_ERROR
},
6956 if (!pFindStringOrdinal
)
6958 win_skip("FindStringOrdinal is not available.\n");
6962 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
6964 SetLastError(0xdeadbeef);
6965 ret
= pFindStringOrdinal(tests
[i
].flag
, tests
[i
].src
, tests
[i
].src_size
, tests
[i
].val
, tests
[i
].val_size
,
6966 tests
[i
].ignore_case
);
6967 err
= GetLastError();
6968 ok(ret
== tests
[i
].ret
, "Item %d expected %d, got %d\n", i
, tests
[i
].ret
, ret
);
6969 ok(err
== tests
[i
].err
, "Item %d expected %#lx, got %#lx\n", i
, tests
[i
].err
, err
);
6973 static void test_SetThreadUILanguage(void)
6977 if (!pGetThreadUILanguage
)
6979 win_skip("GetThreadUILanguage isn't implemented, skipping SetThreadUILanguage tests for version < Vista\n");
6980 return; /* BTW SetThreadUILanguage is present on winxp/2003 but doesn`t set the LANGID anyway when tested */
6983 res
= pSetThreadUILanguage(0);
6984 ok(res
== pGetThreadUILanguage(), "expected %d got %d\n", pGetThreadUILanguage(), res
);
6986 res
= pSetThreadUILanguage(MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
));
6987 ok(res
== MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
),
6988 "expected %d got %d\n", MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
), res
);
6990 res
= pSetThreadUILanguage(0);
6991 todo_wine
ok(res
== MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
),
6992 "expected %d got %d\n", MAKELANGID(LANG_DUTCH
, SUBLANG_DUTCH_BELGIAN
), res
);
6995 /* read a Unicode string from NormalizationTest.txt format; helper for test_NormalizeString */
6996 static int read_str( char *str
, WCHAR res
[32] )
7001 while (*str
&& pos
< 31)
7003 unsigned int c
= strtoul( str
, &end
, 16 );
7004 pos
+= put_utf16( res
+ pos
, c
);
7005 while (*end
== ' ') end
++;
7012 static void test_NormalizeString(void)
7014 /* part 0: specific cases */
7015 /* LATIN CAPITAL LETTER D WITH DOT ABOVE */
7016 static const WCHAR part0_str1
[] = {0x1e0a,0};
7017 static const WCHAR part0_nfd1
[] = {0x0044,0x0307,0};
7019 /* LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7020 static const WCHAR part0_str2
[] = {0x0044,0x0323,0x0307,0};
7021 static const WCHAR part0_nfc2
[] = {0x1e0c,0x0307,0};
7023 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7024 static const WCHAR part0_str3
[] = {0x0044,0x031b,0x0323,0x0307,0};
7025 static const WCHAR part0_nfc3
[] = {0x1e0c,0x031b,0x0307,0};
7027 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
7028 static const WCHAR part0_str4
[] = {0x0044,0x031b,0x0323,0x0307,0};
7029 static const WCHAR part0_nfc4
[] = {0x1e0c,0x031b,0x0307,0};
7032 * HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ,
7033 * HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ,
7034 * HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI
7036 static const WCHAR part0_str5
[] = {0x0592,0x05B7,0x05BC,0x05A5,0x05B0,0x05C0,0x05C4,0x05AD,0};
7037 static const WCHAR part0_nfc5
[] = {0x05B0,0x05B7,0x05BC,0x05A5,0x0592,0x05C0,0x05AD,0x05C4,0};
7040 * HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL,
7041 * HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,
7042 * HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA
7044 static const WCHAR part0_str6
[] = {0x05B8,0x05B9,0x05B1,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
7045 static const WCHAR part0_nfc6
[] = {0x05B1,0x05B8,0x05B9,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
7047 /* LATIN CAPITAL LETTER D WITH DOT BELOW */
7048 static const WCHAR part0_str8
[] = {0x1E0C,0};
7049 static const WCHAR part0_nfd8
[] = {0x0044,0x0323,0};
7051 /* LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW */
7052 static const WCHAR part0_str9
[] = {0x1E0A,0x0323,0};
7053 static const WCHAR part0_nfc9
[] = {0x1E0C,0x0307,0};
7054 static const WCHAR part0_nfd9
[] = {0x0044,0x0323,0x0307,0};
7056 /* LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE */
7057 static const WCHAR part0_str10
[] = {0x1E0C,0x0307,0};
7058 static const WCHAR part0_nfd10
[] = {0x0044,0x0323,0x0307,0};
7060 /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON */
7061 static const WCHAR part0_str11
[] = {0x1E14,0x0304,0};
7062 static const WCHAR part0_nfd11
[] = {0x0045,0x0304,0x0300,0x0304,0};
7064 /* LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT */
7065 static const WCHAR part0_str12
[] = {0x0112,0x0300,0};
7066 static const WCHAR part0_nfc12
[] = {0x1E14,0};
7067 static const WCHAR part0_nfd12
[] = {0x0045,0x0304,0x0300,0};
7069 /* part 1: character by character */
7071 static const WCHAR part1_str1
[] = {0x00a8,0};
7072 static const WCHAR part1_nfkc1
[] = {0x0020,0x0308,0};
7074 /* VULGAR FRACTION ONE QUARTER */
7075 static const WCHAR part1_str2
[] = {0x00bc,0};
7076 static const WCHAR part1_nfkc2
[] = {0x0031,0x2044,0x0034,0};
7078 /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
7079 static const WCHAR part1_str3
[] = {0x00ca,0};
7080 static const WCHAR part1_nfd3
[] = {0x0045,0x0302,0};
7082 /* MODIFIER LETTER SMALL GAMMA */
7083 static const WCHAR part1_str4
[] = {0x02e0,0};
7084 static const WCHAR part1_nfkc4
[] = {0x0263,0};
7086 /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */
7087 static const WCHAR part1_str5
[] = {0x0400,0};
7088 static const WCHAR part1_nfd5
[] = {0x0415,0x0300,0};
7090 /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */
7091 static const WCHAR part1_str6
[] = {0x0476,0};
7092 static const WCHAR part1_nfd6
[] = {0x0474,0x030F,0};
7094 /* ARABIC LIGATURE HAH WITH JEEM INITIAL FORM */
7095 static const WCHAR part1_str7
[] = {0xFCA9,0};
7096 static const WCHAR part1_nfkc7
[] = {0x062D,0x062C,0};
7098 /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */
7099 static const WCHAR part1_str8
[] = {0x1F42,0};
7100 static const WCHAR part1_nfd8
[] = {0x03BF,0x0313,0x0300,0};
7102 /* QUADRUPLE PRIME */
7103 static const WCHAR part1_str9
[] = {0x2057,0};
7104 static const WCHAR part1_nfkc9
[] = {0x2032,0x2032,0x2032,0x2032,0};
7106 /* KATAKANA-HIRAGANA VOICED SOUND MARK */
7107 static const WCHAR part1_str10
[] = {0x309B,0};
7108 static const WCHAR part1_nfkc10
[] = {0x20,0x3099,0};
7111 static const WCHAR part1_str11
[] = {0x212B,0};
7112 static const WCHAR part1_nfc11
[] = {0xC5,0};
7113 static const WCHAR part1_nfd11
[] = {'A',0x030A,0};
7115 static const WCHAR composite_src
[] =
7117 0x008a, 0x008e, 0x009a, 0x009e, 0x009f, 0x00c0, 0x00c1, 0x00c2,
7118 0x00c3, 0x00c4, 0x00c5, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb,
7119 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d1, 0x00d2, 0x00d3, 0x00d4,
7120 0x00d5, 0x00d6, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd,
7121 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e7, 0x00e8,
7122 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f1,
7123 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f8, 0x00f9, 0x00fa,
7124 0x00fb, 0x00fc, 0x00fd, 0x00ff, 0x212b
7127 struct test_data_normal
{
7129 const WCHAR
*expected
[4];
7131 static const struct test_data_normal test_arr
[] =
7133 { part0_str1
, { part0_str1
, part0_nfd1
, part0_str1
, part0_nfd1
} },
7134 { part0_str2
, { part0_nfc2
, part0_str2
, part0_nfc2
, part0_str2
} },
7135 { part0_str3
, { part0_nfc3
, part0_str3
, part0_nfc3
, part0_str3
} },
7136 { part0_str4
, { part0_nfc4
, part0_str4
, part0_nfc4
, part0_str4
} },
7137 { part0_str5
, { part0_nfc5
, part0_nfc5
, part0_nfc5
, part0_nfc5
} },
7138 { part0_str6
, { part0_nfc6
, part0_nfc6
, part0_nfc6
, part0_nfc6
} },
7139 { part0_str8
, { part0_str8
, part0_nfd8
, part0_str8
, part0_nfd8
} },
7140 { part0_str9
, { part0_nfc9
, part0_nfd9
, part0_nfc9
, part0_nfd9
} },
7141 { part0_str10
, { part0_str10
, part0_nfd10
, part0_str10
, part0_nfd10
} },
7142 { part0_str11
, { part0_str11
, part0_nfd11
, part0_str11
, part0_nfd11
} },
7143 { part0_str12
, { part0_nfc12
, part0_nfd12
, part0_nfc12
, part0_nfd12
} },
7144 { part1_str1
, { part1_str1
, part1_str1
, part1_nfkc1
, part1_nfkc1
} },
7145 { part1_str2
, { part1_str2
, part1_str2
, part1_nfkc2
, part1_nfkc2
} },
7146 { part1_str3
, { part1_str3
, part1_nfd3
, part1_str3
, part1_nfd3
} },
7147 { part1_str4
, { part1_str4
, part1_str4
, part1_nfkc4
, part1_nfkc4
} },
7148 { part1_str5
, { part1_str5
, part1_nfd5
, part1_str5
, part1_nfd5
} },
7149 { part1_str6
, { part1_str6
, part1_nfd6
, part1_str6
, part1_nfd6
} },
7150 { part1_str7
, { part1_str7
, part1_str7
, part1_nfkc7
, part1_nfkc7
} },
7151 { part1_str8
, { part1_str8
, part1_nfd8
, part1_str8
, part1_nfd8
} },
7152 { part1_str9
, { part1_str9
, part1_str9
, part1_nfkc9
, part1_nfkc9
} },
7153 { part1_str10
, { part1_str10
, part1_str10
, part1_nfkc10
, part1_nfkc10
} },
7154 { part1_str11
, { part1_nfc11
, part1_nfd11
, part1_nfc11
, part1_nfd11
} },
7157 const struct test_data_normal
*ptest
= test_arr
;
7158 const int norm_forms
[] = { NormalizationC
, NormalizationD
, NormalizationKC
, NormalizationKD
};
7162 int dstlen
, str_cmp
, i
, j
;
7165 if (!pNormalizeString
)
7167 win_skip("NormalizeString is not available.\n");
7170 if (!pRtlNormalizeString
) win_skip("RtlNormalizeString is not available.\n");
7173 * For each string, first test passing -1 as srclen to NormalizeString,
7174 * thereby assuming a null-terminating string in src, and then test passing
7175 * explicitly the string length.
7176 * Do that for all 4 normalization forms.
7180 for (i
= 0; i
< 4; i
++)
7182 SetLastError(0xdeadbeef);
7183 dstlen
= pNormalizeString( norm_forms
[i
], ptest
->str
, -1, NULL
, 0 );
7184 ok( dstlen
> lstrlenW(ptest
->str
), "%s:%d: wrong len %d / %d\n",
7185 wine_dbgstr_w(ptest
->str
), i
, dstlen
, lstrlenW(ptest
->str
) );
7186 ok(GetLastError() == ERROR_SUCCESS
, "%s:%d: got error %lu\n",
7187 wine_dbgstr_w(ptest
->str
), i
, GetLastError());
7188 SetLastError(0xdeadbeef);
7189 dstlen
= pNormalizeString( norm_forms
[i
], ptest
->str
, -1, dst
, dstlen
);
7190 ok(GetLastError() == ERROR_SUCCESS
, "%s:%d: got error %lu\n",
7191 wine_dbgstr_w(ptest
->str
), i
, GetLastError());
7192 ok(dstlen
== lstrlenW( dst
)+1, "%s:%d: Copied length differed: was %d, should be %d\n",
7193 wine_dbgstr_w(ptest
->str
), i
, dstlen
, lstrlenW( dst
)+1);
7194 str_cmp
= wcsncmp( ptest
->expected
[i
], dst
, dstlen
+1 );
7195 ok( str_cmp
== 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest
->str
), i
,
7196 wine_dbgstr_w(dst
), wine_dbgstr_w(ptest
->expected
[i
]) );
7198 dstlen
= pNormalizeString( norm_forms
[i
], ptest
->str
, lstrlenW(ptest
->str
), NULL
, 0 );
7199 memset(dst
, 0xcc, sizeof(dst
));
7200 dstlen
= pNormalizeString( norm_forms
[i
], ptest
->str
, lstrlenW(ptest
->str
), dst
, dstlen
);
7201 ok(dstlen
== lstrlenW( ptest
->expected
[i
] ), "%s:%d: Copied length differed: was %d, should be %d\n",
7202 wine_dbgstr_w(ptest
->str
), i
, dstlen
, lstrlenW( dst
));
7203 str_cmp
= wcsncmp( ptest
->expected
[i
], dst
, dstlen
);
7204 ok( str_cmp
== 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest
->str
), i
,
7205 wine_dbgstr_w(dst
), wine_dbgstr_w(ptest
->expected
[i
]) );
7207 if (pRtlNormalizeString
)
7210 status
= pRtlNormalizeString( norm_forms
[i
], ptest
->str
, lstrlenW(ptest
->str
), NULL
, &dstlen
);
7211 ok( !status
, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest
->str
), i
, status
);
7212 ok( dstlen
> lstrlenW(ptest
->str
), "%s:%d: wrong len %d / %d\n",
7213 wine_dbgstr_w(ptest
->str
), i
, dstlen
, lstrlenW(ptest
->str
) );
7214 memset(dst
, 0, sizeof(dst
));
7215 status
= pRtlNormalizeString( norm_forms
[i
], ptest
->str
, lstrlenW(ptest
->str
), dst
, &dstlen
);
7216 ok( !status
, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest
->str
), i
, status
);
7217 ok(dstlen
== lstrlenW( dst
), "%s:%d: Copied length differed: was %d, should be %d\n",
7218 wine_dbgstr_w(ptest
->str
), i
, dstlen
, lstrlenW( dst
));
7219 str_cmp
= wcsncmp( ptest
->expected
[i
], dst
, dstlen
);
7220 ok( str_cmp
== 0, "%s:%d: string incorrect got %s expect %s\n", wine_dbgstr_w(ptest
->str
), i
,
7221 wine_dbgstr_w(dst
), wine_dbgstr_w(ptest
->expected
[i
]) );
7223 status
= pRtlIsNormalizedString( norm_forms
[i
], ptest
->str
, -1, &ret
);
7224 ok( !status
, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest
->str
), i
, status
);
7225 if (!wcscmp( ptest
->str
, dst
))
7226 ok( ret
, "%s:%d: not normalized\n", wine_dbgstr_w(ptest
->str
), i
);
7228 ok( !ret
, "%s:%d: normalized (dst %s)\n", wine_dbgstr_w(ptest
->str
), i
, wine_dbgstr_w(dst
) );
7230 status
= pRtlIsNormalizedString( norm_forms
[i
], dst
, dstlen
, &ret
);
7231 ok( !status
, "%s:%d: failed %lx\n", wine_dbgstr_w(ptest
->str
), i
, status
);
7232 ok( ret
, "%s:%d: not normalized\n", wine_dbgstr_w(ptest
->str
), i
);
7238 /* buffer overflows */
7240 SetLastError(0xdeadbeef);
7241 dstlen
= pNormalizeString( NormalizationD
, part0_str1
, -1, dst
, 1 );
7242 ok( dstlen
<= 0, "wrong len %d\n", dstlen
);
7243 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got error %lu\n", GetLastError());
7245 SetLastError(0xdeadbeef);
7246 dstlen
= pNormalizeString( NormalizationC
, part0_str2
, -1, dst
, 1 );
7247 ok( dstlen
<= 0, "wrong len %d\n", dstlen
);
7248 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got error %lu\n", GetLastError());
7250 SetLastError(0xdeadbeef);
7251 dstlen
= pNormalizeString( NormalizationC
, part0_str2
, -1, NULL
, 0 );
7252 ok( dstlen
== 12, "wrong len %d\n", dstlen
);
7253 ok(GetLastError() == ERROR_SUCCESS
, "got error %lu\n", GetLastError());
7255 SetLastError(0xdeadbeef);
7256 dstlen
= pNormalizeString( NormalizationC
, part0_str2
, -1, dst
, 3 );
7257 ok( dstlen
== 3, "wrong len %d\n", dstlen
);
7258 ok(GetLastError() == ERROR_SUCCESS
, "got error %lu\n", GetLastError());
7260 SetLastError(0xdeadbeef);
7261 dstlen
= pNormalizeString( NormalizationC
, part0_str2
, 0, NULL
, 0 );
7262 ok( dstlen
== 0, "wrong len %d\n", dstlen
);
7263 ok(GetLastError() == ERROR_SUCCESS
, "got error %lu\n", GetLastError());
7265 SetLastError(0xdeadbeef);
7266 dstlen
= pNormalizeString( NormalizationC
, part0_str2
, 0, dst
, 3 );
7267 ok( dstlen
== 0, "wrong len %d\n", dstlen
);
7268 ok(GetLastError() == ERROR_SUCCESS
, "got error %lu\n", GetLastError());
7270 /* size estimations */
7272 memset( dst
, 'A', sizeof(dst
) );
7273 for (j
= 1; j
< ARRAY_SIZE(dst
); j
++)
7275 for (i
= 0; i
< 4; i
++)
7277 int expect
= (i
< 2) ? j
* 3 : j
* 18;
7278 if (expect
> 64) expect
= max( 64, j
+ j
/ 8 );
7279 dstlen
= pNormalizeString( norm_forms
[i
], dst
, j
, NULL
, 0 );
7280 ok( dstlen
== expect
, "%d: %d -> wrong len %d\n", i
, j
, dstlen
);
7281 if (pRtlNormalizeString
)
7284 status
= pRtlNormalizeString( norm_forms
[i
], dst
, j
, NULL
, &dstlen
);
7285 ok( !status
, "%d: failed %lx\n", i
, status
);
7286 ok( dstlen
== expect
, "%d: %d -> wrong len %d\n", i
, j
, dstlen
);
7290 for (i
= 0; i
< 4; i
++)
7292 int srclen
= ARRAY_SIZE( composite_src
);
7293 int expect
= max( 64, srclen
+ srclen
/ 8 );
7294 dstlen
= pNormalizeString( norm_forms
[i
], composite_src
, srclen
, NULL
, 0 );
7295 ok( dstlen
== expect
, "%d: wrong len %d\n", i
, dstlen
);
7296 dstlen
= pNormalizeString( norm_forms
[i
], composite_src
, srclen
, dst
, dstlen
);
7297 if (i
== 0 || i
== 2)
7299 ok( dstlen
== srclen
, "%d: wrong len %d\n", i
, dstlen
);
7300 ok(GetLastError() == ERROR_SUCCESS
, "got error %lu\n", GetLastError());
7304 ok( dstlen
< -expect
, "%d: wrong len %d\n", i
, dstlen
);
7305 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "got error %lu\n", GetLastError());
7307 if (pRtlNormalizeString
)
7310 status
= pRtlNormalizeString( norm_forms
[i
], composite_src
, srclen
, NULL
, &dstlen
);
7311 ok( !status
, "%d: failed %lx\n", i
, status
);
7312 ok( dstlen
== expect
, "%d: wrong len %d\n", i
, dstlen
);
7313 status
= pRtlNormalizeString( norm_forms
[i
], composite_src
, srclen
, dst
, &dstlen
);
7314 if (i
== 0 || i
== 2)
7316 ok( !status
, "%d: failed %lx\n", i
, status
);
7317 ok( dstlen
== srclen
, "%d: wrong len %d\n", i
, dstlen
);
7321 ok( status
== STATUS_BUFFER_TOO_SMALL
, "%d: failed %lx\n", i
, status
);
7322 ok( dstlen
> expect
, "%d: wrong len %d\n", i
, dstlen
);
7327 /* invalid parameters */
7329 for (i
= 0; i
< 32; i
++)
7331 SetLastError(0xdeadbeef);
7332 dstlen
= pNormalizeString( i
, L
"ABC", -1, NULL
, 0 );
7335 case NormalizationC
:
7336 case NormalizationD
:
7337 case NormalizationKC
:
7338 case NormalizationKD
:
7340 ok( dstlen
> 0, "%d: wrong len %d\n", i
, dstlen
);
7341 ok( GetLastError() == ERROR_SUCCESS
, "%d: got error %lu\n", i
, GetLastError());
7344 ok( dstlen
<= 0, "%d: wrong len %d\n", i
, dstlen
);
7345 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "%d: got error %lu\n", i
, GetLastError());
7348 if (pRtlNormalizeString
)
7351 status
= pRtlNormalizeString( i
, L
"ABC", -1, NULL
, &dstlen
);
7355 ok( status
== STATUS_INVALID_PARAMETER
, "%d: failed %lx\n", i
, status
);
7357 case NormalizationC
:
7358 case NormalizationD
:
7359 case NormalizationKC
:
7360 case NormalizationKD
:
7362 ok( status
== STATUS_SUCCESS
, "%d: failed %lx\n", i
, status
);
7365 ok( status
== STATUS_OBJECT_NAME_NOT_FOUND
, "%d: failed %lx\n", i
, status
);
7371 /* invalid sequences */
7373 for (i
= 0; i
< 4; i
++)
7375 dstlen
= pNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, NULL
, 0 );
7376 ok( dstlen
== (i
< 2 ? 15 : 64), "%d: wrong len %d\n", i
, dstlen
);
7377 SetLastError( 0xdeadbeef );
7378 dstlen
= pNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, dst
, ARRAY_SIZE(dst
) );
7379 ok( dstlen
== -3, "%d: wrong len %d\n", i
, dstlen
);
7380 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION
, "%d: wrong error %ld\n", i
, GetLastError() );
7381 dstlen
= pNormalizeString( norm_forms
[i
], L
"ABCD\xdc12Z", -1, NULL
, 0 );
7382 ok( dstlen
== (i
< 2 ? 21 : 64), "%d: wrong len %d\n", i
, dstlen
);
7383 SetLastError( 0xdeadbeef );
7384 dstlen
= pNormalizeString( norm_forms
[i
], L
"ABCD\xdc12Z", -1, dst
, ARRAY_SIZE(dst
) );
7385 ok( dstlen
== -4, "%d: wrong len %d\n", i
, dstlen
);
7386 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION
, "%d: wrong error %ld\n", i
, GetLastError() );
7387 SetLastError( 0xdeadbeef );
7388 dstlen
= pNormalizeString( norm_forms
[i
], L
"ABCD\xdc12Z", -1, dst
, 2 );
7390 ok( dstlen
== (i
< 2 ? -18 : -74), "%d: wrong len %d\n", i
, dstlen
);
7391 todo_wine_if (i
== 0 || i
== 2)
7392 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "%d: wrong error %ld\n", i
, GetLastError() );
7393 if (pRtlNormalizeString
)
7396 status
= pRtlNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, NULL
, &dstlen
);
7397 ok( !status
, "%d: failed %lx\n", i
, status
);
7398 ok( dstlen
== (i
< 2 ? 15 : 64), "%d: wrong len %d\n", i
, dstlen
);
7399 dstlen
= ARRAY_SIZE(dst
);
7400 status
= pRtlNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, dst
, &dstlen
);
7401 ok( status
== STATUS_NO_UNICODE_TRANSLATION
, "%d: failed %lx\n", i
, status
);
7402 ok( dstlen
== 3, "%d: wrong len %d\n", i
, dstlen
);
7404 status
= pRtlNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, dst
, &dstlen
);
7405 todo_wine_if( i
== 0 || i
== 2)
7406 ok( status
== STATUS_BUFFER_TOO_SMALL
, "%d: failed %lx\n", i
, status
);
7407 todo_wine_if( i
!= 3)
7408 ok( dstlen
== (i
< 2 ? 14 : 73), "%d: wrong len %d\n", i
, dstlen
);
7410 status
= pRtlNormalizeString( norm_forms
[i
], L
"AB\xd800Z", -1, dst
, &dstlen
);
7411 ok( status
== STATUS_NO_UNICODE_TRANSLATION
, "%d: failed %lx\n", i
, status
);
7412 ok( dstlen
== 3, "%d: wrong len %d\n", i
, dstlen
);
7416 /* optionally run the full test file from Unicode.org
7417 * available at http://www.unicode.org/Public/UCD/latest/ucd/NormalizationTest.txt
7419 if ((f
= fopen( "NormalizationTest.txt", "r" )))
7421 char *p
, buffer
[1024];
7422 WCHAR str
[3], srcW
[32], dstW
[32], resW
[4][32];
7423 int line
= 0, part
= 0, ch
;
7424 char tested
[0x110000 / 8];
7426 while (fgets( buffer
, sizeof(buffer
), f
))
7429 if ((p
= strchr( buffer
, '#' ))) *p
= 0;
7430 if (!strncmp( buffer
, "@Part", 5 ))
7432 part
= atoi( buffer
+ 5 );
7435 if (!(p
= strtok( buffer
, ";" ))) continue;
7436 read_str( p
, srcW
);
7437 for (i
= 0; i
< 4; i
++)
7439 p
= strtok( NULL
, ";" );
7440 read_str( p
, &resW
[i
][0] );
7445 if (ch
>= 0xd800 && ch
<= 0xdbff)
7446 ch
= 0x10000 + ((srcW
[0] & 0x3ff) << 10) + (srcW
[1] & 0x3ff);
7447 tested
[ch
/ 8] |= 1 << (ch
% 8);
7449 for (i
= 0; i
< 4; i
++)
7451 memset( dstW
, 0xcc, sizeof(dstW
) );
7452 dstlen
= pNormalizeString( norm_forms
[i
], srcW
, -1, dstW
, ARRAY_SIZE(dstW
) );
7453 ok( !wcscmp( dstW
, resW
[i
] ),
7454 "line %u form %u: wrong result %s for %s expected %s\n", line
, i
,
7455 wine_dbgstr_w( dstW
), wine_dbgstr_w( srcW
), wine_dbgstr_w( resW
[i
] ));
7458 status
= pRtlIsNormalizedString( norm_forms
[i
], srcW
, -1, &ret
);
7459 ok( !status
, "line %u form %u: RtlIsNormalizedString failed %lx\n", line
, i
, status
);
7460 if (!wcscmp( srcW
, dstW
))
7461 ok( ret
, "line %u form %u: source not normalized %s\n", line
, i
, wine_dbgstr_w(srcW
) );
7463 ok( !ret
, "line %u form %u: source normalized %s\n", line
, i
, wine_dbgstr_w(srcW
) );
7465 status
= pRtlIsNormalizedString( norm_forms
[i
], dstW
, -1, &ret
);
7466 ok( !status
, "line %u form %u: RtlIsNormalizedString failed %lx\n", line
, i
, status
);
7467 ok( ret
, "line %u form %u: dest not normalized %s\n", line
, i
, wine_dbgstr_w(dstW
) );
7469 for (j
= 0; j
< 4; j
++)
7471 int expect
= i
| (j
& 2);
7472 memset( dstW
, 0xcc, sizeof(dstW
) );
7473 dstlen
= pNormalizeString( norm_forms
[i
], resW
[j
], -1, dstW
, ARRAY_SIZE(dstW
) );
7474 ok( !wcscmp( dstW
, resW
[expect
] ),
7475 "line %u form %u res %u: wrong result %s for %s expected %s\n", line
, i
, j
,
7476 wine_dbgstr_w( dstW
), wine_dbgstr_w( resW
[j
] ), wine_dbgstr_w( resW
[expect
] ));
7482 /* test chars that are not in the @Part1 list */
7483 for (ch
= 0; ch
< 0x110000; ch
++)
7485 if (tested
[ch
/ 8] & (1 << (ch
% 8))) continue;
7486 str
[put_utf16( str
, ch
)] = 0;
7487 for (i
= 0; i
< 4; i
++)
7489 memset( dstW
, 0xcc, sizeof(dstW
) );
7490 SetLastError( 0xdeadbeef );
7491 dstlen
= pNormalizeString( norm_forms
[i
], str
, -1, dstW
, ARRAY_SIZE(dstW
) );
7492 if ((ch
>= 0xd800 && ch
<= 0xdfff) ||
7493 (ch
>= 0xfdd0 && ch
<= 0xfdef) ||
7494 ((ch
& 0xffff) >= 0xfffe))
7496 ok( dstlen
<= 0, "char %04x form %u: wrong result %d %s expected error\n",
7497 ch
, i
, dstlen
, wine_dbgstr_w( dstW
));
7498 ok( GetLastError() == ERROR_NO_UNICODE_TRANSLATION
,
7499 "char %04x form %u: error %lu\n", str
[0], i
, GetLastError() );
7500 status
= pRtlIsNormalizedString( norm_forms
[i
], str
, -1, &ret
);
7501 ok( status
== STATUS_NO_UNICODE_TRANSLATION
,
7502 "char %04x form %u: failed %lx\n", ch
, i
, status
);
7506 ok( !wcscmp( dstW
, str
),
7507 "char %04x form %u: wrong result %s expected unchanged\n",
7508 ch
, i
, wine_dbgstr_w( dstW
));
7510 status
= pRtlIsNormalizedString( norm_forms
[i
], str
, -1, &ret
);
7511 ok( !status
, "char %04x form %u: failed %lx\n", ch
, i
, status
);
7512 ok( ret
, "char %04x form %u: not normalized\n", ch
, i
);
7519 static void test_SpecialCasing(void)
7523 WCHAR src
[8], buffer
[8];
7524 static const struct test
{
7528 UINT exp
; /* 0 if self */
7529 UINT exp_ling
; /* 0 if exp */
7532 {L
"de-DE", LCMAP_UPPERCASE
, 0x00DF}, /* LATIN SMALL LETTER SHARP S */
7534 {L
"en-US", LCMAP_UPPERCASE
, 0xFB00}, /* LATIN SMALL LIGATURE FF */
7535 {L
"en-US", LCMAP_UPPERCASE
, 0xFB01}, /* LATIN SMALL LIGATURE FI */
7536 {L
"en-US", LCMAP_UPPERCASE
, 0xFB02}, /* LATIN SMALL LIGATURE FL */
7537 {L
"en-US", LCMAP_UPPERCASE
, 0xFB03}, /* LATIN SMALL LIGATURE FFI */
7538 {L
"en-US", LCMAP_UPPERCASE
, 0xFB04}, /* LATIN SMALL LIGATURE FFL */
7539 {L
"en-US", LCMAP_UPPERCASE
, 0xFB05}, /* LATIN SMALL LIGATURE LONG S T */
7540 {L
"en-US", LCMAP_UPPERCASE
, 0xFB06}, /* LATIN SMALL LIGATURE ST */
7542 {L
"hy-AM", LCMAP_UPPERCASE
, 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */
7543 {L
"hy-AM", LCMAP_UPPERCASE
, 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */
7544 {L
"hy-AM", LCMAP_UPPERCASE
, 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */
7545 {L
"hy-AM", LCMAP_UPPERCASE
, 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */
7546 {L
"hy-AM", LCMAP_UPPERCASE
, 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */
7547 {L
"hy-AM", LCMAP_UPPERCASE
, 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */
7549 {L
"en-US", LCMAP_UPPERCASE
, 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
7550 {L
"el-GR", LCMAP_UPPERCASE
, 0x0390,0,0,TRUE
/*win7*/ }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
7551 {L
"el-GR", LCMAP_UPPERCASE
, 0x03B0,0,0,TRUE
/*win7*/ }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
7552 {L
"en-US", LCMAP_UPPERCASE
, 0x01F0}, /* LATIN SMALL LETTER J WITH CARON */
7553 {L
"en-US", LCMAP_UPPERCASE
, 0x1E96}, /* LATIN SMALL LETTER H WITH LINE BELOW */
7554 {L
"en-US", LCMAP_UPPERCASE
, 0x1E97}, /* LATIN SMALL LETTER T WITH DIAERESIS */
7555 {L
"en-US", LCMAP_UPPERCASE
, 0x1E98}, /* LATIN SMALL LETTER W WITH RING ABOVE */
7556 {L
"en-US", LCMAP_UPPERCASE
, 0x1E99}, /* LATIN SMALL LETTER Y WITH RING ABOVE */
7557 {L
"en-US", LCMAP_UPPERCASE
, 0x1E9A}, /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
7558 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F50}, /* GREEK SMALL LETTER UPSILON WITH PSILI */
7559 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F52}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
7560 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F54}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
7561 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F56}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
7562 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FB6}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
7563 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FC6}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
7564 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FD2}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
7565 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FD3}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */
7566 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FD6}, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
7567 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FD7}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
7568 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FE2}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
7569 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FE3}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */
7570 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FE4}, /* GREEK SMALL LETTER RHO WITH PSILI */
7571 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FE6}, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
7572 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FE7}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
7573 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FF6}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
7575 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F80,0x1F88}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
7576 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F81,0x1F89}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
7577 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F82,0x1F8A}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
7578 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F83,0x1F8B}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
7579 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F84,0x1F8C}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
7580 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F85,0x1F8D}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
7581 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F86,0x1F8E}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
7582 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F87,0x1F8F}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
7584 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F88,0x1F80}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
7585 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F89,0x1F81}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
7586 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8A,0x1F82}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
7587 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8B,0x1F83}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
7588 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8C,0x1F84}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
7589 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8D,0x1F85}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
7590 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8E,0x1F86}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
7591 {L
"el-GR", LCMAP_LOWERCASE
, 0x1F8F,0x1F87}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
7593 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F90,0x1F98}, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
7594 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F91,0x1F99}, /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
7595 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F92,0x1F9A}, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
7596 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F93,0x1F9B}, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
7597 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F94,0x1F9C}, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
7598 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F95,0x1F9D}, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
7599 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F96,0x1F9E}, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
7600 {L
"el-GR", LCMAP_UPPERCASE
, 0x1F97,0x1F9F}, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
7602 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FA8,0x1FA0}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
7603 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FA9,0x1FA1}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
7604 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAA,0x1FA2}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
7605 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAB,0x1FA3}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
7606 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAC,0x1FA4}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
7607 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAD,0x1FA5}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
7608 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAE,0x1FA6}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
7609 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FAF,0x1FA7}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
7611 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FB3,0x1FBC}, /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
7612 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FBC,0x1FB3}, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
7613 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FC3,0x1FCC}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
7614 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FCC,0x1FC3}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
7615 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FF3,0x1FFC}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
7616 {L
"el-GR", LCMAP_LOWERCASE
, 0x1FFC,0x1FF3}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
7618 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FB2}, /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
7619 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FB4}, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
7620 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FC2}, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
7621 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FC4}, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
7622 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FF2}, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
7623 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FF4}, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
7625 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FB7}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
7626 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FC7}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
7627 {L
"el-GR", LCMAP_UPPERCASE
, 0x1FF7}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
7629 {L
"el-GR", LCMAP_LOWERCASE
, 0x03A3,0x03C3}, /* GREEK CAPITAL LETTER SIGMA */
7631 {L
"lt-LT", LCMAP_LOWERCASE
, 'J','j'}, /* LATIN CAPITAL LETTER J */
7632 {L
"lt-LT", LCMAP_LOWERCASE
, 0x012E,0x012F}, /* LATIN CAPITAL LETTER I WITH OGONEK */
7633 {L
"lt-LT", LCMAP_LOWERCASE
, 0x00CC,0x00EC}, /* LATIN CAPITAL LETTER I WITH GRAVE */
7634 {L
"lt-LT", LCMAP_LOWERCASE
, 0x00CD,0x00ED}, /* LATIN CAPITAL LETTER I WITH ACUTE */
7635 {L
"lt-LT", LCMAP_LOWERCASE
, 0x0128,0x0129}, /* LATIN CAPITAL LETTER I WITH TILDE */
7637 {L
"en-US", LCMAP_UPPERCASE
, 'i', 'I'}, /* LATIN SMALL LETTER I */
7638 {L
"lt-LT", LCMAP_UPPERCASE
, 'i', 'I'}, /* LATIN SMALL LETTER I */
7639 {L
"tr-TR", LCMAP_UPPERCASE
, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
7640 {L
"TR-TR", LCMAP_UPPERCASE
, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
7641 {L
"az-Cyrl-az", LCMAP_UPPERCASE
, 'i', 'I', 0x0130, TRUE
/*win7*/}, /* LATIN SMALL LETTER I */
7642 {L
"az-Latn-az", LCMAP_UPPERCASE
, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
7644 {L
"en-US", LCMAP_LOWERCASE
, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
7645 {L
"lt-LT", LCMAP_LOWERCASE
, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
7646 {L
"tr-TR", LCMAP_LOWERCASE
, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
7647 {L
"TR-TR", LCMAP_LOWERCASE
, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
7648 {L
"az-Cyrl-az", LCMAP_LOWERCASE
, 'I', 'i', 0x0131, TRUE
/*win7*/}, /* LATIN CAPITAL LETTER I */
7649 {L
"az-Latn-az", LCMAP_LOWERCASE
, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
7651 {L
"en-US", LCMAP_LOWERCASE
, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
7652 {L
"tr-TR", LCMAP_LOWERCASE
, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
7653 {L
"TR-TR", LCMAP_LOWERCASE
, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
7654 {L
"az-Cyrl-az", LCMAP_LOWERCASE
, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
7655 {L
"az-Latn-az", LCMAP_LOWERCASE
, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
7657 {L
"en-US", LCMAP_UPPERCASE
, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
7658 {L
"tr-TR", LCMAP_UPPERCASE
, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
7659 {L
"TR-TR", LCMAP_UPPERCASE
, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
7660 {L
"az-Cyrl-az", LCMAP_UPPERCASE
, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
7661 {L
"az-Latn-az", LCMAP_UPPERCASE
, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
7663 {L
"en-US", LCMAP_LOWERCASE
, 0x10418,0x10440,0,TRUE
/*win7*/}, /* DESERET CAPITAL LETTER GAY */
7664 {L
"en-US", LCMAP_UPPERCASE
, 0x10431,0x10409,0,TRUE
/*win7*/}, /* DESERET SMALL LETTER SHORT AH */
7667 if (!pLCMapStringEx
)
7669 win_skip("LCMapStringEx not available\n");
7673 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
7675 memset(buffer
, 0, sizeof(buffer
));
7676 len
= put_utf16( src
, tests
[i
].ch
);
7677 ret
= pLCMapStringEx(tests
[i
].lang
, tests
[i
].flags
,
7678 src
, len
, buffer
, ARRAY_SIZE(buffer
), NULL
, NULL
, 0);
7679 len
= get_utf16( buffer
, ret
, &val
);
7680 ok(ret
== len
, "got %d for %04x for %s\n", ret
, tests
[i
].ch
, wine_dbgstr_w(tests
[i
].lang
));
7681 exp
= tests
[i
].exp
? tests
[i
].exp
: tests
[i
].ch
;
7682 ok(val
== exp
|| broken(tests
[i
].broken
),
7683 "expected %04x, got %04x for %04x for %s\n",
7684 exp
, val
, tests
[i
].ch
, wine_dbgstr_w(tests
[i
].lang
));
7686 memset(buffer
, 0, sizeof(buffer
));
7687 len
= put_utf16( src
, tests
[i
].ch
);
7688 ret
= pLCMapStringEx(tests
[i
].lang
, tests
[i
].flags
|LCMAP_LINGUISTIC_CASING
,
7689 src
, len
, buffer
, ARRAY_SIZE(buffer
), NULL
, NULL
, 0);
7690 len
= get_utf16( buffer
, ret
, &val
);
7691 ok(ret
== len
, "got %d for %04x for %s\n", ret
, tests
[i
].ch
, wine_dbgstr_w(tests
[i
].lang
));
7692 exp
= tests
[i
].exp_ling
? tests
[i
].exp_ling
: exp
;
7693 ok(val
== exp
|| broken(tests
[i
].broken
),
7694 "expected %04x, got %04x for %04x for %s\n",
7695 exp
, val
, tests
[i
].ch
, wine_dbgstr_w(tests
[i
].lang
));
7699 static void test_NLSVersion(void)
7701 static const GUID guid_null
= { 0 };
7702 static const GUID guid_def
= { 0x000000001, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
7703 static const GUID guid_fr
= { 0x000000003, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
7704 static const GUID guid_ja
= { 0x000000046, 0x57ee, 0x1e5c, {0x00,0xb4,0xd0,0x00,0x0b,0xb1,0xe1,0x1e}};
7706 NLSVERSIONINFOEX info
;
7708 if (!pGetNLSVersion
)
7710 win_skip( "GetNLSVersion not available\n" );
7714 SetLastError( 0xdeadbeef );
7715 memset( &info
, 0xcc, sizeof(info
) );
7716 info
.dwNLSVersionInfoSize
= offsetof( NLSVERSIONINFO
, dwEffectiveId
);
7717 ret
= pGetNLSVersion( COMPARE_STRING
, MAKELANGID( LANG_FRENCH
, SUBLANG_FRENCH_CANADIAN
),
7718 (NLSVERSIONINFO
*)&info
);
7719 ok( ret
, "GetNLSVersion failed err %lu\n", GetLastError() );
7721 SetLastError( 0xdeadbeef );
7722 memset( &info
, 0xcc, sizeof(info
) );
7723 info
.dwNLSVersionInfoSize
= sizeof(info
);
7724 ret
= pGetNLSVersion( COMPARE_STRING
, MAKELANGID( LANG_FRENCH
, SUBLANG_FRENCH_CANADIAN
),
7725 (NLSVERSIONINFO
*)&info
);
7726 ok( ret
|| GetLastError() == ERROR_INSUFFICIENT_BUFFER
/* < Vista */,
7727 "GetNLSVersion failed err %lu\n", GetLastError() );
7730 ok( info
.dwEffectiveId
== MAKELANGID( LANG_FRENCH
, SUBLANG_FRENCH_CANADIAN
),
7731 "wrong id %lx\n", info
.dwEffectiveId
);
7732 ok( IsEqualIID( &info
.guidCustomVersion
, &guid_fr
) ||
7733 broken( IsEqualIID( &info
.guidCustomVersion
, &guid_null
)), /* <= win7 */
7734 "wrong guid %s\n", debugstr_guid(&info
.guidCustomVersion
) );
7737 SetLastError( 0xdeadbeef );
7738 info
.dwNLSVersionInfoSize
= 8;
7739 ret
= pGetNLSVersion( COMPARE_STRING
, LOCALE_USER_DEFAULT
, (NLSVERSIONINFO
*)&info
);
7740 ok( !ret
, "GetNLSVersion succeeded\n" );
7741 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "wrong error %lu\n", GetLastError() );
7743 SetLastError( 0xdeadbeef );
7744 info
.dwNLSVersionInfoSize
= sizeof(info
);
7745 ret
= pGetNLSVersion( 2, LOCALE_USER_DEFAULT
, (NLSVERSIONINFO
*)&info
);
7746 ok( !ret
, "GetNLSVersion succeeded\n" );
7747 ok( GetLastError() == ERROR_INVALID_FLAGS
||
7748 broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER
), /* win2003 */
7749 "wrong error %lu\n", GetLastError() );
7751 SetLastError( 0xdeadbeef );
7752 info
.dwNLSVersionInfoSize
= sizeof(info
);
7753 ret
= pGetNLSVersion( COMPARE_STRING
, 0xdeadbeef, (NLSVERSIONINFO
*)&info
);
7754 ok( !ret
, "GetNLSVersion succeeded\n" );
7755 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7757 if (pGetNLSVersionEx
)
7759 SetLastError( 0xdeadbeef );
7760 memset( &info
, 0xcc, sizeof(info
) );
7761 info
.dwNLSVersionInfoSize
= sizeof(info
);
7762 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"ja-JP", &info
);
7763 ok( ret
, "GetNLSVersionEx failed err %lu\n", GetLastError() );
7764 ok( info
.dwEffectiveId
== MAKELANGID( LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
),
7765 "wrong id %lx\n", info
.dwEffectiveId
);
7766 ok( IsEqualIID( &info
.guidCustomVersion
, &guid_ja
) ||
7767 broken( IsEqualIID( &info
.guidCustomVersion
, &guid_null
)), /* <= win7 */
7768 "wrong guid %s\n", debugstr_guid(&info
.guidCustomVersion
) );
7769 trace( "version %08lx %08lx %08lx %s\n", info
.dwNLSVersion
, info
.dwDefinedVersion
, info
.dwEffectiveId
,
7770 debugstr_guid(&info
.guidCustomVersion
) );
7772 SetLastError( 0xdeadbeef );
7773 memset( &info
, 0xcc, sizeof(info
) );
7774 info
.dwNLSVersionInfoSize
= sizeof(info
);
7775 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"fr", &info
);
7776 ok( !ret
== !pIsValidLocaleName(L
"fr"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
7779 ok( info
.dwEffectiveId
== MAKELANGID( LANG_FRENCH
, SUBLANG_DEFAULT
),
7780 "wrong id %lx\n", info
.dwEffectiveId
);
7781 ok( IsEqualIID( &info
.guidCustomVersion
, &guid_fr
) ||
7782 broken( IsEqualIID( &info
.guidCustomVersion
, &guid_null
)), /* <= win7 */
7783 "wrong guid %s\n", debugstr_guid(&info
.guidCustomVersion
) );
7786 SetLastError( 0xdeadbeef );
7787 info
.dwNLSVersionInfoSize
= sizeof(info
) - 1;
7788 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"en-US", &info
);
7789 ok( !ret
, "GetNLSVersionEx succeeded\n" );
7790 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "wrong error %lu\n", GetLastError() );
7792 SetLastError( 0xdeadbeef );
7793 memset( &info
, 0xcc, sizeof(info
) );
7794 info
.dwNLSVersionInfoSize
= offsetof( NLSVERSIONINFO
, dwEffectiveId
);
7795 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"en-US", &info
);
7796 ok( ret
, "GetNLSVersionEx failed err %lu\n", GetLastError() );
7797 ok( info
.dwEffectiveId
== 0xcccccccc, "wrong id %lx\n", info
.dwEffectiveId
);
7799 SetLastError( 0xdeadbeef );
7800 info
.dwNLSVersionInfoSize
= sizeof(info
);
7801 ret
= pGetNLSVersionEx( 2, L
"en-US", &info
);
7802 ok( !ret
, "GetNLSVersionEx succeeded\n" );
7803 ok( GetLastError() == ERROR_INVALID_FLAGS
, "wrong error %lu\n", GetLastError() );
7805 SetLastError( 0xdeadbeef );
7806 info
.dwNLSVersionInfoSize
= sizeof(info
);
7807 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"foobar", &info
);
7808 ok( !ret
, "GetNLSVersionEx succeeded\n" );
7809 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7811 SetLastError( 0xdeadbeef );
7812 memset( &info
, 0xcc, sizeof(info
) );
7813 info
.dwNLSVersionInfoSize
= sizeof(info
);
7814 ret
= pGetNLSVersionEx( COMPARE_STRING
, L
"zz-XX", &info
);
7815 if (!ret
) ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7816 ok( !ret
== !pIsValidLocaleName(L
"zz-XX"), "GetNLSVersionEx doesn't match IsValidLocaleName\n" );
7819 ok( info
.dwEffectiveId
== LOCALE_CUSTOM_UNSPECIFIED
, "wrong id %lx\n", info
.dwEffectiveId
);
7820 ok( IsEqualIID( &info
.guidCustomVersion
, &guid_def
),
7821 "wrong guid %s\n", debugstr_guid(&info
.guidCustomVersion
) );
7824 SetLastError( 0xdeadbeef );
7825 memset( &info
, 0xcc, sizeof(info
) );
7826 info
.dwNLSVersionInfoSize
= sizeof(info
);
7827 ret
= pGetNLSVersionEx( COMPARE_STRING
, LOCALE_NAME_INVARIANT
, &info
);
7828 ok( ret
, "GetNLSVersionEx failed err %lu\n", GetLastError() );
7831 ok( info
.dwEffectiveId
== LOCALE_INVARIANT
, "wrong id %lx\n", info
.dwEffectiveId
);
7832 ok( IsEqualIID( &info
.guidCustomVersion
, &guid_def
) ||
7833 broken( IsEqualIID( &info
.guidCustomVersion
, &guid_null
)), /* <= win7 */
7834 "wrong guid %s\n", debugstr_guid(&info
.guidCustomVersion
) );
7836 else ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7838 else win_skip( "GetNLSVersionEx not available\n" );
7840 if (pIsValidNLSVersion
)
7842 info
.dwNLSVersionInfoSize
= sizeof(info
);
7843 pGetNLSVersion( COMPARE_STRING
, LOCALE_USER_DEFAULT
, (NLSVERSIONINFO
*)&info
);
7845 SetLastError( 0xdeadbeef );
7846 info
.dwNLSVersionInfoSize
= sizeof(info
);
7847 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"ja-JP", &info
);
7848 ok( ret
, "IsValidNLSVersion failed err %lu\n", GetLastError() );
7849 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7851 SetLastError( 0xdeadbeef );
7852 info
.dwNLSVersionInfoSize
= offsetof( NLSVERSIONINFO
, dwEffectiveId
);
7853 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7854 ok( ret
, "IsValidNLSVersion failed err %lu\n", GetLastError() );
7855 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7857 SetLastError( 0xdeadbeef );
7858 info
.dwNLSVersionInfoSize
= sizeof(info
);
7859 ret
= pIsValidNLSVersion( 2, L
"en-US", &info
);
7860 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7861 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7863 SetLastError( 0xdeadbeef );
7864 info
.dwNLSVersionInfoSize
= sizeof(info
);
7865 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"foobar", &info
);
7866 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7867 ok( GetLastError() == ERROR_INVALID_PARAMETER
, "wrong error %lu\n", GetLastError() );
7869 SetLastError( 0xdeadbeef );
7870 memset( &info
, 0xcc, sizeof(info
) );
7871 info
.dwNLSVersionInfoSize
= sizeof(info
);
7872 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7873 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7874 ok( GetLastError() == ERROR_SUCCESS
, "wrong error %lu\n", GetLastError() );
7876 info
.dwNLSVersionInfoSize
= sizeof(info
);
7877 pGetNLSVersion( COMPARE_STRING
, LOCALE_USER_DEFAULT
, (NLSVERSIONINFO
*)&info
);
7878 info
.dwNLSVersion
++;
7879 SetLastError( 0xdeadbeef );
7880 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7881 ok( ret
, "IsValidNLSVersion failed err %lu\n", GetLastError() );
7882 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7884 info
.dwNLSVersion
+= 0x700; /* much higher ver -> surely invalid */
7885 SetLastError( 0xdeadbeef );
7886 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7887 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7888 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
7890 info
.dwNLSVersion
-= 2 * 0x700; /* much lower ver -> surely invalid */
7891 SetLastError( 0xdeadbeef );
7892 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7893 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7894 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
7896 info
.dwNLSVersion
+= 0x700;
7897 info
.dwDefinedVersion
+= 0x100;
7898 SetLastError( 0xdeadbeef );
7899 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7900 ok( ret
, "IsValidNLSVersion failed err %lu\n", GetLastError() );
7901 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7903 info
.dwDefinedVersion
-= 0x100;
7904 info
.guidCustomVersion
.Data1
= 0x123;
7905 SetLastError( 0xdeadbeef );
7906 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7907 ok( !ret
, "IsValidNLSVersion succeeded\n" );
7908 ok( GetLastError() == 0, "wrong error %lu\n", GetLastError() );
7910 info
.guidCustomVersion
= guid_null
;
7911 SetLastError( 0xdeadbeef );
7912 ret
= pIsValidNLSVersion( COMPARE_STRING
, L
"en-US", &info
);
7913 ok( ret
, "IsValidNLSVersion failed err %lu\n", GetLastError() );
7914 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7916 else win_skip( "IsValidNLSVersion not available\n" );
7918 if (pIsNLSDefinedString
)
7920 SetLastError( 0xdeadbeef );
7921 info
.dwNLSVersionInfoSize
= sizeof(info
);
7922 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"A", 1 );
7924 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7926 ok( broken( GetLastError() == ERROR_INSUFFICIENT_BUFFER
), /* win7 */
7927 "wrong error %lu\n", GetLastError() );
7929 SetLastError( 0xdeadbeef );
7930 info
.dwNLSVersionInfoSize
= sizeof(info
) + 1;
7931 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"A", 1 );
7932 ok( !ret
, "IsNLSDefinedString succeeded\n" );
7933 ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "wrong error %lu\n", GetLastError() );
7935 SetLastError( 0xdeadbeef );
7936 info
.dwNLSVersionInfoSize
= offsetof( NLSVERSIONINFO
, dwEffectiveId
);
7937 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"A", 1 );
7938 ok( ret
, "IsNLSDefinedString failed err %lu\n", GetLastError() );
7939 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7941 SetLastError( 0xdeadbeef );
7942 ret
= pIsNLSDefinedString( 2, 0, (NLSVERSIONINFO
*)&info
, L
"A", 1 );
7943 ok( !ret
, "IsNLSDefinedString succeeded\n" );
7944 ok( GetLastError() == ERROR_INVALID_FLAGS
, "wrong error %lu\n", GetLastError() );
7946 SetLastError( 0xdeadbeef );
7947 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"ABC", -10 );
7948 ok( ret
, "IsNLSDefinedString failed err %lu\n", GetLastError() );
7949 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7951 SetLastError( 0xdeadbeef );
7952 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"ABC", -1 );
7953 ok( ret
, "IsNLSDefinedString failed err %lu\n", GetLastError() );
7954 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7956 SetLastError( 0xdeadbeef );
7957 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"\xd800", 1 );
7958 ok( !ret
, "IsNLSDefinedString failed err %lu\n", GetLastError() );
7959 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7961 SetLastError( 0xdeadbeef );
7962 ret
= pIsNLSDefinedString( COMPARE_STRING
, 0, (NLSVERSIONINFO
*)&info
, L
"\xd800", -20 );
7963 ok( !ret
, "IsNLSDefinedString failed err %lu\n", GetLastError() );
7964 ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() );
7966 else win_skip( "IsNLSDefinedString not available\n" );
7969 static void test_locale_nls(void)
7977 if (!pNtInitializeNlsFiles
|| !pRtlGetLocaleFileMappingAddress
)
7979 win_skip( "locale.nls functions not supported\n" );
7982 size
.QuadPart
= 0xdeadbeef;
7983 status
= pNtInitializeNlsFiles( &addr
, &lcid
, &size
);
7984 ok( !status
, "NtInitializeNlsFiles failed %lx\n", status
);
7985 trace( "locale %04lx size %I64x\n", lcid
, size
.QuadPart
);
7987 ok( size
.QuadPart
== 0xdeadbeef || size
.QuadPart
== ptr
[4] || size
.QuadPart
== ptr
[4] + 8,
7988 "wrong offset %x / %I64x\n", ptr
[4], size
.QuadPart
);
7989 ptr
= (UINT
*)((char *)addr
+ ptr
[4]);
7990 ok( ptr
[0] == 8, "wrong offset %u\n", ptr
[0] );
7991 ok( ptr
[3] == 0x5344534e, "wrong magic %x\n", ptr
[3] );
7993 status
= pNtInitializeNlsFiles( &addr2
, &lcid
, &size
);
7994 ok( !status
, "NtInitializeNlsFiles failed %lx\n", status
);
7995 ok( addr
!= addr2
, "got same address %p\n", addr
);
7996 ok( !memcmp( addr
, addr2
, ptr
[4] ), "contents differ\n" );
7997 status
= NtUnmapViewOfSection( GetCurrentProcess(), addr
);
7998 ok( !status
, "NtUnmapViewOfSection failed %lx\n", status
);
7999 status
= NtUnmapViewOfSection( GetCurrentProcess(), addr2
);
8000 ok( !status
, "NtUnmapViewOfSection failed %lx\n", status
);
8002 size
.QuadPart
= 0xdeadbeef;
8003 status
= pRtlGetLocaleFileMappingAddress( &addr
, &lcid
, &size
);
8004 ok( !status
, "NtInitializeNlsFiles failed %lx\n", status
);
8006 ok( size
.QuadPart
== 0xdeadbeef || size
.QuadPart
== ptr
[4] || size
.QuadPart
== ptr
[4] + 8,
8007 "wrong offset %x / %I64x\n", ptr
[4], size
.QuadPart
);
8008 ptr
= (UINT
*)((char *)addr
+ ptr
[4]);
8009 ok( ptr
[0] == 8, "wrong offset %u\n", ptr
[0] );
8010 ok( ptr
[3] == 0x5344534e, "wrong magic %x\n", ptr
[3] );
8012 /* RtlGetLocaleFileMappingAddress caches the pointer */
8013 status
= pRtlGetLocaleFileMappingAddress( &addr2
, &lcid
, &size
);
8014 ok( !status
, "NtInitializeNlsFiles failed %lx\n", status
);
8015 ok( addr
== addr2
, "got different address %p / %p\n", addr
, addr2
);
8018 static void test_geo_name(void)
8020 WCHAR reg_name
[32], buf
[32], set_name
[32], nation
[32], region
[32];
8021 BOOL have_name
= FALSE
, have_region
= FALSE
, have_nation
= FALSE
;
8022 DWORD size
, type
, name_size
;
8029 if (!pSetUserGeoName
|| !pGetUserDefaultGeoName
)
8031 win_skip("GetUserDefaultGeoName / SetUserGeoName is not available, skipping test.\n");
8035 status
= RegOpenKeyExA(HKEY_CURRENT_USER
, "Control Panel\\International\\Geo", 0, KEY_READ
| KEY_WRITE
, &key
);
8036 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8038 size
= sizeof(reg_name
);
8039 if (!RegQueryValueExW(key
, L
"Name", NULL
, &type
, (BYTE
*)reg_name
, &size
))
8042 lstrcpyW(buf
, L
"QQ");
8043 RegSetValueExW(key
, L
"Name", 0, REG_SZ
, (BYTE
*)buf
, (lstrlenW(buf
) + 1) * sizeof(WCHAR
));
8045 size
= sizeof(reg_name
);
8046 if ((ret
= pGetUserDefaultGeoName(NULL
, 0)) == 1)
8050 status
= RegSetValueExW(key
, L
"Name", 0, REG_SZ
, (BYTE
*)reg_name
, (lstrlenW(reg_name
) + 1) * sizeof(*reg_name
));
8051 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8055 RegDeleteValueW(key
, L
"Name");
8057 win_skip("Geo names are not available, skipping test.\n");
8061 size
= sizeof(nation
);
8062 if (!RegQueryValueExW(key
, L
"Nation", NULL
, &type
, (BYTE
*)nation
, &size
))
8064 size
= sizeof(region
);
8065 if (!RegQueryValueExW(key
, L
"Region", NULL
, &type
, (BYTE
*)region
, &size
))
8068 SetLastError(0xdeadbeef);
8069 ret
= pGetUserDefaultGeoName(NULL
, 0);
8070 ok((ret
== 3 || ret
== 4) && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8073 SetLastError(0xdeadbeef);
8074 ret
= pGetUserDefaultGeoName(buf
, 0);
8075 ok(ret
>= 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8077 SetLastError(0xdeadbeef);
8078 ret
= pGetUserDefaultGeoName(buf
, 2);
8079 ok(!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8081 SetLastError(0xdeadbeef);
8082 ret
= pGetUserDefaultGeoName(NULL
, 1);
8083 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8085 SetLastError(0xdeadbeef);
8086 ret
= pGetUserDefaultGeoName(NULL
, name_size
);
8087 ok(!ret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8089 SetLastError(0xdeadbeef);
8090 ret
= pGetUserDefaultGeoName(buf
, name_size
);
8091 ok(ret
== name_size
&& GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8092 ok(!lstrcmpW(buf
, L
"QQ"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8094 SetLastError(0xdeadbeef);
8095 bret
= pSetUserGeoName(NULL
);
8096 ok(!bret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8098 lstrcpyW(set_name
, L
"QQ");
8099 SetLastError(0xdeadbeef);
8100 bret
= pSetUserGeoName(set_name
);
8101 ok(!bret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8103 lstrcpyW(set_name
, L
"Xx");
8104 SetLastError(0xdeadbeef);
8105 bret
= pSetUserGeoName(set_name
);
8106 ok((bret
&& GetLastError() == 0xdeadbeef) || broken(bret
&& GetLastError() == 0),
8107 "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8109 SetLastError(0xdeadbeef);
8110 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8111 ok(ret
== 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8112 ok(!lstrcmpW(buf
, L
"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8113 geoid
= GetUserGeoID(GEOCLASS_REGION
);
8114 ok(geoid
== 39070, "Got unexpected geoid %lu.\n", geoid
);
8116 status
= RegQueryValueExW(key
, L
"Name", NULL
, &type
, (BYTE
*)buf
, &size
);
8117 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8118 ok(type
== REG_SZ
, "Got unexpected type %#lx.\n", type
);
8119 ok(!lstrcmpW(buf
, L
"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8121 lstrcpyW(set_name
, L
"ar");
8122 SetLastError(0xdeadbeef);
8123 bret
= pSetUserGeoName(set_name
);
8124 ok((bret
&& GetLastError() == 0xdeadbeef) || broken(bret
&& GetLastError() == 0),
8125 "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8126 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8127 ok((ret
== 3 && GetLastError() == 0xdeadbeef) || broken(ret
== 3 && GetLastError() == 0),
8128 "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8129 ok(!lstrcmpW(buf
, L
"AR"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8130 geoid
= GetUserGeoID(GEOCLASS_NATION
);
8131 ok(geoid
== 11, "Got unexpected geoid %lu.\n", geoid
);
8133 lstrcpyW(set_name
, L
"150");
8134 SetLastError(0xdeadbeef);
8135 bret
= pSetUserGeoName(set_name
);
8136 ok((bret
&& GetLastError() == 0xdeadbeef) || broken(bret
&& GetLastError() == 0),
8137 "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8138 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8139 ok((ret
== 4 && GetLastError() == 0xdeadbeef) || broken(ret
== 4 && GetLastError() == 0),
8140 "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8141 ok(!lstrcmpW(buf
, L
"150"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8142 geoid
= GetUserGeoID(GEOCLASS_NATION
);
8143 ok(geoid
== 11, "Got unexpected geoid %lu.\n", geoid
);
8145 lstrcpyW(set_name
, L
"150a");
8146 SetLastError(0xdeadbeef);
8147 bret
= pSetUserGeoName(set_name
);
8148 ok(!bret
&& GetLastError() == ERROR_INVALID_PARAMETER
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8150 bret
= SetUserGeoID(21242);
8151 ok(bret
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8152 SetLastError(0xdeadbeef);
8153 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8154 ok(ret
== 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8155 ok(!lstrcmpW(buf
, L
"XX"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8157 bret
= SetUserGeoID(42483);
8158 ok(bret
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8159 SetLastError(0xdeadbeef);
8160 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8161 ok(ret
== 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8162 ok(!lstrcmpW(buf
, L
"011"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8164 bret
= SetUserGeoID(333);
8165 ok(bret
, "Got unexpected bret %#x, GetLastError() %lu.\n", bret
, GetLastError());
8166 SetLastError(0xdeadbeef);
8167 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8168 ok(ret
== 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8169 ok(!lstrcmpW(buf
, L
"AN"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8171 RegDeleteValueW(key
, L
"Name");
8172 RegDeleteValueW(key
, L
"Region");
8173 lstrcpyW(buf
, L
"124");
8174 status
= RegSetValueExW(key
, L
"Nation", 0, REG_SZ
, (BYTE
*)buf
, (lstrlenW(buf
) + 1) * sizeof(*buf
));
8175 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8176 SetLastError(0xdeadbeef);
8177 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8178 ok(ret
== 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8179 ok(!lstrcmpW(buf
, L
"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8181 lstrcpyW(buf
, L
"333");
8182 status
= RegSetValueExW(key
, L
"Region", 0, REG_SZ
, (BYTE
*)buf
, (lstrlenW(buf
) + 1) * sizeof(*buf
));
8183 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8184 SetLastError(0xdeadbeef);
8185 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8186 ok(ret
== 3 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8187 ok(!lstrcmpW(buf
, L
"JM"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8189 RegDeleteValueW(key
, L
"Nation");
8190 SetLastError(0xdeadbeef);
8191 ret
= pGetUserDefaultGeoName(buf
, ARRAY_SIZE(buf
));
8192 ok(ret
== 4 && GetLastError() == 0xdeadbeef, "Got unexpected ret %u, GetLastError() %lu.\n", ret
, GetLastError());
8193 ok(!lstrcmpW(buf
, L
"001"), "Got unexpected name %s.\n", wine_dbgstr_w(buf
));
8195 /* Restore user geo data. */
8198 status
= RegSetValueExW(key
, L
"Name", 0, REG_SZ
, (BYTE
*)reg_name
, (lstrlenW(reg_name
) + 1) * sizeof(*reg_name
));
8199 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8203 RegDeleteValueW(key
, L
"Name");
8207 status
= RegSetValueExW(key
, L
"Nation", 0, REG_SZ
, (BYTE
*)nation
, (lstrlenW(nation
) + 1) * sizeof(*nation
));
8208 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8212 RegDeleteValueW(key
, L
"Nation");
8216 status
= RegSetValueExW(key
, L
"Region", 0, REG_SZ
, (BYTE
*)region
, (lstrlenW(region
) + 1) * sizeof(*region
));
8217 ok(status
== ERROR_SUCCESS
, "Got unexpected status %#lx.\n", status
);
8221 RegDeleteValueW(key
, L
"Region");
8227 static const LCID locales_with_optional_calendars
[] = {
8228 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_SAUDI_ARABIA
), SORT_DEFAULT
),
8229 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_LEBANON
), SORT_DEFAULT
),
8230 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_EGYPT
), SORT_DEFAULT
),
8231 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_ALGERIA
), SORT_DEFAULT
),
8232 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_BAHRAIN
), SORT_DEFAULT
),
8233 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_IRAQ
), SORT_DEFAULT
),
8234 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_JORDAN
), SORT_DEFAULT
),
8235 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_KUWAIT
), SORT_DEFAULT
),
8236 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_LIBYA
), SORT_DEFAULT
),
8237 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_MOROCCO
), SORT_DEFAULT
),
8238 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_OMAN
), SORT_DEFAULT
),
8239 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_QATAR
), SORT_DEFAULT
),
8240 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_SYRIA
), SORT_DEFAULT
),
8241 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_TUNISIA
), SORT_DEFAULT
),
8242 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_UAE
), SORT_DEFAULT
),
8243 MAKELCID(MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_YEMEN
), SORT_DEFAULT
),
8244 MAKELCID(MAKELANGID(LANG_CHINESE
, SUBLANG_CHINESE_TRADITIONAL
), SORT_DEFAULT
),
8245 MAKELCID(MAKELANGID(LANG_DIVEHI
, SUBLANG_DEFAULT
), SORT_DEFAULT
),
8246 MAKELCID(MAKELANGID(LANG_PERSIAN
, SUBLANG_DEFAULT
), SORT_DEFAULT
),
8247 MAKELCID(MAKELANGID(LANG_HEBREW
, SUBLANG_DEFAULT
), SORT_DEFAULT
),
8248 MAKELCID(MAKELANGID(LANG_JAPANESE
, SUBLANG_DEFAULT
), SORT_DEFAULT
),
8249 MAKELCID(MAKELANGID(LANG_KOREAN
, SUBLANG_KOREAN
), SORT_DEFAULT
),
8250 MAKELCID(MAKELANGID(LANG_THAI
, SUBLANG_DEFAULT
), SORT_DEFAULT
),
8251 MAKELCID(MAKELANGID(LANG_URDU
, SUBLANG_URDU_PAKISTAN
), SORT_DEFAULT
)
8254 static BOOL CALLBACK
calinfo_procA(LPSTR calinfo
)
8260 static void test_EnumCalendarInfoA(void)
8265 ret
= EnumCalendarInfoA( calinfo_procA
, LOCALE_USER_DEFAULT
, ENUM_ALL_CALENDARS
,
8266 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8267 ok( ret
, "EnumCalendarInfoA for user default locale failed: %lu\n", GetLastError() );
8269 for (i
= 0; i
< ARRAY_SIZE( locales_with_optional_calendars
); i
++)
8271 LCID lcid
= locales_with_optional_calendars
[i
];
8272 ret
= EnumCalendarInfoA( calinfo_procA
, lcid
, ENUM_ALL_CALENDARS
,
8273 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8274 ok( ret
|| broken( GetLastError() == ERROR_INVALID_FLAGS
) /* no locale */,
8275 "EnumCalendarInfoA for LCID %#06lx failed: %lu\n", lcid
, GetLastError() );
8279 static BOOL CALLBACK
calinfo_procW(LPWSTR calinfo
)
8285 static void test_EnumCalendarInfoW(void)
8290 ret
= EnumCalendarInfoW( calinfo_procW
, LOCALE_USER_DEFAULT
, ENUM_ALL_CALENDARS
,
8291 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8292 ok( ret
, "EnumCalendarInfoW for user default locale failed: %lu\n", GetLastError() );
8294 for (i
= 0; i
< ARRAY_SIZE( locales_with_optional_calendars
); i
++)
8296 LCID lcid
= locales_with_optional_calendars
[i
];
8297 ret
= EnumCalendarInfoW( calinfo_procW
, lcid
, ENUM_ALL_CALENDARS
,
8298 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8299 ok( ret
|| broken( GetLastError() == ERROR_INVALID_FLAGS
) /* no locale */,
8300 "EnumCalendarInfoW for LCID %#06lx failed: %lu\n", lcid
, GetLastError() );
8304 static BOOL CALLBACK
calinfoex_procA(LPSTR calinfo
, LCID calid
)
8311 static void test_EnumCalendarInfoExA(void)
8316 ret
= EnumCalendarInfoExA( calinfoex_procA
, LOCALE_USER_DEFAULT
, ENUM_ALL_CALENDARS
,
8317 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8318 ok( ret
, "EnumCalendarInfoExA for user default locale failed: %lu\n", GetLastError() );
8320 for (i
= 0; i
< ARRAY_SIZE( locales_with_optional_calendars
); i
++)
8322 LCID lcid
= locales_with_optional_calendars
[i
];
8323 ret
= EnumCalendarInfoExA( calinfoex_procA
, lcid
, ENUM_ALL_CALENDARS
,
8324 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8325 ok( ret
|| broken( GetLastError() == ERROR_INVALID_FLAGS
) /* no locale */,
8326 "EnumCalendarInfoExA for LCID %#06lx failed: %lu\n", lcid
, GetLastError() );
8330 static BOOL CALLBACK
calinfoex_procW(LPWSTR calinfo
, LCID calid
)
8337 static void test_EnumCalendarInfoExW(void)
8342 ret
= EnumCalendarInfoExW( calinfoex_procW
, LOCALE_USER_DEFAULT
, ENUM_ALL_CALENDARS
,
8343 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8344 ok( ret
, "EnumCalendarInfoExW for user default locale failed: %lu\n", GetLastError() );
8346 for (i
= 0; i
< ARRAY_SIZE( locales_with_optional_calendars
); i
++)
8348 LCID lcid
= locales_with_optional_calendars
[i
];
8349 ret
= EnumCalendarInfoExW( calinfoex_procW
, lcid
, ENUM_ALL_CALENDARS
,
8350 CAL_RETURN_NUMBER
| CAL_ICALINTVALUE
);
8351 ok( ret
|| broken( GetLastError() == ERROR_INVALID_FLAGS
) /* no locale */,
8352 "EnumCalendarInfoExW for LCID %#06lx failed: %lu\n", lcid
, GetLastError() );
8356 /* Generate sort keys for a list of Unicode code points.
8357 * Possible source files:
8358 * The Unicode collation test suite: https://www.unicode.org/Public/UCA/latest/CollationTest.zip
8359 * The list of supported char compressions: winedump nls/sortdefault.nls | grep \\-\>
8361 static void dump_sortkeys( char *argv
[] )
8364 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
8366 unsigned int i
, val
, pos
, res
, flags
= 0;
8367 char *p
, *end
, buffer
[1024];
8368 FILE *f
= fopen( argv
[1], "r" );
8373 MultiByteToWideChar( CP_ACP
, 0, argv
[2], -1, locale
, LOCALE_NAME_MAX_LENGTH
);
8374 if (argv
[3]) flags
= strtoul( argv
[3], NULL
, 0 );
8379 fprintf( stderr
, "cannot open %s\n", argv
[1] );
8382 while (fgets( buffer
, sizeof(buffer
), f
))
8384 if (buffer
[0] && buffer
[strlen(buffer
)-1] == '\n') buffer
[strlen(buffer
)-1] = 0;
8386 while (*p
== ' ' || *p
== '\t') p
++;
8387 if (*p
== '#') continue;
8389 while (*p
&& *p
!= ';' && *p
!= '-')
8391 val
= strtoul( p
, &end
, 16 );
8392 if (end
== p
) break;
8395 data
[pos
++] = 0xd800 | (val
>> 10);
8396 data
[pos
++] = 0xdc00 | (val
& 0x3ff);
8398 else data
[pos
++] = val
;
8400 while (*p
== ' ' || *p
== '\t') p
++;
8403 res
= LCMapStringEx( locale
, flags
| LCMAP_SORTKEY
, data
, pos
,
8404 (WCHAR
*)key
, sizeof(key
), NULL
, NULL
, 0 );
8405 printf( "%s:", buffer
);
8406 for (i
= 0; i
< res
; i
++) printf( " %02x", key
[i
] );
8412 static BOOL CALLBACK
EnumDateFormatsExEx_proc(LPWSTR date_format_string
, CALID calendar_id
, LPARAM lp
)
8417 static void test_EnumDateFormatsExEx(void)
8422 /* Invalid locale name */
8423 ret
= EnumDateFormatsExEx(EnumDateFormatsExEx_proc
, L
"deadbeef", DATE_SHORTDATE
, 0);
8424 error
= GetLastError();
8425 ok(!ret
, "EnumDateFormatsExEx succeeded.\n");
8426 ok(error
== ERROR_INVALID_PARAMETER
, "Got unexpected error %#lx.\n", error
);
8428 /* yi-Hebr is missing on versions < Win10 */
8429 /* Running the following tests will cause other tests that use LOCALE_CUSTOM_UNSPECIFIED to
8430 * report yi-Hebr instead the default locale on Windows 10. So run them at the end */
8431 ret
= EnumDateFormatsExEx(EnumDateFormatsExEx_proc
, L
"yi-Hebr", DATE_SHORTDATE
, 0);
8432 error
= GetLastError();
8433 ok(ret
|| (!ret
&& error
== ERROR_INVALID_PARAMETER
), /* < Win10 */
8434 "EnumDateFormatsExEx failed, error %#lx.\n", error
);
8436 ret
= EnumDateFormatsExEx(EnumDateFormatsExEx_proc
, L
"yi-Hebr", DATE_LONGDATE
, 0);
8437 error
= GetLastError();
8438 ok(ret
|| (!ret
&& error
== ERROR_INVALID_PARAMETER
), /* < Win10 */
8439 "EnumDateFormatsExEx failed, error %#lx.\n", error
);
8445 int argc
= winetest_get_mainargs( &argv
);
8447 InitFunctionPointers();
8451 if (!strcmp( argv
[2], "sortkeys" ))
8453 dump_sortkeys( argv
+ 2 );
8458 test_EnumTimeFormatsA();
8459 test_EnumTimeFormatsW();
8460 test_EnumDateFormatsA();
8461 test_GetLocaleInfoA();
8462 test_GetLocaleInfoW();
8463 test_GetLocaleInfoEx();
8464 test_GetTimeFormatA();
8465 test_GetTimeFormatEx();
8466 test_GetDateFormatA();
8467 test_GetDateFormatEx();
8468 test_GetDateFormatW();
8469 test_GetCurrencyFormatA(); /* Also tests the W version */
8470 test_GetNumberFormatA(); /* Also tests the W version */
8471 test_GetNumberFormatEx();
8472 test_CompareStringA();
8473 test_CompareStringW();
8474 test_CompareStringEx();
8475 test_LCMapStringA();
8476 test_LCMapStringW();
8477 test_LCMapStringEx();
8478 test_LocaleNameToLCID();
8481 test_ConvertDefaultLocale();
8482 test_EnumSystemLanguageGroupsA();
8483 test_EnumSystemLocalesEx();
8484 test_EnumLanguageGroupLocalesA();
8485 test_SetLocaleInfo();
8486 test_EnumUILanguageA();
8488 test_GetStringTypeW();
8490 test_IsValidLocaleName();
8491 test_ResolveLocaleName();
8492 test_CompareStringOrdinal();
8494 test_EnumSystemGeoID();
8496 test_GetSystemPreferredUILanguages();
8497 test_GetThreadPreferredUILanguages();
8498 test_GetUserPreferredUILanguages();
8499 test_FindNLSStringEx();
8500 test_FindStringOrdinal();
8501 test_SetThreadUILanguage();
8502 test_NormalizeString();
8503 test_SpecialCasing();
8508 test_unicode_sorting();
8509 test_EnumCalendarInfoA();
8510 test_EnumCalendarInfoW();
8511 test_EnumCalendarInfoExA();
8512 test_EnumCalendarInfoExW();
8514 /* Run this test at the end */
8515 test_EnumDateFormatsExEx();