1 /*
2  * Unit tests for locale functions
3  *
4  * Copyright 2002 YASAR Mehmet
5  * Copyright 2003 Dmitry Timoshkov
6  * Copyright 2003 Jon Griffiths
7  *
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.
12  *
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.
17  *
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
21  *
22  * NOTES
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.
26  */
27 
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 
33 #undef WINVER
34 #define WINVER 0x0600
35 
36 #include "wine/test.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "winnls.h"
41 
42 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};
43 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};
44 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};
45 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
46 static const WCHAR localeW[] = {'e','n','-','U','S',0};
47 static const WCHAR fooW[] = {'f','o','o',0};
48 static const WCHAR emptyW[] = {0};
49 static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
50 
51 static inline unsigned int strlenW( const WCHAR *str )
52 {
53     const WCHAR *s = str;
54     while (*s) s++;
55     return s - str;
56 }
57 
58 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
59 {
60     if (n <= 0) return 0;
61     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
62     return *str1 - *str2;
63 }
64 
65 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
66 {
67     do { if (*str == ch) return (WCHAR *)str; } while (*str++);
68     return NULL;
69 }
70 
71 static inline BOOL isdigitW( WCHAR wc )
72 {
73     WORD type;
74     GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
75     return type & C1_DIGIT;
76 }
77 
78 /* Some functions are only in later versions of kernel32.dll */
79 static WORD enumCount;
80 
81 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
82 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
83 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
84 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
85 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
86 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
87 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
88 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
89 static INT  (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
90 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
91 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
93 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
94 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
95 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
96 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
97 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
98 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
99 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
100                                       LPNLSVERSIONINFO, LPVOID, LPARAM);
101 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
102 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
103 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
104 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
105 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
106 static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
107 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
108 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
109 
110 static void InitFunctionPointers(void)
111 {
112   HMODULE mod = GetModuleHandleA("kernel32");
113 
114 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
115   X(GetTimeFormatEx);
116   X(GetDateFormatEx);
117   X(EnumSystemLanguageGroupsA);
118   X(EnumLanguageGroupLocalesA);
119   X(LocaleNameToLCID);
120   X(LCIDToLocaleName);
121   X(LCMapStringEx);
122   X(FoldStringA);
123   X(FoldStringW);
124   X(IsValidLanguageGroup);
125   X(EnumUILanguagesA);
126   X(EnumSystemLocalesEx);
127   X(IdnToNameprepUnicode);
128   X(IdnToAscii);
129   X(IdnToUnicode);
130   X(GetLocaleInfoEx);
131   X(IsValidLocaleName);
132   X(CompareStringOrdinal);
133   X(CompareStringEx);
134   X(GetGeoInfoA);
135   X(GetGeoInfoW);
136   X(EnumSystemGeoID);
137   X(GetSystemPreferredUILanguages);
138   X(GetThreadPreferredUILanguages);
139   X(GetUserPreferredUILanguages);
140   X(GetNumberFormatEx);
141 
142   mod = GetModuleHandleA("ntdll");
143   X(RtlUpcaseUnicodeChar);
144 #undef X
145 }
146 
147 #define eq(received, expected, label, type) \
148         ok((received) == (expected), "%s: got " type " instead of " type "\n", \
149            (label), (received), (expected))
150 
151 #define BUFFER_SIZE    128
152 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
153 
154 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
155 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
156 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
157   "Expected '%s', got '%s'\n", Expected, buffer)
158 
159 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
160    MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
161    SetLastError(0xdeadbeef); buffer[0] = '\0'
162 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
163 #define EXPECT_EQW  ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
164 
165 #define NUO LOCALE_NOUSEROVERRIDE
166 
167 static void test_GetLocaleInfoA(void)
168 {
169   int ret;
170   int len;
171   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
172   char buffer[BUFFER_SIZE];
173   char expected[BUFFER_SIZE];
174   DWORD val;
175 
176   ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
177 
178   ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
179   ok(ret, "got %d\n", ret);
180   ok(val == lcid, "got 0x%08x\n", val);
181 
182   /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
183      Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
184      assumes SUBLANG_NEUTRAL for zh */
185   memset(expected, 0, COUNTOF(expected));
186   len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
187   SetLastError(0xdeadbeef);
188   memset(buffer, 0, COUNTOF(buffer));
189   ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
190   ok((ret == len) && !lstrcmpA(buffer, expected),
191       "got %d with '%s' (expected %d with '%s')\n",
192       ret, buffer, len, expected);
193 
194   memset(expected, 0, COUNTOF(expected));
195   len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
196   if (len) {
197       SetLastError(0xdeadbeef);
198       memset(buffer, 0, COUNTOF(buffer));
199       ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
200       ok((ret == len) && !lstrcmpA(buffer, expected),
201           "got %d with '%s' (expected %d with '%s')\n",
202           ret, buffer, len, expected);
203   }
204   else
205       win_skip("LANG_ARABIC not installed\n");
206 
207   /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
208   memset(expected, 0, COUNTOF(expected));
209   len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
210   SetLastError(0xdeadbeef);
211   memset(buffer, 0, COUNTOF(buffer));
212   ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
213   ok((ret == len) && !lstrcmpA(buffer, expected),
214       "got %d with '%s' (expected %d with '%s')\n",
215       ret, buffer, len, expected);
216 
217 
218   /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
219    * partially fill the buffer even if it is too short. See bug 637.
220    */
221   SetLastError(0xdeadbeef);
222   memset(buffer, 0, COUNTOF(buffer));
223   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
224   ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
225 
226   SetLastError(0xdeadbeef);
227   memset(buffer, 0, COUNTOF(buffer));
228   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
229   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
230       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
231   ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
232 
233   SetLastError(0xdeadbeef);
234   memset(buffer, 0, COUNTOF(buffer));
235   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
236   ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
237   ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
238 }
239 
240 struct neutralsublang_name2_t {
241     WCHAR name[3];
242     WCHAR sname[15];
243     LCID lcid;
244     LCID lcid_broken;
245     WCHAR sname_broken[15];
246     int todo;
247 };
248 
249 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
250     { {'a','r',0}, {'a','r','-','S','A',0},
251       MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
252     { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
253       MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
254     { {'d','e',0}, {'d','e','-','D','E',0},
255       MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
256     { {'e','n',0}, {'e','n','-','U','S',0},
257       MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
258     { {'e','s',0}, {'e','s','-','E','S',0},
259       MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
260       MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
261       {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
262     { {'g','a',0}, {'g','a','-','I','E',0},
263       MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
264     { {'i','t',0}, {'i','t','-','I','T',0},
265       MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
266     { {'m','s',0}, {'m','s','-','M','Y',0},
267       MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
268     { {'n','l',0}, {'n','l','-','N','L',0},
269       MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
270     { {'p','t',0}, {'p','t','-','B','R',0},
271       MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
272     { {'s','r',0}, {'h','r','-','H','R',0},
273       MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
274     { {'s','v',0}, {'s','v','-','S','E',0},
275       MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
276     { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
277       MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
278     { {'z','h',0}, {'z','h','-','C','N',0},
279       MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
280     { {0} }
281 };
282 
283 static void test_GetLocaleInfoW(void)
284 {
285   LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
286   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
287   LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
288   WCHAR bufferW[80], buffer2W[80];
289   CHAR bufferA[80];
290   DWORD val;
291   DWORD ret;
292   INT i;
293 
294   ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
295   if (!ret) {
296       win_skip("GetLocaleInfoW() isn't implemented\n");
297       return;
298   }
299 
300   ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
301   ok(ret, "got %d\n", ret);
302   ok(val == lcid_en, "got 0x%08x\n", val);
303 
304   ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
305   if (ret)
306   {
307       static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
308                                                                      'S','t','a','t','e','s',')',0};
309       static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
310       static const WCHAR enW[] = {'e','n','-','U','S',0};
311       const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
312 
313       ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
314 
315       ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
316       ok(ret, "got %d\n", ret);
317       if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
318           (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
319       {
320           skip("Non-English locale\n");
321       }
322       else
323           ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
324 
325       ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
326       ok(ret, "got %d\n", ret);
327       if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
328           (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
329       {
330           skip("Non-English locale\n");
331       }
332       else
333           ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
334 
335       while (*ptr->name)
336       {
337           LANGID langid;
338           LCID lcid;
339 
340           /* make neutral lcid */
341           langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
342           lcid = MAKELCID(langid, SORT_DEFAULT);
343 
344           val = 0;
345           GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
346           todo_wine_if (ptr->todo & 0x1)
347               ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
348                   wine_dbgstr_w(ptr->name), val, ptr->lcid);
349 
350           /* now check LOCALE_SNAME */
351           GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
352           todo_wine_if (ptr->todo & 0x2)
353               ok(!lstrcmpW(bufferW, ptr->sname) ||
354                  (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
355                   "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
356           ptr++;
357       }
358   }
359   else
360       win_skip("English neutral locale not supported\n");
361 
362   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
363   if (!ret) {
364       win_skip("LANG_RUSSIAN locale data unavailable\n");
365       return;
366   }
367   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
368                        bufferW, COUNTOF(bufferW));
369   if (!ret) {
370       win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
371       return;
372   }
373 
374   /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
375   bufferA[0] = 'a';
376   SetLastError(0xdeadbeef);
377   ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
378                        bufferA, COUNTOF(bufferA));
379   ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
380   ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
381   ok(GetLastError() == ERROR_INVALID_FLAGS,
382      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
383 
384   bufferW[0] = 'a';
385   SetLastError(0xdeadbeef);
386   ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
387                        bufferW, COUNTOF(bufferW));
388   ok(ret == 0,
389      "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
390   ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
391   ok(GetLastError() == ERROR_INVALID_FLAGS,
392      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
393 
394   /* yes, test empty 13 month entry too */
395   for (i = 0; i < 12; i++) {
396       bufferW[0] = 0;
397       ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
398                            bufferW, COUNTOF(bufferW));
399       ok(ret, "Expected non zero result\n");
400       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
401                                     ret, lstrlenW(bufferW));
402       buffer2W[0] = 0;
403       ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
404                            buffer2W, COUNTOF(buffer2W));
405       ok(ret, "Expected non zero result\n");
406       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
407                                     ret, lstrlenW(buffer2W));
408 
409       ok(lstrcmpW(bufferW, buffer2W) != 0,
410            "Expected genitive name to differ, got the same for month %d\n", i+1);
411 
412       /* for locale without genitive names nominative returned in both cases */
413       bufferW[0] = 0;
414       ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
415                            bufferW, COUNTOF(bufferW));
416       ok(ret, "Expected non zero result\n");
417       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
418                                     ret, lstrlenW(bufferW));
419       buffer2W[0] = 0;
420       ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
421                            buffer2W, COUNTOF(buffer2W));
422       ok(ret, "Expected non zero result\n");
423       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
424                                     ret, lstrlenW(buffer2W));
425 
426       ok(lstrcmpW(bufferW, buffer2W) == 0,
427          "Expected same names, got different for month %d\n", i+1);
428   }
429 }
430 
431 static void test_GetTimeFormatA(void)
432 {
433   int ret;
434   SYSTEMTIME  curtime;
435   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
436   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
437 
438   memset(&curtime, 2, sizeof(SYSTEMTIME));
439   STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
440   SetLastError(0xdeadbeef);
441   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
442   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
443       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
444 
445   curtime.wHour = 8;
446   curtime.wMinute = 56;
447   curtime.wSecond = 13;
448   curtime.wMilliseconds = 22;
449   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
450   SetLastError(0xdeadbeef);
451   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
452   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
453   EXPECT_LENA; EXPECT_EQA;
454 
455   /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
456   SetLastError(0xdeadbeef);
457   ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
458   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
459      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
460 
461   STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
462   SetLastError(0xdeadbeef);
463   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
464   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
465       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
466 
467   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
468   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
469   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
470   EXPECT_LENA;
471 
472   STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
473   ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
474   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
475   EXPECT_LENA; EXPECT_EQA;
476 
477   STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
478   ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
479   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
480   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
481       "Expected '', got '%s'\n", buffer );
482 
483   STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
484   ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
485   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
486   EXPECT_LENA; EXPECT_EQA;
487 
488   STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
489   strcpy(Expected, "8:56 AM");
490   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
491   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
492   EXPECT_LENA; EXPECT_EQA;
493 
494   STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
495   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
496   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
497   ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
498       "Expected '8.@:56AM', got '%s'\n", buffer );
499 
500   STRINGSA("s1s2s3", ""); /* Duplicate tokens */
501   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
502   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
503   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
504       "Expected '', got '%s'\n", buffer );
505 
506   STRINGSA("t/tt", "A/AM"); /* AM time marker */
507   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
508   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
509   EXPECT_LENA; EXPECT_EQA;
510 
511   curtime.wHour = 13;
512   STRINGSA("t/tt", "P/PM"); /* PM time marker */
513   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
514   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
515   EXPECT_LENA; EXPECT_EQA;
516 
517   STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
518   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
519   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
520   EXPECT_LENA; EXPECT_EQA;
521 
522   STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
523   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
524   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
525   EXPECT_LENA; EXPECT_EQA;
526 
527   STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
528   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
529   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
530   EXPECT_LENA; EXPECT_EQA;
531 
532   curtime.wHour = 14; /* change this to 14 or 2pm */
533   curtime.wMinute = 5;
534   curtime.wSecond = 3;
535   STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
536   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
537   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
538   EXPECT_LENA; EXPECT_EQA;
539 
540   curtime.wHour = 0;
541   STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
542   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
543   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
544   EXPECT_LENA; EXPECT_EQA;
545 
546   STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
547   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
548   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
549   EXPECT_LENA; EXPECT_EQA;
550 
551   /* try to convert formatting strings with more than two letters
552    * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
553    * NOTE: We expect any letter for which there is an upper case value
554    *       we should see a replacement.  For letters that DO NOT have
555    *       upper case values we should see NO REPLACEMENT.
556    */
557   curtime.wHour = 8;
558   curtime.wMinute = 56;
559   curtime.wSecond = 13;
560   curtime.wMilliseconds = 22;
561   STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
562            "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
563   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
564   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
565   EXPECT_LENA; EXPECT_EQA;
566 
567   STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
568   strcpy(buffer, "text");
569   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
570   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
571   EXPECT_EQA;
572 
573   STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
574            "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
575   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
576   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
577   EXPECT_LENA; EXPECT_EQA;
578 
579   STRINGSA("'''", "'"); /* invalid quoted string */
580   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
581   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
582   EXPECT_LENA; EXPECT_EQA;
583 
584   /* test that msdn suggested single quotation usage works as expected */
585   STRINGSA("''''", "'"); /* single quote mark */
586   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
587   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
588   EXPECT_LENA; EXPECT_EQA;
589 
590   STRINGSA("''HHHHHH", "08"); /* Normal use */
591   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
592   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
593   EXPECT_LENA; EXPECT_EQA;
594 
595   /* and test for normal use of the single quotation mark */
596   STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
597   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
598   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
599   EXPECT_LENA; EXPECT_EQA;
600 
601   STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
602   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
603   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
604   EXPECT_LENA; EXPECT_EQA;
605 
606   STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
607   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
608   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
609   EXPECT_LENA; EXPECT_EQA;
610 
611   curtime.wHour = 25;
612   STRINGSA("'123'tt", ""); /* Invalid time */
613   SetLastError(0xdeadbeef);
614   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
615   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
616       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
617 
618   curtime.wHour = 12;
619   curtime.wMonth = 60; /* Invalid */
620   STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
621   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
622   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
623   EXPECT_LENA; EXPECT_EQA;
624 }
625 
626 static void test_GetTimeFormatEx(void)
627 {
628   int ret;
629   SYSTEMTIME  curtime;
630   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
631 
632   if (!pGetTimeFormatEx)
633   {
634       win_skip("GetTimeFormatEx not supported\n");
635       return;
636   }
637 
638   memset(&curtime, 2, sizeof(SYSTEMTIME));
639   STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
640   SetLastError(0xdeadbeef);
641   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
642   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
643       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
644 
645   curtime.wHour = 8;
646   curtime.wMinute = 56;
647   curtime.wSecond = 13;
648   curtime.wMilliseconds = 22;
649   STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
650   SetLastError(0xdeadbeef);
651   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
652   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
653   EXPECT_LENW; EXPECT_EQW;
654 
655   /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
656   SetLastError(0xdeadbeef);
657   ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
658   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
659      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
660 
661   STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
662   SetLastError(0xdeadbeef);
663   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
664   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
665       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
666 
667   STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
668   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
669   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
670   EXPECT_LENW;
671 
672   STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
673   ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
674   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
675   EXPECT_LENW; EXPECT_EQW;
676 
677   STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
678   ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
679   ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
680   EXPECT_LENW; EXPECT_EQW;
681 
682   STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
683   ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
684   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
685   EXPECT_LENW; EXPECT_EQW;
686 
687   STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
688   ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
689   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
690   EXPECT_LENW; EXPECT_EQW;
691 
692   STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
693   ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
694   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
695   EXPECT_LENW; EXPECT_EQW;
696 
697   STRINGSW("s1s2s3", ""); /* Duplicate tokens */
698   ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
699   ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
700   EXPECT_LENW; EXPECT_EQW;
701 
702   STRINGSW("t/tt", "A/AM"); /* AM time marker */
703   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
704   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
705   EXPECT_LENW; EXPECT_EQW;
706 
707   curtime.wHour = 13;
708   STRINGSW("t/tt", "P/PM"); /* PM time marker */
709   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
710   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
711   EXPECT_LENW; EXPECT_EQW;
712 
713   STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
714   ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
715   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
716   EXPECT_LENW; EXPECT_EQW;
717 
718   STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
719   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
720   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
721   EXPECT_LENW; EXPECT_EQW;
722 
723   STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
724   ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
725   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
726   EXPECT_LENW; EXPECT_EQW;
727 
728   curtime.wHour = 14; /* change this to 14 or 2pm */
729   curtime.wMinute = 5;
730   curtime.wSecond = 3;
731   STRINGSW("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
732   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
733   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
734   EXPECT_LENW; EXPECT_EQW;
735 
736   curtime.wHour = 0;
737   STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
738   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
739   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
740   EXPECT_LENW; EXPECT_EQW;
741 
742   STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
743   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
744   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
745   EXPECT_LENW; EXPECT_EQW;
746 
747   /* try to convert formatting strings with more than two letters
748    * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
749    * NOTE: We expect any letter for which there is an upper case value
750    *       we should see a replacement.  For letters that DO NOT have
751    *       upper case values we should see NO REPLACEMENT.
752    */
753   curtime.wHour = 8;
754   curtime.wMinute = 56;
755   curtime.wSecond = 13;
756   curtime.wMilliseconds = 22;
757   STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
758            "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
759   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
760   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
761   EXPECT_LENW; EXPECT_EQW;
762 
763   STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
764   lstrcpyW(buffer, Expected);
765   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
766   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
767   EXPECT_EQW;
768 
769   STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
770            "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
771   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
772   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
773   EXPECT_LENW; EXPECT_EQW;
774 
775   STRINGSW("'''", "'"); /* invalid quoted string */
776   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
777   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
778   EXPECT_LENW; EXPECT_EQW;
779 
780   /* test that msdn suggested single quotation usage works as expected */
781   STRINGSW("''''", "'"); /* single quote mark */
782   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
783   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
784   EXPECT_LENW; EXPECT_EQW;
785 
786   STRINGSW("''HHHHHH", "08"); /* Normal use */
787   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
788   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
789   EXPECT_LENW; EXPECT_EQW;
790 
791   /* and test for normal use of the single quotation mark */
792   STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
793   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
794   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
795   EXPECT_LENW; EXPECT_EQW;
796 
797   STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
798   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
799   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
800   EXPECT_LENW; EXPECT_EQW;
801 
802   STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
803   ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
804   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
805   EXPECT_LENW; EXPECT_EQW;
806 
807   curtime.wHour = 25;
808   STRINGSW("'123'tt", ""); /* Invalid time */
809   SetLastError(0xdeadbeef);
810   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
811   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
812       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
813 
814   curtime.wHour = 12;
815   curtime.wMonth = 60; /* Invalid */
816   STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
817   ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
818   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
819   EXPECT_LENW; EXPECT_EQW;
820 }
821 
822 static void test_GetDateFormatA(void)
823 {
824   int ret;
825   SYSTEMTIME  curtime;
826   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
827   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
828   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
829   char Broken[BUFFER_SIZE];
830   char short_day[10], month[10], genitive_month[10];
831 
832   memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
833   STRINGSA("ddd',' MMM dd yy","");
834   SetLastError(0xdeadbeef);
835   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
836   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
837       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
838 
839   curtime.wYear = 2002;
840   curtime.wMonth = 5;
841   curtime.wDay = 4;
842   curtime.wDayOfWeek = 3;
843   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
844   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
845   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
846   EXPECT_LENA; EXPECT_EQA;
847 
848   /* Same as above but with LOCALE_NOUSEROVERRIDE */
849   STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
850   SetLastError(0xdeadbeef);
851   ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
852   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
853      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
854   EXPECT_EQA;
855 
856   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
857   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
858   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
859   EXPECT_LENA; EXPECT_EQA;
860 
861   curtime.wHour = 36; /* Invalid */
862   STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
863   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
864   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
865   EXPECT_LENA; EXPECT_EQA;
866 
867   STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
868   ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
869   ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
870   EXPECT_EQA;
871 
872   STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
873   SetLastError(0xdeadbeef);
874   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
875   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
876       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
877 
878   STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
879   ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
880   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
881   if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
882 	  ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
883 
884   SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
885   ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
886   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
887   ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
888      strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
889      "got an unexpected date string '%s'\n", buffer);
890 
891   /* test for expected DATE_YEARMONTH behavior with null format */
892   /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
893   STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
894   SetLastError(0xdeadbeef);
895   ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
896   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
897      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
898   EXPECT_EQA;
899 
900   /* Test that using invalid DATE_* flags results in the correct error */
901   /* and return values */
902   STRINGSA("m/d/y", ""); /* Invalid flags */
903   SetLastError(0xdeadbeef);
904   ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
905                       &curtime, input, buffer, COUNTOF(buffer));
906   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
907      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
908 
909   ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
910   if (!ret)
911   {
912     win_skip("LANG_RUSSIAN locale data unavailable\n");
913     return;
914   }
915 
916   /* month part should be in genitive form */
917   strcpy(genitive_month, buffer + 2);
918   ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
919   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
920   strcpy(month, buffer);
921   ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
922 
923   ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
924   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
925   strcpy(short_day, buffer);
926 
927   STRINGSA("dd MMMMddd dd", "");
928   sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
929   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
930   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
931   EXPECT_EQA;
932 
933   STRINGSA("MMMMddd dd", "");
934   sprintf(Expected, "%s%s 04", month, short_day);
935   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
936   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
937   EXPECT_EQA;
938 
939   STRINGSA("MMMMddd", "");
940   sprintf(Expected, "%s%s", month, short_day);
941   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
942   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
943   EXPECT_EQA;
944 
945   STRINGSA("MMMMdd", "");
946   sprintf(Expected, "%s04", genitive_month);
947   sprintf(Broken, "%s04", month);
948   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
949   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
950   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
951      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
952      "Expected '%s', got '%s'\n", Expected, buffer);
953 
954   STRINGSA("MMMMdd ddd", "");
955   sprintf(Expected, "%s04 %s", genitive_month, short_day);
956   sprintf(Broken, "%s04 %s", month, short_day);
957   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
958   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
959   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
960      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
961      "Expected '%s', got '%s'\n", Expected, buffer);
962 
963   STRINGSA("dd dddMMMM", "");
964   sprintf(Expected, "04 %s%s", short_day, month);
965   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
966   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
967   EXPECT_EQA;
968 
969   STRINGSA("dd dddMMMM ddd MMMMdd", "");
970   sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
971   sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
972   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
973   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
974   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
975      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
976      "Expected '%s', got '%s'\n", Expected, buffer);
977 
978   /* with literal part */
979   STRINGSA("ddd',' MMMM dd", "");
980   sprintf(Expected, "%s, %s 04", short_day, genitive_month);
981   sprintf(Broken, "%s, %s 04", short_day, month);
982   ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
983   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
984   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
985      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
986      "Expected '%s', got '%s'\n", Expected, buffer);
987 }
988 
989 static void test_GetDateFormatEx(void)
990 {
991   int ret;
992   SYSTEMTIME  curtime;
993   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
994 
995   if (!pGetDateFormatEx)
996   {
997       win_skip("GetDateFormatEx not supported\n");
998       return;
999   }
1000 
1001   STRINGSW("",""); /* If flags are set, then format must be NULL */
1002   SetLastError(0xdeadbeef);
1003   ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1004                        input, buffer, COUNTOF(buffer), NULL);
1005   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1006      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1007   EXPECT_EQW;
1008 
1009   STRINGSW("",""); /* NULL buffer, len > 0 */
1010   SetLastError(0xdeadbeef);
1011   ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1012   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1013       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1014 
1015   STRINGSW("",""); /* NULL buffer, len == 0 */
1016   ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1017   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1018   EXPECT_LENW; EXPECT_EQW;
1019 
1020   STRINGSW("",""); /* Invalid flag combination */
1021   SetLastError(0xdeadbeef);
1022   ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1023                        input, NULL, 0, NULL);
1024   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1025      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1026   EXPECT_EQW;
1027 
1028   curtime.wYear = 2002;
1029   curtime.wMonth = 10;
1030   curtime.wDay = 23;
1031   curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1032   curtime.wHour = 65432; /* Invalid */
1033   curtime.wMinute = 34512; /* Invalid */
1034   curtime.wSecond = 65535; /* Invalid */
1035   curtime.wMilliseconds = 12345;
1036   STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1037   ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1038   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1039   EXPECT_LENW; EXPECT_EQW;
1040 
1041   curtime.wYear = 2002;
1042   curtime.wMonth = 10;
1043   curtime.wDay = 23;
1044   curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1045   curtime.wHour = 65432; /* Invalid */
1046   curtime.wMinute = 34512; /* Invalid */
1047   curtime.wSecond = 65535; /* Invalid */
1048   curtime.wMilliseconds = 12345;
1049   STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1050   ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1051   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1052       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1053 
1054   /* Limit tests */
1055 
1056   curtime.wYear = 1601;
1057   curtime.wMonth = 1;
1058   curtime.wDay = 1;
1059   curtime.wDayOfWeek = 0; /* Irrelevant */
1060   curtime.wHour = 0;
1061   curtime.wMinute = 0;
1062   curtime.wSecond = 0;
1063   curtime.wMilliseconds = 0;
1064   STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1065   SetLastError(0xdeadbeef);
1066   ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1067   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1068   EXPECT_LENW; EXPECT_EQW;
1069 
1070   curtime.wYear = 1600;
1071   curtime.wMonth = 12;
1072   curtime.wDay = 31;
1073   curtime.wDayOfWeek = 0; /* Irrelevant */
1074   curtime.wHour = 23;
1075   curtime.wMinute = 59;
1076   curtime.wSecond = 59;
1077   curtime.wMilliseconds = 999;
1078   STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1079   SetLastError(0xdeadbeef);
1080   ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1081   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1082       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1083 }
1084 
1085 static void test_GetDateFormatW(void)
1086 {
1087   int ret;
1088   SYSTEMTIME  curtime;
1089   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1090   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1091 
1092   STRINGSW("",""); /* If flags is not zero then format must be NULL */
1093   ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1094                        input, buffer, COUNTOF(buffer));
1095   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1096   {
1097     win_skip("GetDateFormatW is not implemented\n");
1098     return;
1099   }
1100   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1101      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1102   EXPECT_EQW;
1103 
1104   STRINGSW("",""); /* NULL buffer, len > 0 */
1105   SetLastError(0xdeadbeef);
1106   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1107   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1108       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1109 
1110   STRINGSW("",""); /* NULL buffer, len == 0 */
1111   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1112   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1113   EXPECT_LENW; EXPECT_EQW;
1114 
1115   curtime.wYear = 2002;
1116   curtime.wMonth = 10;
1117   curtime.wDay = 23;
1118   curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1119   curtime.wHour = 65432; /* Invalid */
1120   curtime.wMinute = 34512; /* Invalid */
1121   curtime.wSecond = 65535; /* Invalid */
1122   curtime.wMilliseconds = 12345;
1123   STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1124   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1125   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1126   EXPECT_LENW; EXPECT_EQW;
1127 
1128   /* Limit tests */
1129 
1130   curtime.wYear = 1601;
1131   curtime.wMonth = 1;
1132   curtime.wDay = 1;
1133   curtime.wDayOfWeek = 0; /* Irrelevant */
1134   curtime.wHour = 0;
1135   curtime.wMinute = 0;
1136   curtime.wSecond = 0;
1137   curtime.wMilliseconds = 0;
1138   STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1139   SetLastError(0xdeadbeef);
1140   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1141   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1142   EXPECT_LENW; EXPECT_EQW;
1143 
1144   curtime.wYear = 1600;
1145   curtime.wMonth = 12;
1146   curtime.wDay = 31;
1147   curtime.wDayOfWeek = 0; /* Irrelevant */
1148   curtime.wHour = 23;
1149   curtime.wMinute = 59;
1150   curtime.wSecond = 59;
1151   curtime.wMilliseconds = 999;
1152   STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1153   SetLastError(0xdeadbeef);
1154   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1155   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1156       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1157 }
1158 
1159 
1160 #define CY_POS_LEFT  0
1161 #define CY_POS_RIGHT 1
1162 #define CY_POS_LEFT_SPACE  2
1163 #define CY_POS_RIGHT_SPACE 3
1164 
1165 static void test_GetCurrencyFormatA(void)
1166 {
1167   static char szDot[] = { '.', '\0' };
1168   static char szComma[] = { ',', '\0' };
1169   static char szDollar[] = { '$', '\0' };
1170   int ret;
1171   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1172   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1173   CURRENCYFMTA format;
1174 
1175   memset(&format, 0, sizeof(format));
1176 
1177   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1178   SetLastError(0xdeadbeef);
1179   ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1180   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1181       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1182 
1183   STRINGSA("23,53",""); /* Invalid character --> Error */
1184   SetLastError(0xdeadbeef);
1185   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1186   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1187       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1188 
1189   STRINGSA("--",""); /* Double '-' --> Error */
1190   SetLastError(0xdeadbeef);
1191   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1192   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1193       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1194 
1195   STRINGSA("0-",""); /* Trailing '-' --> Error */
1196   SetLastError(0xdeadbeef);
1197   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1198   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1199       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1200 
1201   STRINGSA("0..",""); /* Double '.' --> Error */
1202   SetLastError(0xdeadbeef);
1203   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1204   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1205       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1206 
1207   STRINGSA(" 0.1",""); /* Leading space --> Error */
1208   SetLastError(0xdeadbeef);
1209   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1210   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1211       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1212 
1213   STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1214   SetLastError(0xdeadbeef);
1215   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1216   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1217       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1218 
1219   STRINGSA("2353",""); /* Format and flags given --> Error */
1220   SetLastError(0xdeadbeef);
1221   ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1222   ok( !ret, "Expected ret == 0, got %d\n", ret);
1223   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1224       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1225 
1226   STRINGSA("2353",""); /* Invalid format --> Error */
1227   SetLastError(0xdeadbeef);
1228   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1229   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1230       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1231 
1232   STRINGSA("2353","$2,353.00"); /* Valid number */
1233   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1234   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1235   EXPECT_LENA; EXPECT_EQA;
1236 
1237   STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1238   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1239   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1240   EXPECT_LENA; EXPECT_EQA;
1241 
1242   STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1243   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1244   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1245   EXPECT_LENA; EXPECT_EQA;
1246 
1247   STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1248   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1249   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1250   EXPECT_LENA; EXPECT_EQA;
1251 
1252   STRINGSA("2353.119","$2,353.12");  /* Too many DP --> Rounded */
1253   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1254   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1255   EXPECT_LENA; EXPECT_EQA;
1256 
1257   format.NumDigits = 0; /* No decimal separator */
1258   format.LeadingZero = 0;
1259   format.Grouping = 0;  /* No grouping char */
1260   format.NegativeOrder = 0;
1261   format.PositiveOrder = CY_POS_LEFT;
1262   format.lpDecimalSep = szDot;
1263   format.lpThousandSep = szComma;
1264   format.lpCurrencySymbol = szDollar;
1265 
1266   STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1267   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1268   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1269   EXPECT_LENA; EXPECT_EQA;
1270 
1271   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1272   STRINGSA("2353","$2353.0");
1273   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1274   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1275   EXPECT_LENA; EXPECT_EQA;
1276 
1277   format.Grouping = 2; /* Group by 100's */
1278   STRINGSA("2353","$23,53.0");
1279   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1280   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1281   EXPECT_LENA; EXPECT_EQA;
1282 
1283   STRINGSA("235","$235.0"); /* Grouping of a positive number */
1284   format.Grouping = 3;
1285   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1286   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1287   EXPECT_LENA; EXPECT_EQA;
1288 
1289   STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1290   format.NegativeOrder = 2;
1291   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1292   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1293   EXPECT_LENA; EXPECT_EQA;
1294 
1295   format.LeadingZero = 1; /* Always provide leading zero */
1296   STRINGSA(".5","$0.5");
1297   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1298   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1299   EXPECT_LENA; EXPECT_EQA;
1300 
1301   format.PositiveOrder = CY_POS_RIGHT;
1302   STRINGSA("1","1.0$");
1303   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1304   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1305   EXPECT_LENA; EXPECT_EQA;
1306 
1307   format.PositiveOrder = CY_POS_LEFT_SPACE;
1308   STRINGSA("1","$ 1.0");
1309   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1310   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1311   EXPECT_LENA; EXPECT_EQA;
1312 
1313   format.PositiveOrder = CY_POS_RIGHT_SPACE;
1314   STRINGSA("1","1.0 $");
1315   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1316   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1317   EXPECT_LENA; EXPECT_EQA;
1318 
1319   format.NegativeOrder = 0;
1320   STRINGSA("-1","($1.0)");
1321   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1322   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1323   EXPECT_LENA; EXPECT_EQA;
1324 
1325   format.NegativeOrder = 1;
1326   STRINGSA("-1","-$1.0");
1327   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1328   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1329   EXPECT_LENA; EXPECT_EQA;
1330 
1331   format.NegativeOrder = 2;
1332   STRINGSA("-1","$-1.0");
1333   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1334   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1335   EXPECT_LENA; EXPECT_EQA;
1336 
1337   format.NegativeOrder = 3;
1338   STRINGSA("-1","$1.0-");
1339   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1340   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1341   EXPECT_LENA; EXPECT_EQA;
1342 
1343   format.NegativeOrder = 4;
1344   STRINGSA("-1","(1.0$)");
1345   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1346   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1347   EXPECT_LENA; EXPECT_EQA;
1348 
1349   format.NegativeOrder = 5;
1350   STRINGSA("-1","-1.0$");
1351   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1352   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1353   EXPECT_LENA; EXPECT_EQA;
1354 
1355   format.NegativeOrder = 6;
1356   STRINGSA("-1","1.0-$");
1357   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1358   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1359   EXPECT_LENA; EXPECT_EQA;
1360 
1361   format.NegativeOrder = 7;
1362   STRINGSA("-1","1.0$-");
1363   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1364   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1365   EXPECT_LENA; EXPECT_EQA;
1366 
1367   format.NegativeOrder = 8;
1368   STRINGSA("-1","-1.0 $");
1369   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1370   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1371   EXPECT_LENA; EXPECT_EQA;
1372 
1373   format.NegativeOrder = 9;
1374   STRINGSA("-1","-$ 1.0");
1375   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1376   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1377   EXPECT_LENA; EXPECT_EQA;
1378 
1379   format.NegativeOrder = 10;
1380   STRINGSA("-1","1.0 $-");
1381   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1382   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1383   EXPECT_LENA; EXPECT_EQA;
1384 
1385   format.NegativeOrder = 11;
1386   STRINGSA("-1","$ 1.0-");
1387   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1388   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1389   EXPECT_LENA; EXPECT_EQA;
1390 
1391   format.NegativeOrder = 12;
1392   STRINGSA("-1","$ -1.0");
1393   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1394   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1395   EXPECT_LENA; EXPECT_EQA;
1396 
1397   format.NegativeOrder = 13;
1398   STRINGSA("-1","1.0- $");
1399   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1400   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1401   EXPECT_LENA; EXPECT_EQA;
1402 
1403   format.NegativeOrder = 14;
1404   STRINGSA("-1","($ 1.0)");
1405   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1406   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1407   EXPECT_LENA; EXPECT_EQA;
1408 
1409   format.NegativeOrder = 15;
1410   STRINGSA("-1","(1.0 $)");
1411   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1412   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1413   EXPECT_LENA; EXPECT_EQA;
1414 }
1415 
1416 #define NEG_PARENS      0 /* "(1.1)" */
1417 #define NEG_LEFT        1 /* "-1.1"  */
1418 #define NEG_LEFT_SPACE  2 /* "- 1.1" */
1419 #define NEG_RIGHT       3 /* "1.1-"  */
1420 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1421 
1422 static void test_GetNumberFormatA(void)
1423 {
1424   static char szDot[] = { '.', '\0' };
1425   static char szComma[] = { ',', '\0' };
1426   int ret;
1427   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1428   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1429   NUMBERFMTA format;
1430 
1431   memset(&format, 0, sizeof(format));
1432 
1433   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1434   SetLastError(0xdeadbeef);
1435   ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1436   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1437       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1438 
1439   STRINGSA("23,53",""); /* Invalid character --> Error */
1440   SetLastError(0xdeadbeef);
1441   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1442   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1443       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1444 
1445   STRINGSA("--",""); /* Double '-' --> Error */
1446   SetLastError(0xdeadbeef);
1447   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1448   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1449       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1450 
1451   STRINGSA("0-",""); /* Trailing '-' --> Error */
1452   SetLastError(0xdeadbeef);
1453   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1454   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1455       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1456 
1457   STRINGSA("0..",""); /* Double '.' --> Error */
1458   SetLastError(0xdeadbeef);
1459   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1460   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1461       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1462 
1463   STRINGSA(" 0.1",""); /* Leading space --> Error */
1464   SetLastError(0xdeadbeef);
1465   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1466   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1467       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1468 
1469   STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1470   SetLastError(0xdeadbeef);
1471   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1472   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1473       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1474 
1475   STRINGSA("2353",""); /* Format and flags given --> Error */
1476   SetLastError(0xdeadbeef);
1477   ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1478   ok( !ret, "Expected ret == 0, got %d\n", ret);
1479   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1480       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1481 
1482   STRINGSA("2353",""); /* Invalid format --> Error */
1483   SetLastError(0xdeadbeef);
1484   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1485   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1486       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1487 
1488   STRINGSA("2353","2,353.00"); /* Valid number */
1489   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1490   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1491   EXPECT_LENA; EXPECT_EQA;
1492 
1493   STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1494   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1495   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1496   EXPECT_LENA; EXPECT_EQA;
1497 
1498   STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1499   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1500   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1501   EXPECT_LENA; EXPECT_EQA;
1502 
1503   STRINGSA("2353.1","2,353.10"); /* Valid real number */
1504   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1505   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1506   EXPECT_LENA; EXPECT_EQA;
1507 
1508   STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1509   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1510   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1511   EXPECT_LENA; EXPECT_EQA;
1512 
1513   STRINGSA("2353.119","2,353.12");  /* Too many DP --> Rounded */
1514   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1515   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1516   EXPECT_LENA; EXPECT_EQA;
1517 
1518   format.NumDigits = 0; /* No decimal separator */
1519   format.LeadingZero = 0;
1520   format.Grouping = 0;  /* No grouping char */
1521   format.NegativeOrder = 0;
1522   format.lpDecimalSep = szDot;
1523   format.lpThousandSep = szComma;
1524 
1525   STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1526   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1527   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1528   EXPECT_LENA; EXPECT_EQA;
1529 
1530   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1531   STRINGSA("2353","2353.0");
1532   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1533   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1534   EXPECT_LENA; EXPECT_EQA;
1535 
1536   format.Grouping = 2; /* Group by 100's */
1537   STRINGSA("2353","23,53.0");
1538   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1539   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1540   EXPECT_LENA; EXPECT_EQA;
1541 
1542   STRINGSA("235","235.0"); /* Grouping of a positive number */
1543   format.Grouping = 3;
1544   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1545   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1546   EXPECT_LENA; EXPECT_EQA;
1547 
1548   STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1549   format.NegativeOrder = NEG_LEFT;
1550   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1551   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1552   EXPECT_LENA; EXPECT_EQA;
1553 
1554   format.LeadingZero = 1; /* Always provide leading zero */
1555   STRINGSA(".5","0.5");
1556   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1557   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1558   EXPECT_LENA; EXPECT_EQA;
1559 
1560   format.NegativeOrder = NEG_PARENS;
1561   STRINGSA("-1","(1.0)");
1562   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1563   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1564   EXPECT_LENA; EXPECT_EQA;
1565 
1566   format.NegativeOrder = NEG_LEFT;
1567   STRINGSA("-1","-1.0");
1568   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1569   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1570   EXPECT_LENA; EXPECT_EQA;
1571 
1572   format.NegativeOrder = NEG_LEFT_SPACE;
1573   STRINGSA("-1","- 1.0");
1574   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1575   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1576   EXPECT_LENA; EXPECT_EQA;
1577 
1578   format.NegativeOrder = NEG_RIGHT;
1579   STRINGSA("-1","1.0-");
1580   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1581   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1582   EXPECT_LENA; EXPECT_EQA;
1583 
1584   format.NegativeOrder = NEG_RIGHT_SPACE;
1585   STRINGSA("-1","1.0 -");
1586   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1587   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1588   EXPECT_LENA; EXPECT_EQA;
1589 
1590   lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1591 
1592   if (IsValidLocale(lcid, 0))
1593   {
1594     STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1595     Expected[3] = 160; /* Non breaking space */
1596     ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1597     ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1598     EXPECT_LENA; EXPECT_EQA;
1599   }
1600 }
1601 
1602 static void test_GetNumberFormatEx(void)
1603 {
1604   int ret;
1605   NUMBERFMTW format;
1606   static WCHAR dotW[] = {'.',0};
1607   static WCHAR commaW[] = {',',0};
1608   static const WCHAR enW[] = {'e','n','-','U','S',0};
1609   static const WCHAR frW[] = {'f','r','-','F','R',0};
1610   static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1611   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1612 
1613   if (!pGetNumberFormatEx)
1614   {
1615     win_skip("GetNumberFormatEx is not available.\n");
1616     return;
1617   }
1618 
1619   STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1620   ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1621   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1622       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1623 
1624   STRINGSW("23,53",""); /* Invalid character --> Error */
1625   ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1626   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1627       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1628 
1629   STRINGSW("--",""); /* Double '-' --> Error */
1630   ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1631   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1632       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1633 
1634   STRINGSW("0-",""); /* Trailing '-' --> Error */
1635   ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1636   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1637       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1638 
1639   STRINGSW("0..",""); /* Double '.' --> Error */
1640   ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1641   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1642       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1643 
1644   STRINGSW(" 0.1",""); /* Leading space --> Error */
1645   ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1646   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1647       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1648 
1649   STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1650   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1651   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1652       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1653 
1654   STRINGSW("23",""); /* Bogus locale --> Error */
1655   ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1656   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1657       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1658 
1659   memset(&format, 0, sizeof(format));
1660 
1661   STRINGSW("2353",""); /* Format and flags given --> Error */
1662   ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1663   ok( !ret, "Expected ret == 0, got %d\n", ret);
1664   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1665       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1666 
1667   STRINGSW("2353",""); /* Invalid format --> Error */
1668   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1669   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1670       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1671 
1672   STRINGSW("2353","2,353.00"); /* Valid number */
1673   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1674   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1675   EXPECT_LENW; EXPECT_EQW;
1676 
1677   STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1678   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1679   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1680   EXPECT_LENW; EXPECT_EQW;
1681 
1682   STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1683   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1684   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1685   EXPECT_LENW; EXPECT_EQW;
1686 
1687   STRINGSW("2353.1","2,353.10"); /* Valid real number */
1688   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1689   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1690   EXPECT_LENW; EXPECT_EQW;
1691 
1692   STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1693   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1694   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1695   EXPECT_LENW; EXPECT_EQW;
1696 
1697   STRINGSW("2353.119","2,353.12");  /* Too many DP --> Rounded */
1698   ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1699   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1700   EXPECT_LENW; EXPECT_EQW;
1701 
1702   format.NumDigits = 0; /* No decimal separator */
1703   format.LeadingZero = 0;
1704   format.Grouping = 0;  /* No grouping char */
1705   format.NegativeOrder = 0;
1706   format.lpDecimalSep = dotW;
1707   format.lpThousandSep = commaW;
1708 
1709   STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1710   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1711   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1712   EXPECT_LENW; EXPECT_EQW;
1713 
1714   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1715   STRINGSW("2353","2353.0");
1716   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1717   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1718   EXPECT_LENW; EXPECT_EQW;
1719 
1720   format.Grouping = 2; /* Group by 100's */
1721   STRINGSW("2353","23,53.0");
1722   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1723   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1724   EXPECT_LENW; EXPECT_EQW;
1725 
1726   STRINGSW("235","235.0"); /* Grouping of a positive number */
1727   format.Grouping = 3;
1728   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1729   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1730   EXPECT_LENW; EXPECT_EQW;
1731 
1732   STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1733   format.NegativeOrder = NEG_LEFT;
1734   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1735   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1736   EXPECT_LENW; EXPECT_EQW;
1737 
1738   format.LeadingZero = 1; /* Always provide leading zero */
1739   STRINGSW(".5","0.5");
1740   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1741   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1742   EXPECT_LENW; EXPECT_EQW;
1743 
1744   format.NegativeOrder = NEG_PARENS;
1745   STRINGSW("-1","(1.0)");
1746   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1747   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1748   EXPECT_LENW; EXPECT_EQW;
1749 
1750   format.NegativeOrder = NEG_LEFT;
1751   STRINGSW("-1","-1.0");
1752   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1753   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1754   EXPECT_LENW; EXPECT_EQW;
1755 
1756   format.NegativeOrder = NEG_LEFT_SPACE;
1757   STRINGSW("-1","- 1.0");
1758   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1759   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1760   EXPECT_LENW; EXPECT_EQW;
1761 
1762   format.NegativeOrder = NEG_RIGHT;
1763   STRINGSW("-1","1.0-");
1764   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1765   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1766   EXPECT_LENW; EXPECT_EQW;
1767 
1768   format.NegativeOrder = NEG_RIGHT_SPACE;
1769   STRINGSW("-1","1.0 -");
1770   ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1771   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1772   EXPECT_LENW; EXPECT_EQW;
1773 
1774   if (pIsValidLocaleName(frW))
1775   {
1776     STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1777     Expected[3] = 160; /* Non breaking space */
1778     ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1779     ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1780     EXPECT_LENW; EXPECT_EQW;
1781   }
1782 }
1783 
1784 struct comparestringa_entry {
1785   LCID lcid;
1786   DWORD flags;
1787   const char *first;
1788   int first_len;
1789   const char *second;
1790   int second_len;
1791   int ret;
1792 };
1793 
1794 static const struct comparestringa_entry comparestringa_data[] = {
1795   { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1796   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1797   { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1798   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1799   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1800   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1801   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1802   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1803   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1804   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1805   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1806   { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1807   { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1808   { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1809   { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1810   { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1811   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1812   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1813   { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1814   /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1815   { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1816   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1817   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1818   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1819   { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1820   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1821   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1822   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1823   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1824   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1825   { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1826   { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1827   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1828   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1829   { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1830   { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1831   { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1832   { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1833   { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1834   { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1835   { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1836   { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1837   { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1838   { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1839 };
1840 
1841 static void test_CompareStringA(void)
1842 {
1843   int ret, i;
1844   char a[256];
1845   LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1846 
1847   for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1848   {
1849       const struct comparestringa_entry *entry = &comparestringa_data[i];
1850 
1851       ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1852           entry->second, entry->second_len);
1853       ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1854   }
1855 
1856   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1857   ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1858 
1859   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1860   ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1861 
1862   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1863   ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1864 
1865   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1866   ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1867 
1868   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1869 
1870   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1871   ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1872 
1873   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1874   ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1875 
1876     ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1877     ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1878 
1879     /* test for CompareStringA flags */
1880     SetLastError(0xdeadbeef);
1881     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1882     ok(GetLastError() == ERROR_INVALID_FLAGS,
1883         "unexpected error code %d\n", GetLastError());
1884     ok(!ret, "CompareStringA must fail with invalid flag\n");
1885 
1886     SetLastError(0xdeadbeef);
1887     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1888     ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1889     ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1890     /* end of test for CompareStringA flags */
1891 
1892     ret = lstrcmpA("", "");
1893     ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1894 
1895     ret = lstrcmpA(NULL, NULL);
1896     ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1897 
1898     ret = lstrcmpA("", NULL);
1899     ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1900 
1901     ret = lstrcmpA(NULL, "");
1902     ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1903 
1904 
1905     if (0) { /* this requires collation table patch to make it MS compatible */
1906     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1907     ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1908 
1909     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1910     ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1911 
1912     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1913     ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1914 
1915     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1916     ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1917 
1918     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1919     ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1920 
1921     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1922     ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1923 
1924     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1925     ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1926 
1927     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1928     ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1929 
1930     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1931     ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1932 
1933     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1934     ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1935 
1936     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1937     ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1938 
1939     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1940     ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1941     }
1942 
1943 
1944     /* WinXP handles embedded NULLs differently than earlier versions */
1945     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1946     ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1947 
1948     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1949     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);
1950 
1951     ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1952     ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1953 
1954     ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1955     ok(ret == CSTR_EQUAL || /* win2k */
1956        ret == CSTR_GREATER_THAN,
1957        "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1958 
1959     ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1960     todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1961 
1962     ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1963     ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1964 
1965     ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1966     ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1967 
1968     ret = lstrcmpiA("#", ".");
1969     ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1970 
1971     lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1972 
1973     /* \xB9 character lies between a and b */
1974     ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1975     todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1976     ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1977     ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1978 
1979     memset(a, 'a', sizeof(a));
1980     SetLastError(0xdeadbeef);
1981     ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1982     ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1983         "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1984 }
1985 
1986 static void test_CompareStringW(void)
1987 {
1988     WCHAR *str1, *str2;
1989     SYSTEM_INFO si;
1990     DWORD old_prot;
1991     BOOL success;
1992     char *buf;
1993     int ret;
1994 
1995     GetSystemInfo(&si);
1996     buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1997     ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1998     success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1999     ok(success, "VirtualProtect failed with %u\n", GetLastError());
2000     success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2001     ok(success, "VirtualProtect failed with %u\n", GetLastError());
2002 
2003     str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2004     str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2005     *str1 = 'A';
2006     *str2 = 'B';
2007 
2008     /* CompareStringW should abort on the first non-matching character */
2009     ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2010     ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2011 
2012     success = VirtualFree(buf, 0, MEM_RELEASE);
2013     ok(success, "VirtualFree failed with %u\n", GetLastError());
2014 }
2015 
2016 struct comparestringex_test {
2017     const char *locale;
2018     DWORD flags;
2019     const WCHAR first[2];
2020     const WCHAR second[2];
2021     INT ret;
2022     INT broken;
2023     BOOL todo;
2024 };
2025 
2026 static const struct comparestringex_test comparestringex_tests[] = {
2027     /* default behavior */
2028     { /* 0 */
2029       "tr-TR", 0,
2030       {'i',0},   {'I',0},   CSTR_LESS_THAN,    -1,                FALSE
2031     },
2032     { /* 1 */
2033       "tr-TR", 0,
2034       {'i',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                FALSE
2035     },
2036     { /* 2 */
2037       "tr-TR", 0,
2038       {'i',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2039     },
2040     { /* 3 */
2041       "tr-TR", 0,
2042       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2043     },
2044     { /* 4 */
2045       "tr-TR", 0,
2046       {'I',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2047     },
2048     { /* 5 */
2049       "tr-TR", 0,
2050       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1,                TRUE
2051     },
2052     /* with NORM_IGNORECASE */
2053     { /* 6 */
2054       "tr-TR", NORM_IGNORECASE,
2055       {'i',0},   {'I',0},   CSTR_EQUAL,        -1,                FALSE
2056     },
2057     { /* 7 */
2058       "tr-TR", NORM_IGNORECASE,
2059       {'i',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2060     },
2061     { /* 8 */
2062       "tr-TR", NORM_IGNORECASE,
2063       {'i',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2064     },
2065     { /* 9 */
2066       "tr-TR", NORM_IGNORECASE,
2067       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2068     },
2069     { /* 10 */
2070       "tr-TR", NORM_IGNORECASE,
2071       {'I',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2072     },
2073     { /* 11 */
2074       "tr-TR", NORM_IGNORECASE,
2075       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1,                TRUE
2076     },
2077     /* with NORM_LINGUISTIC_CASING */
2078     { /* 12 */
2079       "tr-TR", NORM_LINGUISTIC_CASING,
2080       {'i',0},   {'I',0},   CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2081     },
2082     { /* 13 */
2083       "tr-TR", NORM_LINGUISTIC_CASING,
2084       {'i',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                FALSE
2085     },
2086     { /* 14 */
2087       "tr-TR", NORM_LINGUISTIC_CASING,
2088       {'i',0},   {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2089     },
2090     { /* 15 */
2091       "tr-TR", NORM_LINGUISTIC_CASING,
2092       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2093     },
2094     { /* 16 */
2095       "tr-TR", NORM_LINGUISTIC_CASING,
2096       {'I',0},   {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2097     },
2098     { /* 17 */
2099       "tr-TR", NORM_LINGUISTIC_CASING,
2100       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1,                TRUE
2101     },
2102     /* with LINGUISTIC_IGNORECASE */
2103     { /* 18 */
2104       "tr-TR", LINGUISTIC_IGNORECASE,
2105       {'i',0},   {'I',0},   CSTR_EQUAL,        -1,                TRUE
2106     },
2107     { /* 19 */
2108       "tr-TR", LINGUISTIC_IGNORECASE,
2109       {'i',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                FALSE
2110     },
2111     { /* 20 */
2112       "tr-TR", LINGUISTIC_IGNORECASE,
2113       {'i',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2114     },
2115     { /* 21 */
2116       "tr-TR", LINGUISTIC_IGNORECASE,
2117       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2118     },
2119     { /* 22 */
2120       "tr-TR", LINGUISTIC_IGNORECASE,
2121       {'I',0},   {0x131,0}, CSTR_LESS_THAN,    -1,                FALSE
2122     },
2123     { /* 23 */
2124       "tr-TR", LINGUISTIC_IGNORECASE,
2125       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1,                TRUE
2126     },
2127     /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2128     { /* 24 */
2129       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2130       {'i',0},   {'I',0},   CSTR_GREATER_THAN, CSTR_EQUAL,        TRUE
2131     },
2132     { /* 25 */
2133       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2134       {'i',0},   {0x130,0}, CSTR_EQUAL,        CSTR_LESS_THAN,    FALSE
2135     },
2136     { /* 26 */
2137       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2138       {'i',0},   {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2139     },
2140     { /* 27 */
2141       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2142       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2143      },
2144     { /* 28 */
2145       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2146       {'I',0},   {0x131,0}, CSTR_EQUAL,        CSTR_LESS_THAN,    TRUE
2147     },
2148     { /* 29 */
2149       "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2150       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1,                TRUE
2151     },
2152     /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2153     { /* 30 */
2154       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2155       {'i',0},   {'I',0},   CSTR_GREATER_THAN, CSTR_EQUAL,        TRUE
2156     },
2157     { /* 31 */
2158       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2159       {'i',0},   {0x130,0}, CSTR_EQUAL,        CSTR_LESS_THAN,    TRUE
2160     },
2161     { /* 32 */
2162       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2163       {'i',0},   {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2164     },
2165     { /* 33 */
2166       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2167       {'I',0},   {0x130,0}, CSTR_LESS_THAN,    -1,                TRUE
2168     },
2169     { /* 34 */
2170       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2171       {'I',0},   {0x131,0}, CSTR_EQUAL,        CSTR_LESS_THAN,    TRUE
2172     },
2173     { /* 35 */
2174       "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2175       {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN,    TRUE
2176     }
2177 };
2178 
2179 static void test_CompareStringEx(void)
2180 {
2181     const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2182     WCHAR locale[6];
2183     INT ret, i;
2184 
2185     /* CompareStringEx is only available on Vista+ */
2186     if (!pCompareStringEx)
2187     {
2188         win_skip("CompareStringEx not supported\n");
2189         return;
2190     }
2191 
2192     for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2193     {
2194         const struct comparestringex_test *e = &comparestringex_tests[i];
2195 
2196         MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2197         ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2198         todo_wine_if (e->todo)
2199             ok(ret == e->ret || broken(ret == e->broken),
2200                "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2201     }
2202 
2203 }
2204 
2205 static const DWORD lcmap_invalid_flags[] = {
2206     0,
2207     LCMAP_HIRAGANA | LCMAP_KATAKANA,
2208     LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2209     LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2210     LCMAP_LOWERCASE | SORT_STRINGSORT,
2211     LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2212     LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2213     LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2214     LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2215     LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2216     LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2217     LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2218     LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2219     LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2220     LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2221     LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2222     LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2223     LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2224     LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2225     LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2226     LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2227     LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2228     LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2229     LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2230     LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2231 };
2232 
2233 static void test_LCMapStringA(void)
2234 {
2235     int ret, ret2, i;
2236     char buf[256], buf2[256];
2237     static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2238     static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2239     static const char symbols_stripped[] = "justateststring1";
2240 
2241     SetLastError(0xdeadbeef);
2242     ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2243                        lower_case, -1, buf, sizeof(buf));
2244     ok(ret == lstrlenA(lower_case) + 1,
2245        "ret %d, error %d, expected value %d\n",
2246        ret, GetLastError(), lstrlenA(lower_case) + 1);
2247     ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2248 
2249     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2250                        upper_case, -1, buf, sizeof(buf));
2251     ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2252     ok(GetLastError() == ERROR_INVALID_FLAGS,
2253        "unexpected error code %d\n", GetLastError());
2254 
2255     /* test invalid flag combinations */
2256     for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2257         lstrcpyA(buf, "foo");
2258         SetLastError(0xdeadbeef);
2259         ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2260                            lower_case, -1, buf, sizeof(buf));
2261         ok(GetLastError() == ERROR_INVALID_FLAGS,
2262            "LCMapStringA (flag %08x) unexpected error code %d\n",
2263            lcmap_invalid_flags[i], GetLastError());
2264         ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2265            lcmap_invalid_flags[i], ret);
2266     }
2267 
2268     /* test LCMAP_LOWERCASE */
2269     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2270                        upper_case, -1, buf, sizeof(buf));
2271     ok(ret == lstrlenA(upper_case) + 1,
2272        "ret %d, error %d, expected value %d\n",
2273        ret, GetLastError(), lstrlenA(upper_case) + 1);
2274     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2275 
2276     /* test LCMAP_UPPERCASE */
2277     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2278                        lower_case, -1, buf, sizeof(buf));
2279     ok(ret == lstrlenA(lower_case) + 1,
2280        "ret %d, error %d, expected value %d\n",
2281        ret, GetLastError(), lstrlenA(lower_case) + 1);
2282     ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2283 
2284     /* test buffer overflow */
2285     SetLastError(0xdeadbeef);
2286     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2287                        lower_case, -1, buf, 4);
2288     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2289        "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2290 
2291     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2292     lstrcpyA(buf, lower_case);
2293     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2294                        buf, -1, buf, sizeof(buf));
2295     if (!ret) /* Win9x */
2296         trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2297     else
2298     {
2299         ok(ret == lstrlenA(lower_case) + 1,
2300            "ret %d, error %d, expected value %d\n",
2301            ret, GetLastError(), lstrlenA(lower_case) + 1);
2302         ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2303     }
2304     lstrcpyA(buf, upper_case);
2305     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2306                        buf, -1, buf, sizeof(buf));
2307     if (!ret) /* Win9x */
2308         trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2309     else
2310     {
2311         ok(ret == lstrlenA(upper_case) + 1,
2312            "ret %d, error %d, expected value %d\n",
2313            ret, GetLastError(), lstrlenA(lower_case) + 1);
2314         ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2315     }
2316 
2317     /* otherwise src == dst should fail */
2318     SetLastError(0xdeadbeef);
2319     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2320                        buf, 10, buf, sizeof(buf));
2321     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2322        GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2323        "unexpected error code %d\n", GetLastError());
2324     ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2325 
2326     /* test whether '\0' is always appended */
2327     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2328                        upper_case, -1, buf, sizeof(buf));
2329     ok(ret, "LCMapStringA must succeed\n");
2330     ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2331     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2332                        upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2333     ok(ret2, "LCMapStringA must succeed\n");
2334     ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2335     ok(ret == ret2, "lengths of sort keys must be equal\n");
2336     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2337 
2338     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2339     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2340                        upper_case, -1, buf, sizeof(buf));
2341     ok(ret, "LCMapStringA must succeed\n");
2342     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2343                        lower_case, -1, buf2, sizeof(buf2));
2344     ok(ret2, "LCMapStringA must succeed\n");
2345     ok(ret == ret2, "lengths of sort keys must be equal\n");
2346     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2347 
2348     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2349        results from plain LCMAP_SORTKEY on Vista */
2350 
2351     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2352     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2353                        lower_case, -1, buf, sizeof(buf));
2354     ok(ret, "LCMapStringA must succeed\n");
2355     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2356                        symbols_stripped, -1, buf2, sizeof(buf2));
2357     ok(ret2, "LCMapStringA must succeed\n");
2358     ok(ret == ret2, "lengths of sort keys must be equal\n");
2359     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2360 
2361     /* test NORM_IGNORENONSPACE */
2362     lstrcpyA(buf, "foo");
2363     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2364                        lower_case, -1, buf, sizeof(buf));
2365     ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2366 	lstrlenA(lower_case) + 1, ret);
2367     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2368 
2369     /* test NORM_IGNORESYMBOLS */
2370     lstrcpyA(buf, "foo");
2371     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2372                        lower_case, -1, buf, sizeof(buf));
2373     ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2374 	lstrlenA(symbols_stripped) + 1, ret);
2375     ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2376 
2377     /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2378     lstrcpyA(buf, "foo");
2379     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2380                        lower_case, -1, buf, sizeof(buf));
2381     ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2382 	lstrlenA(symbols_stripped) + 1, ret);
2383     ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2384 
2385     /* test srclen = 0 */
2386     SetLastError(0xdeadbeef);
2387     ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2388     ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2389     ok(GetLastError() == ERROR_INVALID_PARAMETER,
2390        "unexpected error code %d\n", GetLastError());
2391 }
2392 
2393 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2394 
2395 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2396 {
2397     static const WCHAR japanese_text[] = {
2398         0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2399         0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2400     };
2401     static const WCHAR hiragana_text[] = {
2402         0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2403         0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2404     };
2405     static const WCHAR katakana_text[] = {
2406         0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2407         0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2408     };
2409     static const WCHAR halfwidth_text[] = {
2410         0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2411         0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2412     };
2413     int ret, ret2, i;
2414     WCHAR buf[256], buf2[256];
2415     char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2416 
2417     /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2418     ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2419                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2420     todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2421        "%s ret %d, error %d, expected value %d\n", func_name,
2422        ret, GetLastError(), lstrlenW(title_case) + 1);
2423     todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2424        "Expected title case string\n");
2425 
2426     /* test invalid flag combinations */
2427     for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2428         lstrcpyW(buf, fooW);
2429         SetLastError(0xdeadbeef);
2430         ret = func_ptr(lcmap_invalid_flags[i],
2431                            lower_case, -1, buf, sizeof(buf));
2432         ok(GetLastError() == ERROR_INVALID_FLAGS,
2433            "%s (flag %08x) unexpected error code %d\n",
2434            func_name, lcmap_invalid_flags[i], GetLastError());
2435         ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2436            func_name, lcmap_invalid_flags[i], ret);
2437     }
2438 
2439     /* test LCMAP_LOWERCASE */
2440     ret = func_ptr(LCMAP_LOWERCASE,
2441                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2442     ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2443        ret, GetLastError(), lstrlenW(upper_case) + 1);
2444     ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2445 
2446     /* test LCMAP_UPPERCASE */
2447     ret = func_ptr(LCMAP_UPPERCASE,
2448                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2449     ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2450        ret, GetLastError(), lstrlenW(lower_case) + 1);
2451     ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2452 
2453     /* test LCMAP_HIRAGANA */
2454     ret = func_ptr(LCMAP_HIRAGANA,
2455                    japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2456     ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2457        ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2458     ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2459 
2460     buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2461     ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2462     ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2463        ret, GetLastError());
2464     /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2465     ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2466        "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2467 
2468     /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2469     ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
2470                    japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2471     ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2472        ret, GetLastError(), lstrlenW(katakana_text) + 1);
2473     ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2474 
2475     /* test LCMAP_FULLWIDTH */
2476     ret = func_ptr(LCMAP_FULLWIDTH,
2477                    halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2478     ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2479        ret, GetLastError(), lstrlenW(japanese_text) + 1);
2480     ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2481 
2482     ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2483     ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2484 
2485     /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2486        (half-width katakana is converted into full-wdith hiragana) */
2487     ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
2488                    halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2489     ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2490        ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2491     ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2492 
2493     ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2494     ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2495 
2496     /* test LCMAP_HALFWIDTH */
2497     ret = func_ptr(LCMAP_HALFWIDTH,
2498                    japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2499     ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2500        ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2501     ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2502 
2503     ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2504     ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2505 
2506     /* test buffer overflow */
2507     SetLastError(0xdeadbeef);
2508     ret = func_ptr(LCMAP_UPPERCASE,
2509                        lower_case, -1, buf, 4);
2510     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2511        "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2512 
2513     /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2514        Thus, it requires two WCHARs. */
2515     buf[0] = 0x30ac;
2516     SetLastError(0xdeadbeef);
2517     ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2518     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2519        "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2520 
2521     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2522     lstrcpyW(buf, lower_case);
2523     ret = func_ptr(LCMAP_UPPERCASE,
2524                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2525     ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2526        ret, GetLastError(), lstrlenW(lower_case) + 1);
2527     ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2528 
2529     lstrcpyW(buf, upper_case);
2530     ret = func_ptr(LCMAP_LOWERCASE,
2531                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2532     ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2533        ret, GetLastError(), lstrlenW(lower_case) + 1);
2534     ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2535 
2536     /* otherwise src == dst should fail */
2537     SetLastError(0xdeadbeef);
2538     ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2539                        buf, 10, buf, sizeof(buf));
2540     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2541        GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2542        "%s unexpected error code %d\n", func_name, GetLastError());
2543     ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2544 
2545     /* test whether '\0' is always appended */
2546     ret = func_ptr(LCMAP_SORTKEY,
2547                        upper_case, -1, buf, sizeof(buf));
2548     ok(ret, "%s func_ptr must succeed\n", func_name);
2549     ret2 = func_ptr(LCMAP_SORTKEY,
2550                        upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2551     ok(ret, "%s func_ptr must succeed\n", func_name);
2552     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2553     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2554 
2555     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2556     ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2557                        upper_case, -1, buf, sizeof(buf));
2558     ok(ret, "%s func_ptr must succeed\n", func_name);
2559     ret2 = func_ptr(LCMAP_SORTKEY,
2560                        lower_case, -1, buf2, sizeof(buf2));
2561     ok(ret2, "%s func_ptr must succeed\n", func_name);
2562     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2563     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2564 
2565     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2566        results from plain LCMAP_SORTKEY on Vista */
2567 
2568     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2569     ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2570                        lower_case, -1, buf, sizeof(buf));
2571     ok(ret, "%s func_ptr must succeed\n", func_name);
2572     ret2 = func_ptr(LCMAP_SORTKEY,
2573                        symbols_stripped, -1, buf2, sizeof(buf2));
2574     ok(ret2, "%s func_ptr must succeed\n", func_name);
2575     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2576     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2577 
2578     /* test NORM_IGNORENONSPACE */
2579     lstrcpyW(buf, fooW);
2580     ret = func_ptr(NORM_IGNORENONSPACE,
2581                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2582     ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2583     lstrlenW(lower_case) + 1, ret);
2584     ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2585 
2586     /* test NORM_IGNORESYMBOLS */
2587     lstrcpyW(buf, fooW);
2588     ret = func_ptr(NORM_IGNORESYMBOLS,
2589                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2590     ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2591     lstrlenW(symbols_stripped) + 1, ret);
2592     ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2593 
2594     /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2595     lstrcpyW(buf, fooW);
2596     ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2597                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2598     ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2599     lstrlenW(symbols_stripped) + 1, ret);
2600     ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2601 
2602     /* test srclen = 0 */
2603     SetLastError(0xdeadbeef);
2604     ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2605     ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2606     ok(GetLastError() == ERROR_INVALID_PARAMETER,
2607        "%s unexpected error code %d\n", func_name, GetLastError());
2608 }
2609 
2610 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2611 {
2612     return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2613 }
2614 
2615 static void test_LCMapStringW(void)
2616 {
2617     int ret;
2618     WCHAR buf[256];
2619 
2620     trace("testing LCMapStringW\n");
2621 
2622     SetLastError(0xdeadbeef);
2623     ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2624     todo_wine {
2625     ok(!ret, "LCMapStringW should fail with bad lcid\n");
2626     ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2627     }
2628 
2629     test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2630 }
2631 
2632 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2633 {
2634     return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2635 }
2636 
2637 static void test_LCMapStringEx(void)
2638 {
2639     int ret;
2640     WCHAR buf[256];
2641 
2642     if (!pLCMapStringEx)
2643     {
2644         win_skip( "LCMapStringEx not available\n" );
2645         return;
2646     }
2647 
2648     trace("testing LCMapStringEx\n");
2649 
2650     SetLastError(0xdeadbeef);
2651     ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2652                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2653     todo_wine {
2654     ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2655     ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2656     }
2657 
2658     /* test reserved parameters */
2659     ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2660                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2661     ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2662        ret, GetLastError(), lstrlenW(upper_case) + 1);
2663     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2664 
2665     ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2666                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2667     ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2668        ret, GetLastError(), lstrlenW(upper_case) + 1);
2669     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2670 
2671     /* crashes on native */
2672     if(0)
2673         ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2674                              upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2675 
2676     test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2677 }
2678 
2679 struct neutralsublang_name_t {
2680     WCHAR name[3];
2681     WCHAR sname[16];
2682     LCID lcid;
2683     int todo;
2684 };
2685 
2686 static const struct neutralsublang_name_t neutralsublang_names[] = {
2687     { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2688     { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2689     { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2690     { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2691     { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2692     { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2693     { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2694     { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2695     { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2696     { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2697     { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2698     { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2699     { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2700     { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2701     { {0} }
2702 };
2703 
2704 static void test_LocaleNameToLCID(void)
2705 {
2706     LCID lcid;
2707     INT ret;
2708     WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2709     static const WCHAR enW[] = {'e','n',0};
2710     static const WCHAR esesW[] = {'e','s','-','e','s',0};
2711     static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
2712     static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
2713     static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
2714     static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
2715     static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
2716     static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
2717 
2718     if (!pLocaleNameToLCID)
2719     {
2720         win_skip( "LocaleNameToLCID not available\n" );
2721         return;
2722     }
2723 
2724     /* special cases */
2725     buffer[0] = 0;
2726     SetLastError(0xdeadbeef);
2727     lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2728     ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2729        "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2730     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2731     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2732     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2733 
2734     buffer[0] = 0;
2735     SetLastError(0xdeadbeef);
2736     lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2737     ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2738        "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2739     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2740     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2741     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2742 
2743     buffer[0] = 0;
2744     SetLastError(0xdeadbeef);
2745     lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2746     ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2747     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2748     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2749     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2750 
2751     /* bad name */
2752     SetLastError(0xdeadbeef);
2753     lcid = pLocaleNameToLCID(invalidW, 0);
2754     ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2755        "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2756 
2757     /* lower-case */
2758     lcid = pLocaleNameToLCID(esesW, 0);
2759     ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid);
2760 
2761     /* english neutral name */
2762     lcid = pLocaleNameToLCID(enW, 0);
2763     ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2764        broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2765     if (lcid)
2766     {
2767         const struct neutralsublang_name_t *ptr = neutralsublang_names;
2768 
2769         while (*ptr->name)
2770         {
2771             lcid = pLocaleNameToLCID(ptr->name, 0);
2772             todo_wine_if (ptr->todo)
2773                 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2774                     wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2775 
2776             *buffer = 0;
2777             ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2778             ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2779             ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
2780                 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2781 
2782             ptr++;
2783         }
2784 
2785         /* zh-Hant */
2786         lcid = pLocaleNameToLCID(zhHantW, 0);
2787         todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2788            "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid);
2789         ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2790         ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2791         todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2792            wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2793 
2794         /* zh-hant */
2795         lcid = pLocaleNameToLCID(zhhantW, 0);
2796         todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2797            "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW),
2798            MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT));
2799         ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2800         ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret);
2801         todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2802            wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer));
2803 
2804         /* zh-Hans */
2805         lcid = pLocaleNameToLCID(zhHansW, 0);
2806         todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2807            "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid);
2808         ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2809         ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2810         todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2811            wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2812 
2813         /* zh-hans */
2814         lcid = pLocaleNameToLCID(zhhansW, 0);
2815         todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2816            "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW),
2817            MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT));
2818         ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2819         ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret);
2820         todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2821            wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
2822     }
2823 }
2824 
2825 /* this requires collation table patch to make it MS compatible */
2826 static const char * const strings_sorted[] =
2827 {
2828 "'",
2829 "-",
2830 "!",
2831 "\"",
2832 ".",
2833 ":",
2834 "\\",
2835 "_",
2836 "`",
2837 "{",
2838 "}",
2839 "+",
2840 "0",
2841 "1",
2842 "2",
2843 "3",
2844 "4",
2845 "5",
2846 "6",
2847 "7",
2848 "8",
2849 "9",
2850 "a",
2851 "A",
2852 "b",
2853 "B",
2854 "c",
2855 "C"
2856 };
2857 
2858 static const char * const strings[] =
2859 {
2860 "C",
2861 "\"",
2862 "9",
2863 "'",
2864 "}",
2865 "-",
2866 "7",
2867 "+",
2868 "`",
2869 "1",
2870 "a",
2871 "5",
2872 "\\",
2873 "8",
2874 "B",
2875 "3",
2876 "_",
2877 "6",
2878 "{",
2879 "2",
2880 "c",
2881 "4",
2882 "!",
2883 "0",
2884 "A",
2885 ":",
2886 "b",
2887 "."
2888 };
2889 
2890 static int compare_string1(const void *e1, const void *e2)
2891 {
2892     const char *s1 = *(const char *const *)e1;
2893     const char *s2 = *(const char *const *)e2;
2894 
2895     return lstrcmpA(s1, s2);
2896 }
2897 
2898 static int compare_string2(const void *e1, const void *e2)
2899 {
2900     const char *s1 = *(const char *const *)e1;
2901     const char *s2 = *(const char *const *)e2;
2902 
2903     return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2904 }
2905 
2906 static int compare_string3(const void *e1, const void *e2)
2907 {
2908     const char *s1 = *(const char *const *)e1;
2909     const char *s2 = *(const char *const *)e2;
2910     char key1[256], key2[256];
2911 
2912     LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2913     LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2914     return strcmp(key1, key2);
2915 }
2916 
2917 static void test_sorting(void)
2918 {
2919     char buf[256];
2920     char **str_buf = (char **)buf;
2921     int i;
2922 
2923     assert(sizeof(buf) >= sizeof(strings));
2924 
2925     /* 1. sort using lstrcmpA */
2926     memcpy(buf, strings, sizeof(strings));
2927     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2928     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2929     {
2930         ok(!strcmp(strings_sorted[i], str_buf[i]),
2931            "qsort using lstrcmpA failed for element %d\n", i);
2932     }
2933     /* 2. sort using CompareStringA */
2934     memcpy(buf, strings, sizeof(strings));
2935     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2936     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2937     {
2938         ok(!strcmp(strings_sorted[i], str_buf[i]),
2939            "qsort using CompareStringA failed for element %d\n", i);
2940     }
2941     /* 3. sort using sort keys */
2942     memcpy(buf, strings, sizeof(strings));
2943     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2944     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2945     {
2946         ok(!strcmp(strings_sorted[i], str_buf[i]),
2947            "qsort using sort keys failed for element %d\n", i);
2948     }
2949 }
2950 
2951 static void test_FoldStringA(void)
2952 {
2953   int ret, i, j;
2954   BOOL is_special;
2955   char src[256], dst[256];
2956   static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0'  };
2957   static const char digits_dst[] = { '1','2','3','\0'  };
2958   static const char composite_src[] =
2959   {
2960     0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2961     0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2962     0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2963     0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2964     0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2965     0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2966     0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2967     0xfb,0xfc,0xfd,0xff,'\0'
2968   };
2969   static const char composite_dst[] =
2970   {
2971     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2972     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2973     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2974     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2975     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2976     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2977     0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2978     0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2979     0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2980     0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2981     0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2982     0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2983     0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2984     0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2985     0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2986   };
2987   static const char composite_dst_alt[] =
2988   {
2989     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2990     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2991     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2992     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2993     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2994     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2995     0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2996     0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2997     0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2998     0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2999     0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
3000     0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
3001     0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
3002     0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3003     0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3004   };
3005   static const char ligatures_src[] =
3006   {
3007     0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3008   };
3009   static const char ligatures_dst[] =
3010   {
3011     'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3012   };
3013   static const struct special
3014   {
3015     char src;
3016     char dst[4];
3017   }  foldczone_special[] =
3018   {
3019     /* src   dst                   */
3020     { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3021     { 0x98, { 0x20, 0x7e, 0x00 } },
3022     { 0x99, { 0x54, 0x4d, 0x00 } },
3023     { 0xa0, { 0x20, 0x00 } },
3024     { 0xa8, { 0x20, 0xa8, 0x00 } },
3025     { 0xaa, { 0x61, 0x00 } },
3026     { 0xaf, { 0x20, 0xaf, 0x00 } },
3027     { 0xb2, { 0x32, 0x00 } },
3028     { 0xb3, { 0x33, 0x00 } },
3029     { 0xb4, { 0x20, 0xb4, 0x00 } },
3030     { 0xb8, { 0x20, 0xb8, 0x00 } },
3031     { 0xb9, { 0x31, 0x00 } },
3032     { 0xba, { 0x6f, 0x00 } },
3033     { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3034     { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
3035     { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
3036     { 0x00 }
3037   };
3038 
3039   if (!pFoldStringA)
3040     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3041 
3042   /* these tests are locale specific */
3043   if (GetACP() != 1252)
3044   {
3045       trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
3046       return;
3047   }
3048 
3049   /* MAP_FOLDDIGITS */
3050   SetLastError(0);
3051   ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
3052   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3053   {
3054     win_skip("FoldStringA is not implemented\n");
3055     return;
3056   }
3057   ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
3058   ok(strcmp(dst, digits_dst) == 0,
3059      "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
3060   for (i = 1; i < 256; i++)
3061   {
3062     if (!strchr(digits_src, i))
3063     {
3064       src[0] = i;
3065       src[1] = '\0';
3066       SetLastError(0);
3067       ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
3068       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3069       ok(dst[0] == src[0],
3070          "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3071     }
3072   }
3073 
3074   /* MAP_EXPAND_LIGATURES */
3075   SetLastError(0);
3076   ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3077   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3078   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3079     ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3080     ok(strcmp(dst, ligatures_dst) == 0,
3081        "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3082     for (i = 1; i < 256; i++)
3083     {
3084       if (!strchr(ligatures_src, i))
3085       {
3086         src[0] = i;
3087         src[1] = '\0';
3088         SetLastError(0);
3089         ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3090         if (ret == 3)
3091         {
3092           /* Vista */
3093           ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3094              (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3095              "Got %s for %d\n", dst, i);
3096         }
3097         else
3098         {
3099           ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3100           ok(dst[0] == src[0],
3101              "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3102         }
3103       }
3104     }
3105   }
3106 
3107   /* MAP_COMPOSITE */
3108   SetLastError(0);
3109   ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3110   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3111   ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3112   ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3113      "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3114 
3115   for (i = 1; i < 256; i++)
3116   {
3117     if (!strchr(composite_src, i))
3118     {
3119       src[0] = i;
3120       src[1] = '\0';
3121       SetLastError(0);
3122       ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3123       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3124       ok(dst[0] == src[0],
3125          "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3126          (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3127     }
3128   }
3129 
3130   /* MAP_FOLDCZONE */
3131   for (i = 1; i < 256; i++)
3132   {
3133     src[0] = i;
3134     src[1] = '\0';
3135     SetLastError(0);
3136     ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3137     is_special = FALSE;
3138     for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3139     {
3140       if (foldczone_special[j].src == src[0])
3141       {
3142         ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3143            "Expected ret == 2 or %d, got %d, error %d\n",
3144            lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3145         ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3146            "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3147            (unsigned char)src[0]);
3148         is_special = TRUE;
3149       }
3150     }
3151     if (! is_special)
3152     {
3153       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3154       ok(src[0] == dst[0],
3155          "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3156          (unsigned char)src[0], (unsigned char)dst[0]);
3157     }
3158   }
3159 
3160   /* MAP_PRECOMPOSED */
3161   for (i = 1; i < 256; i++)
3162   {
3163     src[0] = i;
3164     src[1] = '\0';
3165     SetLastError(0);
3166     ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3167     ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3168     ok(src[0] == dst[0],
3169        "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3170        (unsigned char)src[0], (unsigned char)dst[0]);
3171   }
3172 }
3173 
3174 static void test_FoldStringW(void)
3175 {
3176   int ret;
3177   unsigned int i, j;
3178   WCHAR src[256], dst[256], ch, prev_ch = 1;
3179   static const DWORD badFlags[] =
3180   {
3181     0,
3182     MAP_PRECOMPOSED|MAP_COMPOSITE,
3183     MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3184     MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3185   };
3186   /* Ranges of digits 0-9 : Must be sorted! */
3187   static const WCHAR digitRanges[] =
3188   {
3189     0x0030, /* '0'-'9' */
3190     0x0660, /* Eastern Arabic */
3191     0x06F0, /* Arabic - Hindu */
3192     0x07C0, /* Nko */
3193     0x0966, /* Devengari */
3194     0x09E6, /* Bengalii */
3195     0x0A66, /* Gurmukhi */
3196     0x0AE6, /* Gujarati */
3197     0x0B66, /* Oriya */
3198     0x0BE6, /* Tamil - No 0 */
3199     0x0C66, /* Telugu */
3200     0x0CE6, /* Kannada */
3201     0x0D66, /* Maylayalam */
3202     0x0DE6, /* Sinhala Lith */
3203     0x0E50, /* Thai */
3204     0x0ED0, /* Laos */
3205     0x0F20, /* Tibet */
3206     0x0F29, /* Tibet half - 0 is out of sequence */
3207     0x1040, /* Myanmar */
3208     0x1090, /* Myanmar Shan */
3209     0x1368, /* Ethiopic - no 0 */
3210     0x17E0, /* Khmer */
3211     0x1810, /* Mongolian */
3212     0x1946, /* Limbu */
3213     0x19D0, /* New Tai Lue */
3214     0x1A80, /* Tai Tham Hora */
3215     0x1A90, /* Tai Tham Tham */
3216     0x1B50, /* Balinese */
3217     0x1BB0, /* Sundanese */
3218     0x1C40, /* Lepcha */
3219     0x1C50, /* Ol Chiki */
3220     0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3221     0x2080, /* Subscript */
3222     0x245F, /* Circled - 0 is out of sequence */
3223     0x2473, /* Bracketed */
3224     0x2487, /* Full stop */
3225     0x24F4, /* Double Circled */
3226     0x2775, /* Inverted circled - No 0 */
3227     0x277F, /* Patterned circled - No 0 */
3228     0x2789, /* Inverted Patterned circled - No 0 */
3229     0x3020, /* Hangzhou */
3230     0xA620, /* Vai */
3231     0xA8D0, /* Saurashtra */
3232     0xA900, /* Kayah Li */
3233     0xA9D0, /* Javanese */
3234     0xA9F0, /* Myanmar Tai Laing */
3235     0xAA50, /* Cham */
3236     0xABF0, /* Meetei Mayek */
3237     0xff10, /* Pliene chasse (?) */
3238     0xffff  /* Terminator */
3239   };
3240   /* Digits which are represented, but out of sequence */
3241   static const WCHAR outOfSequenceDigits[] =
3242   {
3243       0xB9,   /* Superscript 1 */
3244       0xB2,   /* Superscript 2 */
3245       0xB3,   /* Superscript 3 */
3246       0x0C78, /* Telugu Fraction 0 */
3247       0x0C79, /* Telugu Fraction 1 */
3248       0x0C7A, /* Telugu Fraction 2 */
3249       0x0C7B, /* Telugu Fraction 3 */
3250       0x0C7C, /* Telugu Fraction 1 */
3251       0x0C7D, /* Telugu Fraction 2 */
3252       0x0C7E, /* Telugu Fraction 3 */
3253       0x0F33, /* Tibetan half zero */
3254       0x19DA, /* New Tai Lue Tham 1 */
3255       0x24EA, /* Circled 0 */
3256       0x24FF, /* Negative Circled 0 */
3257       0x3007, /* Ideographic number zero */
3258       '\0'    /* Terminator */
3259   };
3260   /* Digits in digitRanges for which no representation is available */
3261   static const WCHAR noDigitAvailable[] =
3262   {
3263       0x0BE6, /* No Tamil 0 */
3264       0x0F29, /* No Tibetan half zero (out of sequence) */
3265       0x1368, /* No Ethiopic 0 */
3266       0x2473, /* No Bracketed 0 */
3267       0x2487, /* No 0 Full stop */
3268       0x24F4, /* No double circled 0 */
3269       0x2775, /* No inverted circled 0 */
3270       0x277F, /* No patterned circled */
3271       0x2789, /* No inverted Patterned circled */
3272       0x3020, /* No Hangzhou 0 */
3273       '\0'    /* Terminator */
3274   };
3275   static const WCHAR foldczone_src[] =
3276   {
3277     'W',    'i',    'n',    'e',    0x0348, 0x0551, 0x1323, 0x280d,
3278     0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3279   };
3280   static const WCHAR foldczone_dst[] =
3281   {
3282     'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3283   };
3284   static const WCHAR foldczone_todo_src[] =
3285   {
3286       0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3287   };
3288   static const WCHAR foldczone_todo_dst[] =
3289   {
3290       0x3cb,0x1f0,' ','a',0
3291   };
3292   static const WCHAR foldczone_todo_broken_dst[] =
3293   {
3294       0x3cb,0x1f0,0xa0,0xaa,0
3295   };
3296   static const WCHAR ligatures_src[] =
3297   {
3298     'W',    'i',    'n',    'e',    0x03a6, 0x03b9, 0x03bd, 0x03b5,
3299     0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3300     0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3301     0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3302     0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3303     0xfb04, 0xfb05, 0xfb06, '\0'
3304   };
3305   static const WCHAR ligatures_dst[] =
3306   {
3307     'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3308     'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3309     'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3310     'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3311     0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3312     'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3313   };
3314 
3315   if (!pFoldStringW)
3316   {
3317     win_skip("FoldStringW is not available\n");
3318     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3319   }
3320 
3321   /* Invalid flag combinations */
3322   for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3323   {
3324     src[0] = dst[0] = '\0';
3325     SetLastError(0);
3326     ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3327     if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3328     {
3329       win_skip("FoldStringW is not implemented\n");
3330       return;
3331     }
3332     ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3333        "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3334   }
3335 
3336   /* src & dst cannot be the same */
3337   SetLastError(0);
3338   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3339   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3340       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3341 
3342   /* src can't be NULL */
3343   SetLastError(0);
3344   ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3345   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3346       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3347 
3348   /* srclen can't be 0 */
3349   SetLastError(0);
3350   ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3351   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3352       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3353 
3354   /* dstlen can't be < 0 */
3355   SetLastError(0);
3356   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3357   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3358       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3359 
3360   /* Ret includes terminating NUL which is appended if srclen = -1 */
3361   SetLastError(0);
3362   src[0] = 'A';
3363   src[1] = '\0';
3364   dst[0] = '\0';
3365   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3366   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3367   ok(dst[0] == 'A' && dst[1] == '\0',
3368      "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3369      'A', '\0', ret, dst[0], dst[1], GetLastError());
3370 
3371   /* If size is given, result is not NUL terminated */
3372   SetLastError(0);
3373   src[0] = 'A';
3374   src[1] = 'A';
3375   dst[0] = 'X';
3376   dst[1] = 'X';
3377   ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3378   ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3379   ok(dst[0] == 'A' && dst[1] == 'X',
3380      "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3381      'A','X', ret, dst[0], dst[1], GetLastError());
3382 
3383   /* MAP_FOLDDIGITS */
3384   for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3385   {
3386     /* Check everything before this range */
3387     for (ch = prev_ch; ch < digitRanges[j]; ch++)
3388     {
3389       SetLastError(0);
3390       src[0] = ch;
3391       src[1] = dst[0] = '\0';
3392       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3393       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3394 
3395       ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3396          (ch >= 0xa8e0 && ch <= 0xa8e9),  /* combining Devanagari on Win8 */
3397          "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3398       ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3399          broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3400          "char %04x should not be a digit\n", ch );
3401     }
3402 
3403     if (digitRanges[j] == 0xffff)
3404       break; /* Finished the whole code point space */
3405 
3406     for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3407     {
3408       WCHAR c;
3409 
3410       /* Map out of sequence characters */
3411       if      (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3412       else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3413       else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3414       else if (ch == 0x245F) c = 0x24EA; /* Circled 0     */
3415       else                   c = ch;
3416       SetLastError(0);
3417       src[0] = c;
3418       src[1] = dst[0] = '\0';
3419       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3420       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3421 
3422       ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3423          broken( dst[0] == ch ) ||  /* old Windows versions don't have all mappings */
3424          (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3425          (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3426          strchrW(noDigitAvailable, c),
3427          "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3428          ch, '0' + digitRanges[j] - ch, dst[0]);
3429     }
3430     prev_ch = ch;
3431   }
3432 
3433   /* MAP_FOLDCZONE */
3434   SetLastError(0);
3435   ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3436   ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3437      "Got %d, error %d\n", ret, GetLastError());
3438   ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3439      "MAP_FOLDCZONE: Expanded incorrectly\n");
3440 
3441   ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3442   todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3443           "Got %d, error %d\n", ret, GetLastError());
3444   todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3445           || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3446           "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3447 
3448   /* MAP_EXPAND_LIGATURES */
3449   SetLastError(0);
3450   ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3451   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3452   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3453     ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3454        "Got %d, error %d\n", ret, GetLastError());
3455     ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3456        "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3457   }
3458 
3459   /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3460 }
3461 
3462 
3463 
3464 #define LCID_OK(l) \
3465   ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3466 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3467 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3468 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3469 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3470 
3471 static void test_ConvertDefaultLocale(void)
3472 {
3473   LCID lcid;
3474 
3475   /* Doesn't change lcid, even if non default sublang/sort used */
3476   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_US, SORT_DEFAULT);
3477   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3478   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_DEFAULT);
3479   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_JAPANESE_UNICODE);
3480 
3481   /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3482   LCID_RES(MKLCID(LANG_ENGLISH,  SUBLANG_NEUTRAL, SORT_DEFAULT),
3483            MKLCID(LANG_ENGLISH,  SUBLANG_DEFAULT, SORT_DEFAULT));
3484   LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3485            MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3486 
3487   /* Invariant language is not treated specially */
3488   TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3489 
3490   /* User/system default languages alone are not mapped */
3491   TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3492   TEST_LCIDLANG(LANG_USER_DEFAULT,   SORT_JAPANESE_UNICODE);
3493 
3494   /* Default lcids */
3495   LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3496   LCID_RES(LOCALE_USER_DEFAULT,   GetUserDefaultLCID());
3497   LCID_RES(LOCALE_NEUTRAL,        GetUserDefaultLCID());
3498   lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3499   ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3500      "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3501 }
3502 
3503 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3504                                     DWORD dwFlags, LONG_PTR lParam)
3505 {
3506   if (winetest_debug > 1)
3507     trace("%08x, %s, %s, %08x, %08lx\n",
3508           lgrpid, lpszNum, lpszName, dwFlags, lParam);
3509 
3510   ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3511      "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3512 
3513   /* If lParam is one, we are calling with flags defaulted from 0 */
3514   ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3515          "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3516 
3517   return TRUE;
3518 }
3519 
3520 static void test_EnumSystemLanguageGroupsA(void)
3521 {
3522   BOOL ret;
3523 
3524   if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3525   {
3526     win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3527     return;
3528   }
3529 
3530   /* No enumeration proc */
3531   SetLastError(0);
3532   ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3533   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3534   {
3535     win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3536     return;
3537   }
3538   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3539       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3540 
3541   /* Invalid flags */
3542   SetLastError(0);
3543   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3544   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3545 
3546   /* No flags - defaults to LGRPID_INSTALLED */
3547   SetLastError(0xdeadbeef);
3548   pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3549   ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3550 
3551   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3552   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3553 }
3554 
3555 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3556 {
3557     if (winetest_debug > 1)
3558         trace( "%s %x\n", wine_dbgstr_w(name), flags );
3559     return TRUE;
3560 }
3561 
3562 static void test_EnumSystemLocalesEx(void)
3563 {
3564     BOOL ret;
3565 
3566     if (!pEnumSystemLocalesEx)
3567     {
3568         win_skip( "EnumSystemLocalesEx not available\n" );
3569         return;
3570     }
3571     SetLastError( 0xdeadbeef );
3572     ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3573     ok( !ret, "should have failed\n" );
3574     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3575     SetLastError( 0xdeadbeef );
3576     ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3577     ok( ret, "failed err %u\n", GetLastError() );
3578 }
3579 
3580 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3581                                       LONG_PTR lParam)
3582 {
3583   if (winetest_debug > 1)
3584     trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3585 
3586   /* invalid locale enumerated on some platforms */
3587   if (lcid == 0)
3588       return TRUE;
3589 
3590   ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3591      "Enumerated grp %d not valid\n", lgrpid);
3592   ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3593      "Enumerated grp locale %04x not valid\n", lcid);
3594   return TRUE;
3595 }
3596 
3597 static void test_EnumLanguageGroupLocalesA(void)
3598 {
3599   BOOL ret;
3600 
3601   if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3602   {
3603     win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3604     return;
3605   }
3606 
3607   /* No enumeration proc */
3608   SetLastError(0);
3609   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3610   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3611   {
3612     win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3613     return;
3614   }
3615   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3616       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3617 
3618   /* lgrpid too small */
3619   SetLastError(0);
3620   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3621   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3622       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3623 
3624   /* lgrpid too big */
3625   SetLastError(0);
3626   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3627   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3628       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3629 
3630   /* dwFlags is reserved */
3631   SetLastError(0);
3632   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3633   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3634       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3635 
3636   pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3637 }
3638 
3639 static void test_SetLocaleInfoA(void)
3640 {
3641   BOOL bRet;
3642   LCID lcid = GetUserDefaultLCID();
3643 
3644   /* Null data */
3645   SetLastError(0);
3646   bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3647   ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3648       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3649 
3650   /* IDATE */
3651   SetLastError(0);
3652   bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3653   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3654      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3655 
3656   /* ILDATE */
3657   SetLastError(0);
3658   bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3659   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3660      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3661 }
3662 
3663 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3664 {
3665   if (winetest_debug > 1)
3666     trace("%s %08lx\n", value, lParam);
3667   return(TRUE);
3668 }
3669 
3670 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3671 {
3672   ok(!enumCount, "callback called again unexpected\n");
3673   enumCount++;
3674   return(FALSE);
3675 }
3676 
3677 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3678 {
3679   ok(0,"callback called unexpected\n");
3680   return(FALSE);
3681 }
3682 
3683 static void test_EnumUILanguageA(void)
3684 {
3685   BOOL ret;
3686   if (!pEnumUILanguagesA) {
3687     win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3688     return;
3689   }
3690 
3691   SetLastError(ERROR_SUCCESS);
3692   ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3693   if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3694   {
3695     win_skip("EnumUILanguagesA is not implemented\n");
3696     return;
3697   }
3698   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3699 
3700   enumCount = 0;
3701   SetLastError(ERROR_SUCCESS);
3702   ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3703   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3704 
3705   SetLastError(ERROR_SUCCESS);
3706   ret = pEnumUILanguagesA(NULL, 0, 0);
3707   ok(!ret, "Expected return value FALSE, got %u\n", ret);
3708   ok(GetLastError() == ERROR_INVALID_PARAMETER,
3709       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3710 
3711   SetLastError(ERROR_SUCCESS);
3712   ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3713   ok(!ret, "Expected return value FALSE, got %u\n", ret);
3714   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3715 
3716   SetLastError(ERROR_SUCCESS);
3717   ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3718   ok(!ret, "Expected return value FALSE, got %u\n", ret);
3719   ok(GetLastError() == ERROR_INVALID_PARAMETER,
3720       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3721 }
3722 
3723 static char date_fmt_buf[1024];
3724 static WCHAR date_fmt_bufW[1024];
3725 
3726 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3727 {
3728     lstrcatA(date_fmt_buf, fmt);
3729     lstrcatA(date_fmt_buf, "\n");
3730     return TRUE;
3731 }
3732 
3733 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3734 {
3735     lstrcatW(date_fmt_bufW, fmt);
3736     return FALSE;
3737 }
3738 
3739 static void test_EnumDateFormatsA(void)
3740 {
3741     char *p, buf[256];
3742     BOOL ret;
3743     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3744 
3745     date_fmt_buf[0] = 0;
3746     SetLastError(0xdeadbeef);
3747     ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3748     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3749     {
3750         win_skip("0 for dwFlags is not supported\n");
3751     }
3752     else
3753     {
3754         ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3755         trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3756         /* test the 1st enumerated format */
3757         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3758         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3759         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3760         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3761     }
3762 
3763     date_fmt_buf[0] = 0;
3764     SetLastError(0xdeadbeef);
3765     ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3766     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3767     {
3768         win_skip("LOCALE_USE_CP_ACP is not supported\n");
3769     }
3770     else
3771     {
3772         ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3773         trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3774         /* test the 1st enumerated format */
3775         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3776         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3777         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3778         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3779     }
3780 
3781     date_fmt_buf[0] = 0;
3782     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3783     ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3784     trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3785     /* test the 1st enumerated format */
3786     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3787     ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3788     ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3789     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3790 
3791     date_fmt_buf[0] = 0;
3792     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3793     ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3794     trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3795     /* test the 1st enumerated format */
3796     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3797     ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3798     ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3799     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3800 
3801     date_fmt_buf[0] = 0;
3802     SetLastError(0xdeadbeef);
3803     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3804     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3805     {
3806         win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3807         return;
3808     }
3809     ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3810     trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3811     /* test the 1st enumerated format */
3812     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3813     ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3814     ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3815     ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3816        "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3817 }
3818 
3819 static void test_EnumTimeFormatsA(void)
3820 {
3821     char *p, buf[256];
3822     BOOL ret;
3823     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3824 
3825     date_fmt_buf[0] = 0;
3826     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3827     ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3828     trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3829     /* test the 1st enumerated format */
3830     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3831     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3832     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3833     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3834 
3835     date_fmt_buf[0] = 0;
3836     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3837     ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3838     trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3839     /* test the 1st enumerated format */
3840     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3841     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3842     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3843     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3844 }
3845 
3846 static void test_EnumTimeFormatsW(void)
3847 {
3848     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3849     WCHAR bufW[256];
3850     BOOL ret;
3851 
3852     date_fmt_bufW[0] = 0;
3853     ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3854     ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3855     ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3856     ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3857     ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3858         wine_dbgstr_w(bufW));
3859 
3860     date_fmt_bufW[0] = 0;
3861     ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3862     ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3863     ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3864     ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3865     ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3866         wine_dbgstr_w(bufW));
3867 
3868     /* TIME_NOSECONDS is Win7+ feature */
3869     date_fmt_bufW[0] = 0;
3870     ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3871     if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3872         win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3873     else {
3874         char buf[256];
3875 
3876         ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3877         ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3878         ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3879         ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3880             wine_dbgstr_w(bufW));
3881 
3882         /* EnumTimeFormatsA doesn't support this flag */
3883         ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3884         ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3885             GetLastError());
3886 
3887         ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3888         ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3889             GetLastError());
3890 
3891         /* And it's not supported by GetLocaleInfoA either */
3892         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3893         ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3894             GetLastError());
3895     }
3896 }
3897 static void test_GetCPInfo(void)
3898 {
3899     BOOL ret;
3900     CPINFO cpinfo;
3901 
3902     SetLastError(0xdeadbeef);
3903     ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3904     ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3905     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3906        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3907 
3908     SetLastError(0xdeadbeef);
3909     ret = GetCPInfo(CP_UTF7, &cpinfo);
3910     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3911     {
3912         win_skip("Codepage CP_UTF7 is not installed/available\n");
3913     }
3914     else
3915     {
3916         ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3917         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3918         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3919         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3920         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3921         ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3922     }
3923 
3924     SetLastError(0xdeadbeef);
3925     ret = GetCPInfo(CP_UTF8, &cpinfo);
3926     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3927     {
3928         win_skip("Codepage CP_UTF8 is not installed/available\n");
3929     }
3930     else
3931     {
3932         ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3933         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3934         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3935         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3936         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3937         ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3938            "expected 4, got %u\n", cpinfo.MaxCharSize);
3939     }
3940 }
3941 
3942 /*
3943  * The CT_TYPE1 has varied over windows version.
3944  * The current target for correct behavior is windows 7.
3945  * There was a big shift between windows 2000 (first introduced) and windows Xp
3946  * Most of the old values below are from windows 2000.
3947  * A smaller subset of changes happened between windows Xp and Window vista/7
3948  */
3949 static void test_GetStringTypeW(void)
3950 {
3951     static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3952     static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3953                                  C1_SPACE | C1_BLANK | C1_DEFINED,
3954                                  C1_SPACE | C1_BLANK | C1_DEFINED,
3955                                  C1_SPACE | C1_BLANK | C1_DEFINED,
3956                                  C1_CNTRL | C1_BLANK | C1_DEFINED};
3957     static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3958                                     C1_SPACE | C1_BLANK,
3959                                     C1_SPACE | C1_BLANK,
3960                                     C1_SPACE | C1_BLANK,
3961                                     C1_SPACE | C1_BLANK};
3962 
3963     static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3964 
3965                                   /* Lu, Ll, Lt */
3966     static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3967     static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3968                                      C1_LOWER | C1_ALPHA,
3969                                      C1_UPPER | C1_LOWER | C1_ALPHA,
3970                                      C1_ALPHA};
3971 
3972                                   /* Sk, Sk, Mn, So, Me */
3973     static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3974                                  /* Sc, Sm, No,*/
3975                                      0xffe0, 0xffe9, 0x2153};
3976 
3977                                 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3978     static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3979     static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3980     static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3981                                       C1_ALPHA | C1_DEFINED,
3982                                       C1_CNTRL | C1_DEFINED,
3983                                       C1_PUNCT | C1_DEFINED,
3984                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3985                                       C1_ALPHA | C1_LOWER | C1_DEFINED,
3986                                       C1_ALPHA | C1_DEFINED };
3987     static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3988                                       C1_ALPHA | C1_DEFINED,
3989                                       C1_CNTRL | C1_DEFINED,
3990                                       C1_PUNCT | C1_CNTRL | C1_DEFINED,
3991                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3992                                       C1_ALPHA | C1_DEFINED,
3993                                       C1_DEFINED
3994  };
3995                                 /* Pc,  Pd, Ps, Pe, Pi, Pf, Po*/
3996     static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3997 
3998     static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3999                                           0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
4000     static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
4001     static const WCHAR lower_special[] = {0x2071, 0x207f};
4002     static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
4003                   0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
4004                   0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
4005                   0xfff9, 0xfffa, 0xfffb};
4006     static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
4007 
4008     WORD types[20];
4009     WCHAR ch[2];
4010     BOOL ret;
4011     int i;
4012 
4013     /* NULL src */
4014     SetLastError(0xdeadbeef);
4015     ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
4016     ok(!ret, "got %d\n", ret);
4017     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4018 
4019     SetLastError(0xdeadbeef);
4020     ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
4021     ok(!ret, "got %d\n", ret);
4022     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4023 
4024     SetLastError(0xdeadbeef);
4025     ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
4026     ok(!ret, "got %d\n", ret);
4027     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4028 
4029     memset(types,0,sizeof(types));
4030     GetStringTypeW(CT_CTYPE1, blanks, 5, types);
4031     for (i = 0; i < 5; i++)
4032         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]);
4033 
4034     memset(types,0,sizeof(types));
4035     GetStringTypeW(CT_CTYPE1, alpha, 3, types);
4036     for (i = 0; i < 3; i++)
4037         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]));
4038     memset(types,0,sizeof(types));
4039     GetStringTypeW(CT_CTYPE1, undefined, 5, types);
4040     for (i = 0; i < 5; i++)
4041         ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
4042 
4043     memset(types,0,sizeof(types));
4044     GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
4045     for (i = 0; i < 8; i++)
4046         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);
4047 
4048     memset(types,0,sizeof(types));
4049     GetStringTypeW(CT_CTYPE1, changed, 7, types);
4050     for (i = 0; i < 7; i++)
4051         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]);
4052 
4053     memset(types,0,sizeof(types));
4054     GetStringTypeW(CT_CTYPE1, punct, 7, types);
4055     for (i = 0; i < 7; i++)
4056         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));
4057 
4058 
4059     memset(types,0,sizeof(types));
4060     GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
4061     for (i = 0; i < 12; i++)
4062         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);
4063 
4064     memset(types,0,sizeof(types));
4065     GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
4066     for (i = 0; i < 3; i++)
4067         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);
4068 
4069     memset(types,0,sizeof(types));
4070     GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
4071     for (i = 0; i < 2; i++)
4072         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);
4073 
4074     memset(types,0,sizeof(types));
4075     GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4076     for (i = 0; i < 20; i++)
4077         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);
4078 
4079     memset(types,0,sizeof(types));
4080     GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4081     for (i = 0; i < 3; i++)
4082         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 );
4083 
4084     /* surrogate pairs */
4085     ch[0] = 0xd800;
4086     memset(types, 0, sizeof(types));
4087     GetStringTypeW(CT_CTYPE3, ch, 1, types);
4088     if (types[0] == C3_NOTAPPLICABLE)
4089         win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4090     else {
4091         ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4092 
4093         ch[0] = 0xdc00;
4094         memset(types, 0, sizeof(types));
4095         GetStringTypeW(CT_CTYPE3, ch, 1, types);
4096         ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4097     }
4098 
4099     /* Zl, Zp categories */
4100     ch[0] = 0x2028;
4101     ch[1] = 0x2029;
4102     memset(types, 0, sizeof(types));
4103     GetStringTypeW(CT_CTYPE1, ch, 2, types);
4104     ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4105     ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4106 
4107     /* check Arabic range for kashida flag */
4108     for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4109     {
4110         types[0] = 0;
4111         ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4112         ok(ret, "%#x: failed %d\n", ch[0], ret);
4113         if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4114             ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4115         else
4116             ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4117     }
4118 }
4119 
4120 static void test_IdnToNameprepUnicode(void)
4121 {
4122     struct {
4123         DWORD in_len;
4124         const WCHAR in[64];
4125         DWORD ret;
4126         DWORD broken_ret;
4127         const WCHAR out[64];
4128         DWORD flags;
4129         DWORD err;
4130         DWORD todo;
4131     } test_data[] = {
4132         {
4133             5, {'t','e','s','t',0},
4134             5, 5, {'t','e','s','t',0},
4135             0, 0xdeadbeef
4136         },
4137         {
4138             3, {'a',0xe111,'b'},
4139             0, 0, {0},
4140             0, ERROR_INVALID_NAME
4141         },
4142         {
4143             4, {'t',0,'e',0},
4144             0, 0, {0},
4145             0, ERROR_INVALID_NAME
4146         },
4147         {
4148             1, {'T',0},
4149             1, 1, {'T',0},
4150             0, 0xdeadbeef
4151         },
4152         {
4153             1, {0},
4154             0, 0, {0},
4155             0, ERROR_INVALID_NAME
4156         },
4157         {
4158             6, {' ','-','/','[',']',0},
4159             6, 6, {' ','-','/','[',']',0},
4160             0, 0xdeadbeef
4161         },
4162         {
4163             3, {'a','-','a'},
4164             3, 3, {'a','-','a'},
4165             IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4166         },
4167         {
4168             3, {'a','a','-'},
4169             0, 0, {0},
4170             IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4171         },
4172         { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4173             10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4174             12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4175             0, 0xdeadbeef, TRUE
4176         },
4177         {
4178             11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4179             2, 0, {'t',0},
4180             0, 0xdeadbeef
4181         },
4182         { /* Another example of incorrectly working FoldString (composition) */
4183             2, {0x3b0, 0},
4184             2, 2, {0x3b0, 0},
4185             0, 0xdeadbeef, TRUE
4186         },
4187         {
4188             2, {0x221, 0},
4189             0, 2, {0},
4190             0, ERROR_NO_UNICODE_TRANSLATION
4191         },
4192         {
4193             2, {0x221, 0},
4194             2, 2, {0x221, 0},
4195             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4196         },
4197         {
4198             5, {'a','.','.','a',0},
4199             0, 0, {0},
4200             0, ERROR_INVALID_NAME
4201         },
4202         {
4203             3, {'a','.',0},
4204             3, 3, {'a','.',0},
4205             0, 0xdeadbeef
4206         },
4207     };
4208 
4209     WCHAR buf[1024];
4210     DWORD i, ret, err;
4211 
4212     if (!pIdnToNameprepUnicode)
4213     {
4214         win_skip("IdnToNameprepUnicode is not available\n");
4215         return;
4216     }
4217 
4218     ret = pIdnToNameprepUnicode(0, test_data[0].in,
4219             test_data[0].in_len, NULL, 0);
4220     ok(ret == test_data[0].ret, "ret = %d\n", ret);
4221 
4222     SetLastError(0xdeadbeef);
4223     ret = pIdnToNameprepUnicode(0, test_data[1].in,
4224             test_data[1].in_len, NULL, 0);
4225     err = GetLastError();
4226     ok(ret == test_data[1].ret, "ret = %d\n", ret);
4227     ok(err == test_data[1].err, "err = %d\n", err);
4228 
4229     SetLastError(0xdeadbeef);
4230     ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
4231             buf, sizeof(buf)/sizeof(WCHAR));
4232     err = GetLastError();
4233     ok(ret == test_data[0].ret, "ret = %d\n", ret);
4234     ok(err == 0xdeadbeef, "err = %d\n", err);
4235 
4236     SetLastError(0xdeadbeef);
4237     ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
4238             buf, sizeof(buf)/sizeof(WCHAR));
4239     err = GetLastError();
4240     ok(ret == 0, "ret = %d\n", ret);
4241     ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4242 
4243     SetLastError(0xdeadbeef);
4244     ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
4245             buf, sizeof(buf)/sizeof(WCHAR));
4246     err = GetLastError();
4247     ok(ret == 0, "ret = %d\n", ret);
4248     ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4249 
4250     ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4251             test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
4252     ok(ret == test_data[0].ret, "ret = %d\n", ret);
4253 
4254     SetLastError(0xdeadbeef);
4255     ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4256     err = GetLastError();
4257     ok(ret == 0, "ret = %d\n", ret);
4258     ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4259 
4260     SetLastError(0xdeadbeef);
4261     ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4262     err = GetLastError();
4263     ok(ret == 0, "ret = %d\n", ret);
4264     ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4265        "err = %d\n", err);
4266 
4267     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4268     {
4269         SetLastError(0xdeadbeef);
4270         ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
4271                 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
4272         err = GetLastError();
4273 
4274         todo_wine_if (test_data[i].todo)
4275             ok(ret == test_data[i].ret ||
4276                     broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4277 
4278         if(ret != test_data[i].ret)
4279             continue;
4280 
4281         ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4282         ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4283                 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4284     }
4285 }
4286 
4287 static void test_IdnToAscii(void)
4288 {
4289     struct {
4290         DWORD in_len;
4291         const WCHAR in[64];
4292         DWORD ret;
4293         const WCHAR out[64];
4294         DWORD flags;
4295         DWORD err;
4296     } test_data[] = {
4297         {
4298             5, {'T','e','s','t',0},
4299             5, {'T','e','s','t',0},
4300             0, 0xdeadbeef
4301         },
4302         {
4303             5, {'T','e',0x017c,'s','t',0},
4304             12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4305             0, 0xdeadbeef
4306         },
4307         {
4308             12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4309             26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4310             0, 0xdeadbeef
4311         },
4312         {
4313             3, {0x0105,'.',0},
4314             9, {'x','n','-','-','2','d','a','.',0},
4315             0, 0xdeadbeef
4316         },
4317         {
4318             10, {'h','t','t','p',':','/','/','t',0x0106,0},
4319             17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4320             0, 0xdeadbeef
4321         },
4322         {
4323             10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4324             35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4325                 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4326             0, 0xdeadbeef
4327         },
4328         {
4329             2, {0x221,0},
4330             8, {'x','n','-','-','6','l','a',0},
4331             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4332         },
4333     };
4334 
4335     WCHAR buf[1024];
4336     DWORD i, ret, err;
4337 
4338     if (!pIdnToAscii)
4339     {
4340         win_skip("IdnToAscii is not available\n");
4341         return;
4342     }
4343 
4344     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4345     {
4346         SetLastError(0xdeadbeef);
4347         ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4348                 test_data[i].in_len, buf, sizeof(buf));
4349         err = GetLastError();
4350         ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4351         ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4352         ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4353                 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4354     }
4355 }
4356 
4357 static void test_IdnToUnicode(void)
4358 {
4359     struct {
4360         DWORD in_len;
4361         const WCHAR in[64];
4362         DWORD ret;
4363         const WCHAR out[64];
4364         DWORD flags;
4365         DWORD err;
4366     } test_data[] = {
4367         {
4368             5, {'T','e','s','.',0},
4369             5, {'T','e','s','.',0},
4370             0, 0xdeadbeef
4371         },
4372         {
4373             2, {0x105,0},
4374             0, {0},
4375             0, ERROR_INVALID_NAME
4376         },
4377         {
4378             33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4379                 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4380             23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4381                 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4382                 0x05d1,0x05e8,0x05d9,0x05ea,0},
4383             0, 0xdeadbeef
4384         },
4385         {
4386             34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4387                 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4388             16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4389                 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4390             0, 0xdeadbeef
4391         },
4392         {
4393             64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4394                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4395                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4396                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4397             0, {0},
4398             0, ERROR_INVALID_NAME
4399         },
4400         {
4401             8, {'x','n','-','-','6','l','a',0},
4402             2, {0x221,0},
4403             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4404         },
4405     };
4406 
4407     WCHAR buf[1024];
4408     DWORD i, ret, err;
4409 
4410     if (!pIdnToUnicode)
4411     {
4412         win_skip("IdnToUnicode is not available\n");
4413         return;
4414     }
4415 
4416     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4417     {
4418         ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4419                 test_data[i].in_len, NULL, 0);
4420         ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4421 
4422         SetLastError(0xdeadbeef);
4423         ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4424                 test_data[i].in_len, buf, sizeof(buf));
4425         err = GetLastError();
4426         ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4427         ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4428         ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4429                 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4430     }
4431 }
4432 
4433 static void test_GetLocaleInfoEx(void)
4434 {
4435     static const WCHAR enW[] = {'e','n',0};
4436     WCHAR bufferW[80], buffer2[80];
4437     INT ret;
4438 
4439     if (!pGetLocaleInfoEx)
4440     {
4441         win_skip("GetLocaleInfoEx not supported\n");
4442         return;
4443     }
4444 
4445     ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4446     ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4447     if (ret)
4448     {
4449         static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4450         static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4451         static const WCHAR enusW[] = {'e','n','-','U','S',0};
4452         static const WCHAR usaW[] = {'U','S','A',0};
4453         static const WCHAR enuW[] = {'E','N','U',0};
4454         const struct neutralsublang_name_t *ptr = neutralsublang_names;
4455         DWORD val;
4456 
4457         ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4458         ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4459 
4460         SetLastError(0xdeadbeef);
4461         ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4462         ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4463 
4464         SetLastError(0xdeadbeef);
4465         ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4466         ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4467 
4468         ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4469         ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4470         ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4471 
4472         ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4473         ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4474         ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4475 
4476         ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4477         ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4478         ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4479 
4480         ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4481         ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4482         if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4483             (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4484         {
4485             skip("Non-English locale\n");
4486         }
4487         else
4488             ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4489 
4490         bufferW[0] = 0;
4491         SetLastError(0xdeadbeef);
4492         ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4493         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4494 
4495         while (*ptr->name)
4496         {
4497             val = 0;
4498             pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4499             todo_wine_if (ptr->todo)
4500                 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4501             bufferW[0] = 0;
4502             ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4503             ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4504             ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4505             ptr++;
4506         }
4507 
4508         ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4509         ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4510         ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR));
4511         ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4512         ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4513     }
4514 }
4515 
4516 static void test_IsValidLocaleName(void)
4517 {
4518     static const WCHAR enusW[] = {'e','n','-','U','S',0};
4519     static const WCHAR zzW[] = {'z','z',0};
4520     static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0};
4521     static const WCHAR zzzzW[] = {'z','z','z','z',0};
4522     BOOL ret;
4523 
4524     if (!pIsValidLocaleName)
4525     {
4526         win_skip("IsValidLocaleName not supported\n");
4527         return;
4528     }
4529 
4530     ret = pIsValidLocaleName(enusW);
4531     ok(ret, "IsValidLocaleName failed\n");
4532     ret = pIsValidLocaleName(zzW);
4533     ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4534     ret = pIsValidLocaleName(zz_zzW);
4535     ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4536     ret = pIsValidLocaleName(zzzzW);
4537     ok(!ret, "IsValidLocaleName should have failed\n");
4538     ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4539     ok(ret, "IsValidLocaleName failed\n");
4540     ret = pIsValidLocaleName(NULL);
4541     ok(!ret, "IsValidLocaleName should have failed\n");
4542 }
4543 
4544 static void test_CompareStringOrdinal(void)
4545 {
4546     INT ret;
4547     WCHAR test1[] = { 't','e','s','t',0 };
4548     WCHAR test2[] = { 'T','e','S','t',0 };
4549     WCHAR test3[] = { 't','e','s','t','3',0 };
4550     WCHAR null1[] = { 'a',0,'a',0 };
4551     WCHAR null2[] = { 'a',0,'b',0 };
4552     WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4553     WCHAR bills2[] = { 'b','i','l','l','s',0 };
4554     WCHAR coop1[] = { 'c','o','-','o','p',0 };
4555     WCHAR coop2[] = { 'c','o','o','p',0 };
4556     WCHAR nonascii1[] = { 0x0102,0 };
4557     WCHAR nonascii2[] = { 0x0201,0 };
4558     WCHAR ch1, ch2;
4559 
4560     if (!pCompareStringOrdinal)
4561     {
4562         win_skip("CompareStringOrdinal not supported\n");
4563         return;
4564     }
4565 
4566     /* Check errors */
4567     SetLastError(0xdeadbeef);
4568     ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4569     ok(!ret, "Got %u, expected 0\n", ret);
4570     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4571     SetLastError(0xdeadbeef);
4572     ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4573     ok(!ret, "Got %u, expected 0\n", ret);
4574     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4575     SetLastError(0xdeadbeef);
4576     ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4577     ok(!ret, "Got %u, expected 0\n", ret);
4578     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4579 
4580     /* Check case */
4581     ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4582     ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4583     ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4584     ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4585     ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4586     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4587     ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4588     ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4589 
4590     /* Check different sizes */
4591     ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4592     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4593     ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4594     ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4595 
4596     /* Check null character */
4597     ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4598     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4599     ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4600     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4601     ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4602     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4603     ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4604     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4605 
4606     /* Check ordinal behaviour */
4607     ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4608     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4609     ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4610     ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4611     ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4612     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4613     ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4614     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4615 
4616     for (ch1 = 0; ch1 < 512; ch1++)
4617     {
4618         for (ch2 = 0; ch2 < 1024; ch2++)
4619         {
4620             int diff = ch1 - ch2;
4621             ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4622             ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4623                         "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4624             diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4625             ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4626             ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4627                         "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4628         }
4629     }
4630 }
4631 
4632 static void test_GetGeoInfo(void)
4633 {
4634     char buffA[20];
4635     INT ret;
4636 
4637     if (!pGetGeoInfoA)
4638     {
4639         win_skip("GetGeoInfo is not available.\n");
4640         return;
4641     }
4642 
4643     /* unassigned id */
4644     SetLastError(0xdeadbeef);
4645     ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4646     ok(ret == 0, "got %d\n", ret);
4647     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4648 
4649     ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4650     ok(ret == 3, "got %d\n", ret);
4651 
4652     ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4653     ok(ret == 4, "got %d\n", ret);
4654 
4655     ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4656     ok(ret == 3, "got %d\n", ret);
4657     ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4658 
4659     /* buffer pointer not NULL, length is 0 - return required length */
4660     buffA[0] = 'a';
4661     SetLastError(0xdeadbeef);
4662     ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4663     ok(ret == 3, "got %d\n", ret);
4664     ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4665 
4666     ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4667     ok(ret == 4, "got %d\n", ret);
4668     ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4669 
4670     /* shorter buffer */
4671     SetLastError(0xdeadbeef);
4672     buffA[1] = buffA[2] = 0;
4673     ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4674     ok(ret == 0, "got %d\n", ret);
4675     ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4676     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4677 
4678     /* GEO_NATION returns GEOID in a string form */
4679     buffA[0] = 0;
4680     ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4681     ok(ret == 4, "got %d\n", ret);
4682     ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4683 
4684     /* GEO_PARENT */
4685     buffA[0] = 0;
4686     ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4687     if (ret == 0)
4688         win_skip("GEO_PARENT not supported.\n");
4689     else
4690     {
4691         ok(ret == 6, "got %d\n", ret);
4692         ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4693     }
4694 
4695     buffA[0] = 0;
4696     ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4697     if (ret == 0)
4698         win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4699     else
4700     {
4701         ok(ret == 4, "got %d\n", ret);
4702         ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4703     }
4704 
4705     /* try invalid type value */
4706     SetLastError(0xdeadbeef);
4707     ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4708     ok(ret == 0, "got %d\n", ret);
4709     ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4710 }
4711 
4712 static int geoidenum_count;
4713 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4714 {
4715     INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4716     ok(ret == 3, "got %d for %d\n", ret, geoid);
4717     /* valid geoid starts at 2 */
4718     ok(geoid >= 2, "got geoid %d\n", geoid);
4719 
4720     return geoidenum_count++ < 5;
4721 }
4722 
4723 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4724 {
4725     geoidenum_count++;
4726     return TRUE;
4727 }
4728 
4729 static void test_EnumSystemGeoID(void)
4730 {
4731     BOOL ret;
4732 
4733     if (!pEnumSystemGeoID)
4734     {
4735         win_skip("EnumSystemGeoID is not available.\n");
4736         return;
4737     }
4738 
4739     SetLastError(0xdeadbeef);
4740     ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4741     ok(!ret, "got %d\n", ret);
4742     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4743 
4744     SetLastError(0xdeadbeef);
4745     ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4746     ok(!ret, "got %d\n", ret);
4747     ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4748 
4749     SetLastError(0xdeadbeef);
4750     ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4751     ok(!ret, "got %d\n", ret);
4752     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4753 
4754     ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4755     ok(ret, "got %d\n", ret);
4756 
4757     /* only the first level is enumerated, not the whole hierarchy */
4758     geoidenum_count = 0;
4759     ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4760     if (ret == 0)
4761         win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4762     else
4763         ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4764 
4765     geoidenum_count = 0;
4766     ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4767     if (ret == 0)
4768         win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4769     else
4770     {
4771         ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4772 
4773         geoidenum_count = 0;
4774         ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4775         ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4776     }
4777 }
4778 
4779 struct invariant_entry {
4780   const char *name;
4781   int id;
4782   const char *expect, *expect2;
4783 };
4784 
4785 #define X(x)  #x, x
4786 static const struct invariant_entry invariant_list[] = {
4787     { X(LOCALE_ILANGUAGE),                "007f" },
4788     { X(LOCALE_SENGLANGUAGE),             "Invariant Language" },
4789     { X(LOCALE_SABBREVLANGNAME),          "IVL" },
4790     { X(LOCALE_SNATIVELANGNAME),          "Invariant Language" },
4791     { X(LOCALE_ICOUNTRY),                 "1" },
4792     { X(LOCALE_SENGCOUNTRY),              "Invariant Country" },
4793     { X(LOCALE_SABBREVCTRYNAME),          "IVC", "" },
4794     { X(LOCALE_SNATIVECTRYNAME),          "Invariant Country" },
4795     { X(LOCALE_IDEFAULTLANGUAGE),         "0409" },
4796     { X(LOCALE_IDEFAULTCOUNTRY),          "1" },
4797     { X(LOCALE_IDEFAULTCODEPAGE),         "437" },
4798     { X(LOCALE_IDEFAULTANSICODEPAGE),     "1252" },
4799     { X(LOCALE_IDEFAULTMACCODEPAGE),      "10000" },
4800     { X(LOCALE_SLIST),                    "," },
4801     { X(LOCALE_IMEASURE),                 "0" },
4802     { X(LOCALE_SDECIMAL),                 "." },
4803     { X(LOCALE_STHOUSAND),                "," },
4804     { X(LOCALE_SGROUPING),                "3;0" },
4805     { X(LOCALE_IDIGITS),                  "2" },
4806     { X(LOCALE_ILZERO),                   "1" },
4807     { X(LOCALE_INEGNUMBER),               "1" },
4808     { X(LOCALE_SNATIVEDIGITS),            "0123456789" },
4809     { X(LOCALE_SCURRENCY),                "\x00a4" },
4810     { X(LOCALE_SINTLSYMBOL),              "XDR" },
4811     { X(LOCALE_SMONDECIMALSEP),           "." },
4812     { X(LOCALE_SMONTHOUSANDSEP),          "," },
4813     { X(LOCALE_SMONGROUPING),             "3;0" },
4814     { X(LOCALE_ICURRDIGITS),              "2" },
4815     { X(LOCALE_IINTLCURRDIGITS),          "2" },
4816     { X(LOCALE_ICURRENCY),                "0" },
4817     { X(LOCALE_INEGCURR),                 "0" },
4818     { X(LOCALE_SDATE),                    "/" },
4819     { X(LOCALE_STIME),                    ":" },
4820     { X(LOCALE_SSHORTDATE),               "MM/dd/yyyy" },
4821     { X(LOCALE_SLONGDATE),                "dddd, dd MMMM yyyy" },
4822     { X(LOCALE_STIMEFORMAT),              "HH:mm:ss" },
4823     { X(LOCALE_IDATE),                    "0" },
4824     { X(LOCALE_ILDATE),                   "1" },
4825     { X(LOCALE_ITIME),                    "1" },
4826     { X(LOCALE_ITIMEMARKPOSN),            "0" },
4827     { X(LOCALE_ICENTURY),                 "1" },
4828     { X(LOCALE_ITLZERO),                  "1" },
4829     { X(LOCALE_IDAYLZERO),                "1" },
4830     { X(LOCALE_IMONLZERO),                "1" },
4831     { X(LOCALE_S1159),                    "AM" },
4832     { X(LOCALE_S2359),                    "PM" },
4833     { X(LOCALE_ICALENDARTYPE),            "1" },
4834     { X(LOCALE_IOPTIONALCALENDAR),        "0" },
4835     { X(LOCALE_IFIRSTDAYOFWEEK),          "6" },
4836     { X(LOCALE_IFIRSTWEEKOFYEAR),         "0" },
4837     { X(LOCALE_SDAYNAME1),                "Monday" },
4838     { X(LOCALE_SDAYNAME2),                "Tuesday" },
4839     { X(LOCALE_SDAYNAME3),                "Wednesday" },
4840     { X(LOCALE_SDAYNAME4),                "Thursday" },
4841     { X(LOCALE_SDAYNAME5),                "Friday" },
4842     { X(LOCALE_SDAYNAME6),                "Saturday" },
4843     { X(LOCALE_SDAYNAME7),                "Sunday" },
4844     { X(LOCALE_SABBREVDAYNAME1),          "Mon" },
4845     { X(LOCALE_SABBREVDAYNAME2),          "Tue" },
4846     { X(LOCALE_SABBREVDAYNAME3),          "Wed" },
4847     { X(LOCALE_SABBREVDAYNAME4),          "Thu" },
4848     { X(LOCALE_SABBREVDAYNAME5),          "Fri" },
4849     { X(LOCALE_SABBREVDAYNAME6),          "Sat" },
4850     { X(LOCALE_SABBREVDAYNAME7),          "Sun" },
4851     { X(LOCALE_SMONTHNAME1),              "January" },
4852     { X(LOCALE_SMONTHNAME2),              "February" },
4853     { X(LOCALE_SMONTHNAME3),              "March" },
4854     { X(LOCALE_SMONTHNAME4),              "April" },
4855     { X(LOCALE_SMONTHNAME5),              "May" },
4856     { X(LOCALE_SMONTHNAME6),              "June" },
4857     { X(LOCALE_SMONTHNAME7),              "July" },
4858     { X(LOCALE_SMONTHNAME8),              "August" },
4859     { X(LOCALE_SMONTHNAME9),              "September" },
4860     { X(LOCALE_SMONTHNAME10),             "October" },
4861     { X(LOCALE_SMONTHNAME11),             "November" },
4862     { X(LOCALE_SMONTHNAME12),             "December" },
4863     { X(LOCALE_SMONTHNAME13),             "" },
4864     { X(LOCALE_SABBREVMONTHNAME1),        "Jan" },
4865     { X(LOCALE_SABBREVMONTHNAME2),        "Feb" },
4866     { X(LOCALE_SABBREVMONTHNAME3),        "Mar" },
4867     { X(LOCALE_SABBREVMONTHNAME4),        "Apr" },
4868     { X(LOCALE_SABBREVMONTHNAME5),        "May" },
4869     { X(LOCALE_SABBREVMONTHNAME6),        "Jun" },
4870     { X(LOCALE_SABBREVMONTHNAME7),        "Jul" },
4871     { X(LOCALE_SABBREVMONTHNAME8),        "Aug" },
4872     { X(LOCALE_SABBREVMONTHNAME9),        "Sep" },
4873     { X(LOCALE_SABBREVMONTHNAME10),       "Oct" },
4874     { X(LOCALE_SABBREVMONTHNAME11),       "Nov" },
4875     { X(LOCALE_SABBREVMONTHNAME12),       "Dec" },
4876     { X(LOCALE_SABBREVMONTHNAME13),       "" },
4877     { X(LOCALE_SPOSITIVESIGN),            "+" },
4878     { X(LOCALE_SNEGATIVESIGN),            "-" },
4879     { X(LOCALE_IPOSSIGNPOSN),             "3" },
4880     { X(LOCALE_INEGSIGNPOSN),             "0" },
4881     { X(LOCALE_IPOSSYMPRECEDES),          "1" },
4882     { X(LOCALE_IPOSSEPBYSPACE),           "0" },
4883     { X(LOCALE_INEGSYMPRECEDES),          "1" },
4884     { X(LOCALE_INEGSEPBYSPACE),           "0" },
4885     { X(LOCALE_SISO639LANGNAME),          "iv" },
4886     { X(LOCALE_SISO3166CTRYNAME),         "IV" },
4887     { X(LOCALE_IDEFAULTEBCDICCODEPAGE),   "037" },
4888     { X(LOCALE_IPAPERSIZE),               "9" },
4889     { X(LOCALE_SENGCURRNAME),             "International Monetary Fund" },
4890     { X(LOCALE_SNATIVECURRNAME),          "International Monetary Fund" },
4891     { X(LOCALE_SYEARMONTH),               "yyyy MMMM" },
4892     { X(LOCALE_IDIGITSUBSTITUTION),       "1" },
4893     { X(LOCALE_SNAME),                    "" },
4894     { X(LOCALE_SSCRIPTS),                 "Latn;" },
4895     { 0 }
4896 };
4897 #undef X
4898 
4899 static void test_invariant(void)
4900 {
4901   int ret;
4902   int len;
4903   char buffer[BUFFER_SIZE];
4904   const struct invariant_entry *ptr = invariant_list;
4905 
4906   if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4907   {
4908       win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4909       return;
4910   }
4911 
4912   while (ptr->name)
4913   {
4914     ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4915     if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4916         win_skip("not supported\n"); /* winxp/win2k3 */
4917     else
4918     {
4919         len = strlen(ptr->expect)+1; /* include \0 */
4920         ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
4921            "For id %d, expected ret == %d, got %d, error %d\n",
4922             ptr->id, len, ret, GetLastError());
4923         ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
4924            "For id %d, Expected %s, got '%s'\n",
4925             ptr->id, ptr->expect, buffer);
4926     }
4927 
4928     ptr++;
4929   }
4930 
4931  if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) ||
4932      (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
4933   {
4934       skip("Non US-English locale\n");
4935   }
4936   else
4937   {
4938     /* some locales translate these */
4939     static const char lang[]  = "Invariant Language (Invariant Country)";
4940     static const char cntry[] = "Invariant Country";
4941     static const char sortm[] = "Math Alphanumerics";
4942     static const char sortd[] = "Default"; /* win2k3 */
4943 
4944     ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4945     len = lstrlenA(lang) + 1;
4946     ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4947     ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4948 
4949     ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4950     len = lstrlenA(cntry) + 1;
4951     ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4952     ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4953 
4954     ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4955     if (ret == lstrlenA(sortm)+1)
4956         ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4957     else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4958         ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4959     else
4960         ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4961             lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4962   }
4963 }
4964 
4965 static void test_GetSystemPreferredUILanguages(void)
4966 {
4967     BOOL ret;
4968     ULONG count, size, size_id, size_name, size_buffer;
4969     WCHAR *buffer;
4970 
4971 
4972     if (!pGetSystemPreferredUILanguages)
4973     {
4974         win_skip("GetSystemPreferredUILanguages is not available.\n");
4975         return;
4976     }
4977 
4978     /* (in)valid first parameter */
4979     count = 0xdeadbeef;
4980     size = 0;
4981     SetLastError(0xdeadbeef);
4982     ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4983     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4984     ok(count, "Expected count > 0\n");
4985     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4986 
4987     count = 0xdeadbeef;
4988     size = 0;
4989     SetLastError(0xdeadbeef);
4990     ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4991     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4992     ok(ERROR_INVALID_PARAMETER == GetLastError(),
4993        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4994 
4995     count = 0xdeadbeef;
4996     size = 0;
4997     SetLastError(0xdeadbeef);
4998     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4999     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5000     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5001        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5002 
5003     count = 0xdeadbeef;
5004     size = 0;
5005     SetLastError(0xdeadbeef);
5006     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
5007     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5008     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5009        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5010 
5011     count = 0xdeadbeef;
5012     size = 0;
5013     SetLastError(0xdeadbeef);
5014     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5015     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5016     ok(count, "Expected count > 0\n");
5017     ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5018 
5019     count = 0xdeadbeef;
5020     size = 0;
5021     SetLastError(0xdeadbeef);
5022     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5023     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5024     ok(count, "Expected count > 0\n");
5025     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5026 
5027     /* second parameter
5028      * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
5029      * -> unhandled exception c0000005
5030      */
5031 
5032     /* invalid third parameter */
5033     count = 0xdeadbeef;
5034     size = 1;
5035     SetLastError(0xdeadbeef);
5036     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5037     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5038     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5039        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5040 
5041     /* fourth parameter
5042      * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
5043      * -> unhandled exception c0000005
5044      */
5045 
5046     count = 0xdeadbeef;
5047     size_id = 0;
5048     SetLastError(0xdeadbeef);
5049     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5050     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5051     ok(count, "Expected count > 0\n");
5052     ok(size_id  % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5053 
5054     count = 0xdeadbeef;
5055     size_name = 0;
5056     SetLastError(0xdeadbeef);
5057     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5058     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5059     ok(count, "Expected count > 0\n");
5060     ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5061 
5062     size_buffer = max(size_id, size_name);
5063     if(!size_buffer)
5064     {
5065         skip("No valid buffer size\n");
5066         return;
5067     }
5068 
5069     buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5070     if (!buffer)
5071     {
5072         skip("Failed to allocate memory for %d chars\n", size_buffer);
5073         return;
5074     }
5075 
5076     count = 0xdeadbeef;
5077     size = size_buffer;
5078     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5079     SetLastError(0xdeadbeef);
5080     ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5081     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5082     ok(count, "Expected count > 0\n");
5083     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5084     if (ret && size % 6 == 1)
5085         ok(!buffer[size -2] && !buffer[size -1],
5086            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5087            buffer[size -2], buffer[size -1]);
5088 
5089     count = 0xdeadbeef;
5090     size = size_buffer;
5091     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5092     SetLastError(0xdeadbeef);
5093     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5094     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5095     ok(count, "Expected count > 0\n");
5096     ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5097     if (ret && size % 5 == 1)
5098         ok(!buffer[size -2] && !buffer[size -1],
5099            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5100            buffer[size -2], buffer[size -1]);
5101 
5102     count = 0xdeadbeef;
5103     size = size_buffer;
5104     SetLastError(0xdeadbeef);
5105     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5106     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5107     ok(count, "Expected count > 0\n");
5108     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5109     if (ret && size % 5 == 1)
5110         ok(!buffer[size -2] && !buffer[size -1],
5111            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5112            buffer[size -2], buffer[size -1]);
5113 
5114     count = 0xdeadbeef;
5115     size = 0;
5116     SetLastError(0xdeadbeef);
5117     ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5118     ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5119     ok(count, "Expected count > 0\n");
5120     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5121     if (ret && size % 6 == 1)
5122         ok(!buffer[size -2] && !buffer[size -1],
5123            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5124            buffer[size -2], buffer[size -1]);
5125 
5126     count = 0xdeadbeef;
5127     size = 1;
5128     SetLastError(0xdeadbeef);
5129     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5130     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5131     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5132        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5133 
5134     count = 0xdeadbeef;
5135     size = size_id -1;
5136     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5137     SetLastError(0xdeadbeef);
5138     ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5139     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5140     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5141        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5142 
5143     count = 0xdeadbeef;
5144     size = size_id -2;
5145     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5146     SetLastError(0xdeadbeef);
5147     ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5148     ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5149     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5150        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5151 
5152     HeapFree(GetProcessHeap(), 0, buffer);
5153 }
5154 
5155 static void test_GetThreadPreferredUILanguages(void)
5156 {
5157     BOOL ret;
5158     ULONG count, size;
5159     WCHAR *buf;
5160 
5161     if (!pGetThreadPreferredUILanguages)
5162     {
5163         win_skip("GetThreadPreferredUILanguages is not available.\n");
5164         return;
5165     }
5166 
5167     size = count = 0;
5168     ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5169     ok(ret, "got %u\n", GetLastError());
5170     ok(count, "expected count > 0\n");
5171     ok(size, "expected size > 0\n");
5172 
5173     count = 0;
5174     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5175     ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5176     ok(ret, "got %u\n", GetLastError());
5177     ok(count, "expected count > 0\n");
5178     HeapFree(GetProcessHeap(), 0, buf);
5179 }
5180 
5181 static void test_GetUserPreferredUILanguages(void)
5182 {
5183     BOOL ret;
5184     ULONG count, size, size_id, size_name, size_buffer;
5185     WCHAR *buffer;
5186 
5187 
5188     if (!pGetUserPreferredUILanguages)
5189     {
5190         win_skip("GetUserPreferredUILanguages is not available.\n");
5191         return;
5192     }
5193 
5194     count = 0xdeadbeef;
5195     size = 0;
5196     SetLastError(0xdeadbeef);
5197     ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5198     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5199     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5200        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5201 
5202     count = 0xdeadbeef;
5203     size = 0;
5204     SetLastError(0xdeadbeef);
5205     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5206     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5207     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5208        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5209 
5210     count = 0xdeadbeef;
5211     size = 0;
5212     SetLastError(0xdeadbeef);
5213     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5214     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5215     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5216        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5217 
5218     count = 0xdeadbeef;
5219     size = 1;
5220     SetLastError(0xdeadbeef);
5221     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5222     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5223     ok(ERROR_INVALID_PARAMETER == GetLastError(),
5224        "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5225 
5226     count = 0xdeadbeef;
5227     size_id = 0;
5228     SetLastError(0xdeadbeef);
5229     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5230     ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5231     ok(count, "Expected count > 0\n");
5232     ok(size_id  % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5233 
5234     count = 0xdeadbeef;
5235     size_name = 0;
5236     SetLastError(0xdeadbeef);
5237     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5238     ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5239     ok(count, "Expected count > 0\n");
5240     ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5241 
5242     size_buffer = max(size_id, size_name);
5243     if(!size_buffer)
5244     {
5245         skip("No valid buffer size\n");
5246         return;
5247     }
5248 
5249     buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5250 
5251     count = 0xdeadbeef;
5252     size = size_buffer;
5253     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5254     SetLastError(0xdeadbeef);
5255     ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5256     ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5257     ok(count, "Expected count > 0\n");
5258     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5259     if (ret && size % 6 == 1)
5260         ok(!buffer[size -2] && !buffer[size -1],
5261            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5262            buffer[size -2], buffer[size -1]);
5263 
5264     count = 0xdeadbeef;
5265     size = size_buffer;
5266     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5267     SetLastError(0xdeadbeef);
5268     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5269     ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5270     ok(count, "Expected count > 0\n");
5271     ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5272     if (ret && size % 5 == 1)
5273         ok(!buffer[size -2] && !buffer[size -1],
5274            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5275            buffer[size -2], buffer[size -1]);
5276 
5277     count = 0xdeadbeef;
5278     size = size_buffer;
5279     SetLastError(0xdeadbeef);
5280     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5281     ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5282     ok(count, "Expected count > 0\n");
5283     ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5284     if (ret && size % 5 == 1)
5285         ok(!buffer[size -2] && !buffer[size -1],
5286            "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5287            buffer[size -2], buffer[size -1]);
5288 
5289     count = 0xdeadbeef;
5290     size = 1;
5291     SetLastError(0xdeadbeef);
5292     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5293     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5294     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5295        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5296 
5297     count = 0xdeadbeef;
5298     size = size_id -1;
5299     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5300     SetLastError(0xdeadbeef);
5301     ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5302     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5303     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5304        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5305 
5306     count = 0xdeadbeef;
5307     size = size_id -2;
5308     memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5309     SetLastError(0xdeadbeef);
5310     ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5311     ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5312     ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5313        "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5314 
5315     HeapFree(GetProcessHeap(), 0, buffer);
5316 }
5317 
5318 START_TEST(locale)
5319 {
5320   InitFunctionPointers();
5321 
5322   test_EnumTimeFormatsA();
5323   test_EnumTimeFormatsW();
5324   test_EnumDateFormatsA();
5325   test_GetLocaleInfoA();
5326   test_GetLocaleInfoW();
5327   test_GetLocaleInfoEx();
5328   test_GetTimeFormatA();
5329   test_GetTimeFormatEx();
5330   test_GetDateFormatA();
5331   test_GetDateFormatEx();
5332   test_GetDateFormatW();
5333   test_GetCurrencyFormatA(); /* Also tests the W version */
5334   test_GetNumberFormatA();   /* Also tests the W version */
5335   test_GetNumberFormatEx();
5336   test_CompareStringA();
5337   test_CompareStringW();
5338   test_CompareStringEx();
5339   test_LCMapStringA();
5340   test_LCMapStringW();
5341   test_LCMapStringEx();
5342   test_LocaleNameToLCID();
5343   test_FoldStringA();
5344   test_FoldStringW();
5345   test_ConvertDefaultLocale();
5346   test_EnumSystemLanguageGroupsA();
5347   test_EnumSystemLocalesEx();
5348   test_EnumLanguageGroupLocalesA();
5349   test_SetLocaleInfoA();
5350   test_EnumUILanguageA();
5351   test_GetCPInfo();
5352   test_GetStringTypeW();
5353   test_IdnToNameprepUnicode();
5354   test_IdnToAscii();
5355   test_IdnToUnicode();
5356   test_IsValidLocaleName();
5357   test_CompareStringOrdinal();
5358   test_GetGeoInfo();
5359   test_EnumSystemGeoID();
5360   test_invariant();
5361   test_GetSystemPreferredUILanguages();
5362   test_GetThreadPreferredUILanguages();
5363   test_GetUserPreferredUILanguages();
5364   test_sorting();
5365 }
5366