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