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