mlang/tests: Accept the different translation in win8.
[wine/multimedia.git] / dlls / mlang / tests / mlang.c
blob0da31b51834268a52f4691e8ebba9744d2d79c52
1 /*
2 * Unit test suite for MLANG APIs.
4 * Copyright 2004 Dmitry Timoshkov
5 * Copyright 2009 Detlef Riekenberg
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "initguid.h"
31 #include "mlang.h"
33 #include "wine/test.h"
35 #ifndef CP_UNICODE
36 #define CP_UNICODE 1200
37 #endif
39 /* #define DUMP_CP_INFO */
40 /* #define DUMP_SCRIPT_INFO */
42 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
43 static HRESULT (WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD, DWORD, LPCSTR,
44 LPINT, LPWSTR, LPINT);
45 static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD, DWORD, LPCWSTR,
46 LPINT, LPSTR, LPINT);
47 static HRESULT (WINAPI *pRfc1766ToLcidA)(LCID *, LPCSTR);
48 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
50 typedef struct lcid_tag_table {
51 LPCSTR rfc1766;
52 LCID lcid;
53 HRESULT hr;
54 LCID broken_lcid;
55 LPCSTR broken_rfc;
56 } lcid_table_entry;
58 /* en, ar and zh use SUBLANG_NEUTRAL for the rfc1766 name without the country
59 all others suppress the country with SUBLANG_DEFAULT.
60 For 3 letter language codes, the rfc1766 is too small for the country */
62 static const lcid_table_entry lcid_table[] = {
63 {"e", -1, E_FAIL},
64 {"", -1, E_FAIL},
65 {"-", -1, E_FAIL},
66 {"e-", -1, E_FAIL},
68 {"ar", 1, S_OK},
69 {"zh", 4, S_OK},
71 {"de", 0x0407, S_OK},
72 {"de-ch", 0x0807, S_OK},
73 {"de-at", 0x0c07, S_OK},
74 {"de-lu", 0x1007, S_OK},
75 {"de-li", 0x1407, S_OK},
77 {"en", 9, S_OK},
78 {"en-gb", 0x809, S_OK},
79 {"en-GB", 0x809, S_OK},
80 {"EN-GB", 0x809, S_OK},
81 {"en-US", 0x409, S_OK},
82 {"en-us", 0x409, S_OK},
84 {"fr", 0x040c, S_OK},
85 {"fr-be", 0x080c, S_OK},
86 {"fr-ca", 0x0c0c, S_OK},
87 {"fr-ch", 0x100c, S_OK},
88 {"fr-lu", 0x140c, S_OK},
89 {"fr-mc", 0x180c, S_OK, 0x040c, "fr"},
91 {"it", 0x0410, S_OK},
92 {"it-ch", 0x0810, S_OK},
94 {"nl", 0x0413, S_OK},
95 {"nl-be", 0x0813, S_OK},
96 {"pl", 0x0415, S_OK},
97 {"ru", 0x0419, S_OK},
99 {"kok", 0x0457, S_OK, 0x0412, "x-kok"}
103 #define TODO_NAME 1
105 typedef struct info_table_tag {
106 LCID lcid;
107 LANGID lang;
108 DWORD todo;
109 LPCSTR rfc1766;
110 LPCWSTR localename;
111 LPCWSTR broken_name;
112 } info_table_entry;
114 static const WCHAR de_en[] = {'E','n','g','l','i','s','c','h',0};
115 static const WCHAR de_enca[] = {'E','n','g','l','i','s','c','h',' ',
116 '(','K','a','n','a','d','a',')',0};
117 static const WCHAR de_engb[] = {'E','n','g','l','i','s','c','h',' ',
118 '(','G','r','o',0xDF,'b','r','i','t','a','n','n','i','e','n',')',0};
119 static const WCHAR de_engb2[] ={'E','n','g','l','i','s','c','h',' ',
120 '(','V','e','r','e','i','n','i','g','t','e','s',' ',
121 'K',0xF6,'n','i','g','r','e','i','c',0};
122 static const WCHAR de_enus[] = {'E','n','g','l','i','s','c','h',' ',
123 '(','U','S','A',')',0};
124 static const WCHAR de_enus2[] ={'E','n','g','l','i','s','c','h',' ',
125 '(','V','e','r','e','i','n','i','g','t','e',' ',
126 'S','t','a','a','t','e','n',')',0};
127 static const WCHAR de_de[] = {'D','e','u','t','s','c','h',' ',
128 '(','D','e','u','t','s','c','h','l','a','n','d',')',0};
129 static const WCHAR de_deat[] = {'D','e','u','t','s','c','h',' ',
130 '(',0xD6,'s','t','e','r','r','e','i','c','h',')',0};
131 static const WCHAR de_dech[] = {'D','e','u','t','s','c','h',' ',
132 '(','S','c','h','w','e','i','z',')',0};
134 static const WCHAR en_en[] = {'E','n','g','l','i','s','h',0};
135 static const WCHAR en_enca[] = {'E','n','g','l','i','s','h',' ',
136 '(','C','a','n','a','d','a',')',0};
137 static const WCHAR en_engb[] = {'E','n','g','l','i','s','h',' ',
138 '(','U','n','i','t','e','d',' ','K','i','n','g','d','o','m',')',0};
139 static const WCHAR en_enus[] = {'E','n','g','l','i','s','h',' ',
140 '(','U','n','i','t','e','d',' ','S','t','a','t','e','s',')',0};
141 static const WCHAR en_de[] = {'G','e','r','m','a','n',' ',
142 '(','G','e','r','m','a','n','y',')',0};
143 static const WCHAR en_deat[] = {'G','e','r','m','a','n',' ',
144 '(','A','u','s','t','r','i','a',')',0};
145 static const WCHAR en_dech[] = {'G','e','r','m','a','n',' ',
146 '(','S','w','i','t','z','e','r','l','a','n','d',')',0};
148 static const WCHAR fr_en[] = {'A','n','g','l','a','i','s',0};
149 static const WCHAR fr_enca[] = {'A','n','g','l','a','i','s',' ',
150 '(','C','a','n','a','d','a',')',0};
151 static const WCHAR fr_engb[] = {'A','n','g','l','a','i','s',' ',
152 '(','R','o','y','a','u','m','e','-','U','n','i',')',0};
153 static const WCHAR fr_enus[] = {'A','n','g','l','a','i','s',' ',
154 '(',0xC9, 't','a','t','s','-','U','n','i','s',')',0};
155 static const WCHAR fr_enus2[] ={'A','n','g','l','a','i','s',' ',
156 '(','U','.','S','.',')',0};
157 static const WCHAR fr_de[] = {'A','l','l','e','m','a','n','d',' ',
158 '(','A','l','l','e','m','a','g','n','e',')',0};
159 static const WCHAR fr_de2[] = {'A','l','l','e','m','a','n','d',' ',
160 '(','S','t','a','n','d','a','r','d',')',0};
161 static const WCHAR fr_deat[] = {'A','l','l','e','m','a','n','d',' ',
162 '(','A','u','t','r','i','c','h','e',')',0};
163 static const WCHAR fr_dech[] = {'A','l','l','e','m','a','n','d',' ',
164 '(','S','u','i','s','s','e',')',0};
166 static const info_table_entry info_table[] = {
167 {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
168 0, "en", en_en},
169 {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
170 0, "en-us", en_enus},
171 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
172 0, "en-gb", en_engb},
173 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
174 0, "en-us", en_enus},
175 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
176 0, "en-ca", en_enca},
178 {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
179 0, "de", en_de},
180 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
181 0, "de", en_de},
182 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
183 0, "de-ch", en_dech},
184 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
185 0, "de-at", en_deat},
187 {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
188 TODO_NAME, "en", de_en},
189 {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
190 TODO_NAME, "en-us", de_enus, de_enus2},
191 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
192 TODO_NAME, "en-gb", de_engb, de_engb2},
193 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
194 TODO_NAME, "en-us", de_enus, de_enus2},
195 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
196 TODO_NAME, "en-ca", de_enca},
198 {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
199 TODO_NAME, "de", de_de},
200 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
201 TODO_NAME, "de",de_de},
202 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
203 TODO_NAME, "de-ch", de_dech},
204 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT),
205 TODO_NAME, "de-at", de_deat},
207 {MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
208 TODO_NAME, "en", fr_en},
209 {MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
210 TODO_NAME, "en-us", fr_enus, fr_enus2},
211 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
212 TODO_NAME, "en-gb", fr_engb},
213 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
214 TODO_NAME, "en-us", fr_enus, fr_enus2},
215 {MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
216 TODO_NAME, "en-ca", fr_enca},
218 {MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
219 TODO_NAME, "de", fr_de, fr_de2},
220 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
221 TODO_NAME, "de", fr_de, fr_de2},
222 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
223 TODO_NAME, "de-ch", fr_dech},
224 {MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT),
225 TODO_NAME, "de-at", fr_deat}
229 static BOOL init_function_ptrs(void)
231 HMODULE hMlang;
233 hMlang = LoadLibraryA("mlang.dll");
234 if (!hMlang)
236 skip("mlang not available\n");
237 return FALSE;
240 pConvertINetMultiByteToUnicode = (void *)GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode");
241 pConvertINetUnicodeToMultiByte = (void *)GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte");
242 pRfc1766ToLcidA = (void *)GetProcAddress(hMlang, "Rfc1766ToLcidA");
243 pLcidToRfc1766A = (void *)GetProcAddress(hMlang, "LcidToRfc1766A");
245 pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA");
247 return TRUE;
250 #define ok_w2(format, szString1, szString2) \
252 if (lstrcmpW((szString1), (szString2)) != 0) \
254 CHAR string1[256], string2[256]; \
255 WideCharToMultiByte(CP_ACP, 0, (szString1), -1, string1, 256, NULL, NULL); \
256 WideCharToMultiByte(CP_ACP, 0, (szString2), -1, string2, 256, NULL, NULL); \
257 ok(0, (format), string1, string2); \
260 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
262 /* these APIs are broken regarding constness of the input buffer */
263 char stringA[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
264 WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
265 char bufA[256];
266 WCHAR bufW[256];
267 UINT lenA, lenW, expected_len;
268 HRESULT ret;
270 /* IMultiLanguage2_ConvertStringToUnicode tests */
272 memset(bufW, 'x', sizeof(bufW));
273 lenA = 0;
274 lenW = sizeof(bufW)/sizeof(bufW[0]);
275 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
276 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
277 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
278 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
280 memset(bufW, 'x', sizeof(bufW));
281 lenA = -1;
282 lenW = sizeof(bufW)/sizeof(bufW[0]);
283 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
284 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
285 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
286 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
287 if (lenW < sizeof(bufW)/sizeof(bufW[0])) {
288 /* can only happen if the convert call fails */
289 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
290 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
292 ok(!lstrcmpW(bufW, stringW), "bufW/stringW mismatch\n");
294 memset(bufW, 'x', sizeof(bufW));
295 lenA = -1;
296 lenW = 5;
297 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
298 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret);
299 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
300 /* still has to do partial conversion */
301 ok(!memcmp(bufW, stringW, 5 * sizeof(WCHAR)), "bufW/stringW mismatch\n");
303 memset(bufW, 'x', sizeof(bufW));
304 lenA = -1;
305 lenW = sizeof(bufW)/sizeof(bufW[0]);
306 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW);
307 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
308 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
309 ok(lenW == lstrlenW(stringW)/(int)sizeof(WCHAR), "wrong lenW %u\n", lenW);
310 ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
311 bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
312 ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n");
314 memset(bufW, 'x', sizeof(bufW));
315 lenA = lstrlenA(stringA);
316 lenW = 0;
317 ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, NULL, &lenW);
318 ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
319 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
320 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
321 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
323 memset(bufW, 'x', sizeof(bufW));
324 lenA = lstrlenA(stringA);
325 lenW = sizeof(bufW)/sizeof(bufW[0]);
326 ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
327 ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
328 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
329 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
330 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
332 memset(bufW, 'x', sizeof(bufW));
333 lenA = lstrlenA(stringA);
334 lenW = 0;
335 ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
336 ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
337 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
338 expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
339 ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
341 /* IMultiLanguage2_ConvertStringFromUnicode tests */
343 memset(bufA, 'x', sizeof(bufA));
344 lenW = 0;
345 lenA = sizeof(bufA);
346 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
347 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
348 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
349 ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
351 memset(bufA, 'x', sizeof(bufA));
352 lenW = -1;
353 lenA = sizeof(bufA);
354 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
355 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
356 ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
357 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
358 ok(bufA[lenA] != 0, "buf should not be 0 terminated\n");
359 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
360 ok(!lstrcmpA(bufA, stringA), "bufA/stringA mismatch\n");
362 memset(bufA, 'x', sizeof(bufA));
363 lenW = -1;
364 lenA = 5;
365 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
366 ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret);
367 ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
368 /* still has to do partial conversion */
369 ok(!memcmp(bufA, stringA, 5), "bufW/stringW mismatch\n");
371 memset(bufA, 'x', sizeof(bufA));
372 lenW = -1;
373 lenA = sizeof(bufA);
374 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA);
375 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
376 ok(lenA == lstrlenA(stringA) * (int)sizeof(WCHAR), "wrong lenA %u\n", lenA);
377 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
378 ok(bufA[lenA] != 0 && bufA[lenA+1] != 0, "buf should not be 0 terminated\n");
379 bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
380 bufA[lenA+1] = 0; /* sizeof(WCHAR) */
381 ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n");
383 memset(bufA, 'x', sizeof(bufA));
384 lenW = lstrlenW(stringW);
385 lenA = 0;
386 ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, NULL, &lenA);
387 ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
388 ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
389 expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
390 ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
393 static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
395 ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08x != %08x\n", cpinfo1->dwFlags, cpinfo2->dwFlags);
396 ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage);
397 ok(cpinfo1->uiFamilyCodePage == cpinfo2->uiFamilyCodePage, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1->uiFamilyCodePage, cpinfo2->uiFamilyCodePage);
398 ok(!lstrcmpW(cpinfo1->wszDescription, cpinfo2->wszDescription), "wszDescription mismatch\n");
399 ok(!lstrcmpW(cpinfo1->wszWebCharset, cpinfo2->wszWebCharset), "wszWebCharset mismatch\n");
400 ok(!lstrcmpW(cpinfo1->wszHeaderCharset, cpinfo2->wszHeaderCharset), "wszHeaderCharset mismatch\n");
401 ok(!lstrcmpW(cpinfo1->wszBodyCharset, cpinfo2->wszBodyCharset), "wszBodyCharset mismatch\n");
402 ok(!lstrcmpW(cpinfo1->wszFixedWidthFont, cpinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
403 ok(!lstrcmpW(cpinfo1->wszProportionalFont, cpinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
404 ok(cpinfo1->bGDICharset == cpinfo2->bGDICharset, "bGDICharset mismatch: %d != %d\n", cpinfo1->bGDICharset, cpinfo2->bGDICharset);
407 #ifdef DUMP_CP_INFO
408 static const char *dump_mime_flags(DWORD flags)
410 static char buf[1024];
412 buf[0] = 0;
414 if (flags & MIMECONTF_MAILNEWS) strcat(buf, " MIMECONTF_MAILNEWS");
415 if (flags & MIMECONTF_BROWSER) strcat(buf, " MIMECONTF_BROWSER");
416 if (flags & MIMECONTF_MINIMAL) strcat(buf, " MIMECONTF_MINIMAL");
417 if (flags & MIMECONTF_IMPORT) strcat(buf, " MIMECONTF_IMPORT");
418 if (flags & MIMECONTF_SAVABLE_MAILNEWS) strcat(buf, " MIMECONTF_SAVABLE_MAILNEWS");
419 if (flags & MIMECONTF_SAVABLE_BROWSER) strcat(buf, " MIMECONTF_SAVABLE_BROWSER");
420 if (flags & MIMECONTF_EXPORT) strcat(buf, " MIMECONTF_EXPORT");
421 if (flags & MIMECONTF_PRIVCONVERTER) strcat(buf, " MIMECONTF_PRIVCONVERTER");
422 if (flags & MIMECONTF_VALID) strcat(buf, " MIMECONTF_VALID");
423 if (flags & MIMECONTF_VALID_NLS) strcat(buf, " MIMECONTF_VALID_NLS");
424 if (flags & MIMECONTF_MIME_IE4) strcat(buf, " MIMECONTF_MIME_IE4");
425 if (flags & MIMECONTF_MIME_LATEST) strcat(buf, " MIMECONTF_MIME_LATEST");
426 if (flags & MIMECONTF_MIME_REGISTRY) strcat(buf, " MIMECONTF_MIME_REGISTRY");
428 return buf;
430 #endif
432 static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to)
434 CHAR convert[MAX_PATH];
435 BYTE dest[MAX_PATH];
436 HRESULT hr;
437 UINT srcsz, destsz;
439 static WCHAR strW[] = {'a','b','c',0};
441 /* Check to see if the target codepage has these characters or not */
442 if (from != CP_UTF8)
444 BOOL fDefaultChar;
445 char ch[10];
446 int cb;
447 cb = WideCharToMultiByte( from, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR,
448 strW, 3, ch, sizeof(ch), NULL, &fDefaultChar);
450 if(cb == 0 || fDefaultChar)
452 trace("target codepage %i does not contain 'abc'\n",from);
453 return E_FAIL;
457 srcsz = lstrlenW(strW) + 1;
458 destsz = MAX_PATH;
459 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW,
460 &srcsz, convert, &destsz);
461 if (hr != S_OK)
462 return S_FALSE;
464 srcsz = -1;
465 destsz = MAX_PATH;
466 hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert,
467 &srcsz, dest, &destsz);
468 if (hr != S_OK)
469 return S_FALSE;
471 return S_OK;
474 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
476 IEnumCodePage *iEnumCP = NULL;
477 MIMECPINFO *cpinfo;
478 MIMECPINFO cpinfo2;
479 HRESULT ret;
480 ULONG i, n;
481 UINT total;
483 total = 0;
484 ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total);
485 ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret, total);
487 trace("total mlang supported codepages %u\n", total);
489 ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP);
490 ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumCP);
492 ret = IEnumCodePage_Reset(iEnumCP);
493 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
494 n = 65536;
495 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n);
496 if (ret == S_FALSE)
497 ok(n == 0 && ret == S_FALSE, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n, ret);
498 else if (ret == E_FAIL)
499 ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
500 ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL);
501 if (ret == S_FALSE)
502 ok(ret == S_FALSE, "IEnumCodePage_Next: expected S_FALSE, got %08x\n", ret);
503 else if (ret == E_FAIL)
504 ok(n == 65536 && ret == E_FAIL, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
506 cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2);
508 n = total * 2;
509 ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n);
510 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
512 n = total * 2;
513 ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n);
514 ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret, n);
516 trace("flags %08x, enumerated codepages %u\n", flags, n);
518 if (!flags)
520 ok(n == total, "IEnumCodePage_Next: expected %u, got %u\n", total, n);
522 flags = MIMECONTF_MIME_LATEST;
525 total = n;
527 for (i = 0; i < n; i++)
529 CHARSETINFO csi;
530 MIMECSETINFO mcsi;
531 HRESULT convertible = S_OK;
532 static const WCHAR autoW[] = {'_','a','u','t','o',0};
533 static const WCHAR feffW[] = {'u','n','i','c','o','d','e','F','E','F','F',0};
535 #ifdef DUMP_CP_INFO
536 trace("MIMECPINFO #%u:\n"
537 "dwFlags %08x %s\n"
538 "uiCodePage %u\n"
539 "uiFamilyCodePage %u\n"
540 "wszDescription %s\n"
541 "wszWebCharset %s\n"
542 "wszHeaderCharset %s\n"
543 "wszBodyCharset %s\n"
544 "wszFixedWidthFont %s\n"
545 "wszProportionalFont %s\n"
546 "bGDICharset %d\n\n",
548 cpinfo[i].dwFlags, dump_mime_flags(cpinfo[i].dwFlags),
549 cpinfo[i].uiCodePage,
550 cpinfo[i].uiFamilyCodePage,
551 wine_dbgstr_w(cpinfo[i].wszDescription),
552 wine_dbgstr_w(cpinfo[i].wszWebCharset),
553 wine_dbgstr_w(cpinfo[i].wszHeaderCharset),
554 wine_dbgstr_w(cpinfo[i].wszBodyCharset),
555 wine_dbgstr_w(cpinfo[i].wszFixedWidthFont),
556 wine_dbgstr_w(cpinfo[i].wszProportionalFont),
557 cpinfo[i].bGDICharset);
558 #endif
559 ok(cpinfo[i].dwFlags & flags, "enumerated flags %08x do not include requested %08x\n", cpinfo[i].dwFlags, flags);
561 if (TranslateCharsetInfo((DWORD *)(INT_PTR)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE))
562 ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset);
563 else
564 if (winetest_debug > 1)
565 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
567 #ifdef DUMP_CP_INFO
568 trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
569 #endif
571 /* support files for some codepages might be not installed, or
572 * the codepage is just an alias.
574 if (IsValidCodePage(cpinfo[i].uiCodePage))
576 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE);
577 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo[i].uiCodePage, ret);
578 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage);
579 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
581 convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
582 if (convertible != E_FAIL)
584 ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
585 ok(ret == convertible, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret);
586 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage);
587 ok(ret == convertible, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
590 else
591 if (winetest_debug > 1)
592 trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage);
594 if (memcmp(cpinfo[i].wszWebCharset,feffW,sizeof(WCHAR)*11)==0)
595 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
596 else
598 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszWebCharset, &mcsi);
599 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
600 if (memcmp(cpinfo[i].wszWebCharset, autoW, 5 * sizeof(WCHAR)))
602 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
603 #ifdef DUMP_CP_INFO
604 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszWebCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
605 #endif
606 ok(!lstrcmpiW(cpinfo[i].wszWebCharset, mcsi.wszCharset), "%s != %s\n",
607 wine_dbgstr_w(cpinfo[i].wszWebCharset), wine_dbgstr_w(mcsi.wszCharset));
609 if (0)
611 /* native mlang returns completely messed up encodings in some cases */
612 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
613 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
614 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
615 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
620 if (memcmp(cpinfo[i].wszHeaderCharset,feffW,sizeof(WCHAR)*11)==0)
621 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
622 else
624 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszHeaderCharset, &mcsi);
625 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
626 if (memcmp(cpinfo[i].wszHeaderCharset, autoW, 5 * sizeof(WCHAR)))
628 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
629 #ifdef DUMP_CP_INFO
630 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszHeaderCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
631 #endif
632 ok(!lstrcmpiW(cpinfo[i].wszHeaderCharset, mcsi.wszCharset), "%s != %s\n",
633 wine_dbgstr_w(cpinfo[i].wszHeaderCharset), wine_dbgstr_w(mcsi.wszCharset));
635 if (0)
637 /* native mlang returns completely messed up encodings in some cases */
638 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
639 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
640 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
641 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
646 if (memcmp(cpinfo[i].wszBodyCharset,feffW,sizeof(WCHAR)*11)==0)
647 skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
648 else
650 ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszBodyCharset, &mcsi);
651 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
652 if (memcmp(cpinfo[i].wszBodyCharset, autoW, 5 * sizeof(WCHAR)))
654 ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
655 #ifdef DUMP_CP_INFO
656 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszBodyCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
657 #endif
658 ok(!lstrcmpiW(cpinfo[i].wszBodyCharset, mcsi.wszCharset), "%s != %s\n",
659 wine_dbgstr_w(cpinfo[i].wszBodyCharset), wine_dbgstr_w(mcsi.wszCharset));
661 if (0)
663 /* native mlang returns completely messed up encodings in some cases */
664 ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
665 "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
666 ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
667 "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
673 /* now IEnumCodePage_Next should fail, since pointer is at the end */
674 n = 1;
675 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
676 ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
678 ret = IEnumCodePage_Reset(iEnumCP);
679 ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
680 n = 0;
681 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
682 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
683 cpinfo_cmp(cpinfo, &cpinfo2);
685 if (0)
687 /* Due to a bug in MS' implementation of IEnumCodePage_Skip
688 * it's not used here.
690 ret = IEnumCodePage_Skip(iEnumCP, 1);
691 ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret);
693 for (i = 0; i < total - 1; i++)
695 n = 0;
696 ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
697 ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
698 cpinfo_cmp(&cpinfo[i + 1], &cpinfo2);
701 HeapFree(GetProcessHeap(), 0, cpinfo);
702 IEnumCodePage_Release(iEnumCP);
705 static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2)
707 ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId);
708 ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage);
709 ok(!lstrcmpW(sinfo1->wszDescription, sinfo2->wszDescription), "wszDescription mismatch\n");
710 ok(!lstrcmpW(sinfo1->wszFixedWidthFont, sinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
711 ok(!lstrcmpW(sinfo1->wszProportionalFont, sinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
714 static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags)
716 IEnumScript *iEnumScript = NULL;
717 SCRIPTINFO *sinfo;
718 SCRIPTINFO sinfo2;
719 HRESULT ret;
720 ULONG i, n;
721 UINT total;
723 total = 0;
724 ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total);
725 ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret, total);
727 trace("total mlang supported scripts %u\n", total);
729 ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript);
730 ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumScript);
732 ret = IEnumScript_Reset(iEnumScript);
733 ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
734 n = 65536;
735 ret = IEnumScript_Next(iEnumScript, 0, NULL, &n);
736 ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
737 ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL);
738 ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret);
740 sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2);
742 n = total * 2;
743 ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n);
744 ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
746 n = total * 2;
747 ret = IEnumScript_Next(iEnumScript, n, sinfo, &n);
748 ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret, n);
750 trace("flags %08x, enumerated scripts %u\n", flags, n);
752 if (!flags)
754 ok(n == total, "IEnumScript_Next: expected %u, got %u\n", total, n);
757 total = n;
759 for (i = 0; pGetCPInfoExA && i < n; i++)
761 #ifdef DUMP_SCRIPT_INFO
762 trace("SCRIPTINFO #%u:\n"
763 "ScriptId %08x\n"
764 "uiCodePage %u\n"
765 "wszDescription %s\n"
766 "wszFixedWidthFont %s\n"
767 "wszProportionalFont %s\n\n",
769 sinfo[i].ScriptId,
770 sinfo[i].uiCodePage,
771 wine_dbgstr_w(sinfo[i].wszDescription),
772 wine_dbgstr_w(sinfo[i].wszFixedWidthFont),
773 wine_dbgstr_w(sinfo[i].wszProportionalFont));
774 trace("%u codepage %u\n", i, sinfo[i].uiCodePage);
775 #endif
778 /* now IEnumScript_Next should fail, since pointer is at the end */
779 n = 1;
780 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
781 ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
783 ret = IEnumScript_Reset(iEnumScript);
784 ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
785 n = 0;
786 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
787 ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
788 scriptinfo_cmp(sinfo, &sinfo2);
790 if (0)
792 /* Due to a bug in MS' implementation of IEnumScript_Skip
793 * it's not used here.
795 ret = IEnumScript_Skip(iEnumScript, 1);
796 ok(ret == S_OK, "IEnumScript_Skip: expected S_OK, got %08x\n", ret);
798 for (i = 0; i < total - 1; i++)
800 n = 0;
801 ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
802 ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
803 scriptinfo_cmp(&sinfo[i + 1], &sinfo2);
806 HeapFree(GetProcessHeap(), 0, sinfo);
807 IEnumScript_Release(iEnumScript);
810 static void IMLangFontLink_Test(IMLangFontLink* iMLFL)
812 DWORD dwCodePages, dwManyCodePages;
813 DWORD dwCmpCodePages;
814 UINT CodePage;
815 static const WCHAR str[] = { 'd', 0x0436, 0xff90 };
816 LONG processed;
817 HRESULT ret;
819 dwCodePages = ~0u;
820 ret = IMLangFontLink_CodePageToCodePages(iMLFL, -1, &dwCodePages);
821 ok(ret == E_FAIL, "IMLangFontLink_CodePageToCodePages should fail: %x\n", ret);
822 ok(dwCodePages == 0, "expected 0, got %u\n", dwCodePages);
824 dwCodePages = 0;
825 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages);
826 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
827 ok(dwCodePages == FS_JISJAPAN, "expected FS_JISJAPAN, got %08x\n", dwCodePages);
828 CodePage = 0;
829 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, &CodePage);
830 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
831 ok(CodePage == 932, "Incorrect CodePage Returned (%i)\n",CodePage);
833 dwManyCodePages = 0;
834 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwManyCodePages);
835 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
836 ok(dwManyCodePages == FS_LATIN1, "expected FS_LATIN1, got %08x\n", dwManyCodePages);
837 dwCodePages = 0;
838 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages);
839 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
840 ok(dwCodePages == FS_ARABIC, "expected FS_ARABIC, got %08x\n", dwCodePages);
841 dwManyCodePages |= dwCodePages;
842 ret = IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages);
843 ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
844 ok(dwCodePages == FS_THAI, "expected FS_THAI, got %08x\n", dwCodePages);
845 dwManyCodePages |= dwCodePages;
847 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, &CodePage);
848 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
849 ok(CodePage == 1256, "Incorrect CodePage Returned (%i)\n",CodePage);
851 ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, &CodePage);
852 ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
853 ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage);
855 /* Tests for GetCharCodePages */
857 /* Latin 1 */
858 dwCmpCodePages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH
859 | FS_HEBREW | FS_ARABIC | FS_BALTIC | FS_VIETNAMESE | FS_THAI
860 | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG | FS_CHINESETRAD;
861 ret = IMLangFontLink_GetCharCodePages(iMLFL, 'd', &dwCodePages);
862 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
863 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
865 dwCodePages = 0;
866 processed = 0;
867 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 1, 0, &dwCodePages, &processed);
868 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
869 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
870 ok(processed == 1, "expected 1, got %d\n", processed);
872 /* Cyrillic */
873 dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
874 ret = IMLangFontLink_GetCharCodePages(iMLFL, 0x0436, &dwCodePages);
875 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
876 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
878 dwCodePages = 0;
879 processed = 0;
880 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[1], 1, 0, &dwCodePages, &processed);
881 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
882 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
883 ok(processed == 1, "expected 1, got %d\n", processed);
885 /* Japanese */
886 dwCmpCodePages = FS_JISJAPAN;
887 ret = IMLangFontLink_GetCharCodePages(iMLFL, 0xff90, &dwCodePages);
888 ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
889 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
891 dwCodePages = 0;
892 processed = 0;
893 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
894 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
895 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
896 ok(processed == 1, "expected 1, got %d\n", processed);
898 dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
899 dwCodePages = 0;
900 processed = 0;
901 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 2, 0, &dwCodePages, &processed);
902 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
903 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
904 ok(processed == 2, "expected 2, got %d\n", processed);
906 dwCmpCodePages = FS_JISJAPAN;
907 dwCodePages = 0;
908 processed = 0;
909 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 3, 0, &dwCodePages, &processed);
910 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
911 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
912 ok(processed == 3, "expected 3, got %d\n", processed);
914 dwCodePages = 0xffff;
915 processed = -1;
916 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
917 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
918 ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
919 ok(processed == 1, "expected 0, got %d\n", processed);
921 ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, NULL, NULL);
922 ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
924 dwCodePages = 0xffff;
925 processed = -1;
926 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, -1, 0, &dwCodePages, &processed);
927 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
928 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
929 ok(processed == 0, "expected 0, got %d\n", processed);
931 dwCodePages = 0xffff;
932 processed = -1;
933 ret = IMLangFontLink_GetStrCodePages(iMLFL, NULL, 1, 0, &dwCodePages, &processed);
934 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
935 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
936 ok(processed == 0, "expected 0, got %d\n", processed);
938 dwCodePages = 0xffff;
939 processed = -1;
940 ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 0, 0, &dwCodePages, &processed);
941 ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
942 ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
943 ok(processed == 0, "expected 0, got %d\n", processed);
946 /* copied from libs/wine/string.c */
947 static WCHAR *strstrW(const WCHAR *str, const WCHAR *sub)
949 while (*str)
951 const WCHAR *p1 = str, *p2 = sub;
952 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
953 if (!*p2) return (WCHAR *)str;
954 str++;
956 return NULL;
959 static void test_rfc1766(IMultiLanguage2 *iML2)
961 IEnumRfc1766 *pEnumRfc1766;
962 RFC1766INFO info;
963 ULONG n;
964 HRESULT ret;
965 BSTR rfcstr;
967 ret = IMultiLanguage2_EnumRfc1766(iML2, LANG_NEUTRAL, &pEnumRfc1766);
968 ok(ret == S_OK, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret);
970 while (1)
972 ret = IEnumRfc1766_Next(pEnumRfc1766, 1, &info, &n);
973 if (ret != S_OK) break;
975 #ifdef DUMP_CP_INFO
976 trace("lcid %04x rfc_name %s locale_name %s\n",
977 info.lcid, wine_dbgstr_w(info.wszRfc1766), wine_dbgstr_w(info.wszLocaleName));
978 #endif
980 ok(n == 1, "couldn't fetch 1 RFC1766INFO structure\n");
982 /* verify the Rfc1766 value */
983 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, info.lcid, &rfcstr);
984 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
986 /* not an exact 1:1 correspondence between lcid and rfc1766 in the
987 * mlang database, e.g., nb-no -> 1044 -> no */
988 ok(strstrW(info.wszRfc1766, rfcstr) != NULL,
989 "Expected matching locale names\n");
991 SysFreeString(rfcstr);
993 IEnumRfc1766_Release(pEnumRfc1766);
996 static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2)
998 WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
999 LCID lcid;
1000 HRESULT ret;
1001 DWORD i;
1003 static WCHAR en[] = { 'e','n',0 };
1004 static WCHAR en_them[] = { 'e','n','-','t','h','e','m',0 };
1005 static WCHAR english[] = { 'e','n','g','l','i','s','h',0 };
1008 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1009 lcid = -1;
1010 MultiByteToWideChar(CP_ACP, 0, lcid_table[i].rfc1766, -1, rfc1766W, MAX_RFC1766_NAME);
1011 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, rfc1766W);
1013 /* IE <6.0 guess 0x412 (ko) from "kok" */
1014 ok((ret == lcid_table[i].hr) ||
1015 broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1016 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1018 ok((lcid == lcid_table[i].lcid) ||
1019 broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */
1020 "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1024 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, NULL, en);
1025 ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1027 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, NULL);
1028 ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1030 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_them);
1031 ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1032 if (ret == S_FALSE)
1034 BSTR rfcstr;
1035 static WCHAR en[] = {'e','n',0};
1037 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1038 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1039 ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr);
1042 ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, english);
1043 ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1044 if (ret == S_FALSE)
1046 BSTR rfcstr;
1047 static WCHAR en[] = {'e','n',0};
1049 ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1050 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1051 ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr);
1056 static void test_Rfc1766ToLcid(void)
1058 LCID lcid;
1059 HRESULT ret;
1060 DWORD i;
1062 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1063 lcid = -1;
1064 ret = pRfc1766ToLcidA(&lcid, lcid_table[i].rfc1766);
1066 /* IE <6.0 guess 0x412 (ko) from "kok" */
1067 ok( (ret == lcid_table[i].hr) ||
1068 broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1069 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1071 ok( (lcid == lcid_table[i].lcid) ||
1072 broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */
1073 "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1076 ret = pRfc1766ToLcidA(&lcid, NULL);
1077 ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1079 ret = pRfc1766ToLcidA(NULL, "en");
1080 ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1083 static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2)
1085 HRESULT hr;
1086 UINT value;
1088 value = 0xdeadbeef;
1089 hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &value);
1090 ok( (hr == S_OK) && value,
1091 "got 0x%x with %d (expected S_OK with '!= 0')\n", hr, value);
1093 hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, NULL);
1094 ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1098 static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2)
1100 CHAR expected[MAX_RFC1766_NAME];
1101 CHAR buffer[MAX_RFC1766_NAME + 1];
1102 DWORD i;
1103 HRESULT hr;
1104 BSTR rfcstr;
1106 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1107 buffer[0] = '\0';
1109 rfcstr = NULL;
1110 hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid_table[i].lcid, &rfcstr);
1111 ok(hr == lcid_table[i].hr,
1112 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1114 if (hr != S_OK)
1115 continue; /* no result-string created */
1117 WideCharToMultiByte(CP_ACP, 0, rfcstr, -1, buffer, sizeof(buffer), NULL, NULL);
1118 LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766,
1119 lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1121 /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1122 ok( (!lstrcmpA(buffer, expected)) ||
1123 broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1124 "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1126 SysFreeString(rfcstr);
1129 hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL);
1130 ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1133 static void test_LcidToRfc1766(void)
1135 CHAR expected[MAX_RFC1766_NAME];
1136 CHAR buffer[MAX_RFC1766_NAME * 2];
1137 HRESULT hr;
1138 DWORD i;
1140 for(i = 0; i < sizeof(lcid_table) / sizeof(lcid_table[0]); i++) {
1142 memset(buffer, '#', sizeof(buffer)-1);
1143 buffer[sizeof(buffer)-1] = '\0';
1145 hr = pLcidToRfc1766A(lcid_table[i].lcid, buffer, MAX_RFC1766_NAME);
1147 /* IE <5.0 does not recognize 0x180c (fr-mc) and 0x457 (kok) */
1148 ok( (hr == lcid_table[i].hr) ||
1149 broken(lcid_table[i].broken_lcid && (hr == E_FAIL)),
1150 "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1152 if (hr != S_OK)
1153 continue;
1155 LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, lcid_table[i].rfc1766,
1156 lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1158 /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1159 /* IE <5.0 return "fr" for LCID 0x180c ("fr-mc") */
1160 ok( (!lstrcmpA(buffer, expected)) ||
1161 broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1162 "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1166 memset(buffer, '#', sizeof(buffer)-1);
1167 buffer[sizeof(buffer)-1] = '\0';
1168 hr = pLcidToRfc1766A(-1, buffer, MAX_RFC1766_NAME);
1169 ok(hr == E_FAIL, "got 0x%08x and '%s' (expected E_FAIL)\n", hr, buffer);
1171 hr = pLcidToRfc1766A(LANG_ENGLISH, NULL, MAX_RFC1766_NAME);
1172 ok(hr == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", hr);
1174 memset(buffer, '#', sizeof(buffer)-1);
1175 buffer[sizeof(buffer)-1] = '\0';
1176 hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, -1);
1177 ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1179 memset(buffer, '#', sizeof(buffer)-1);
1180 buffer[sizeof(buffer)-1] = '\0';
1181 hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, 0);
1182 ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1185 static void test_GetRfc1766Info(IMultiLanguage2 *iML2)
1187 WCHAR short_broken_name[MAX_LOCALE_NAME];
1188 CHAR rfc1766A[MAX_RFC1766_NAME + 1];
1189 BYTE buffer[sizeof(RFC1766INFO) + 4];
1190 PRFC1766INFO prfc = (RFC1766INFO *) buffer;
1191 HRESULT ret;
1192 DWORD i;
1194 for(i = 0; i < sizeof(info_table) / sizeof(info_table[0]); i++) {
1195 memset(buffer, 'x', sizeof(RFC1766INFO) + 2);
1196 buffer[sizeof(buffer) -1] = 0;
1197 buffer[sizeof(buffer) -2] = 0;
1199 ret = IMultiLanguage2_GetRfc1766Info(iML2, info_table[i].lcid, info_table[i].lang, prfc);
1200 WideCharToMultiByte(CP_ACP, 0, prfc->wszRfc1766, -1, rfc1766A, MAX_RFC1766_NAME, NULL, NULL);
1201 ok(ret == S_OK, "#%02d: got 0x%x (expected S_OK)\n", i, ret);
1202 ok(prfc->lcid == info_table[i].lcid,
1203 "#%02d: got 0x%04x (expected 0x%04x)\n", i, prfc->lcid, info_table[i].lcid);
1205 ok(!lstrcmpA(rfc1766A, info_table[i].rfc1766),
1206 "#%02d: got '%s' (expected '%s')\n", i, rfc1766A, info_table[i].rfc1766);
1208 /* Some IE versions truncate an oversized name one character too short */
1209 if (info_table[i].broken_name) {
1210 lstrcpyW(short_broken_name, info_table[i].broken_name);
1211 short_broken_name[MAX_LOCALE_NAME - 2] = 0;
1214 if (info_table[i].todo & TODO_NAME) {
1215 todo_wine
1216 ok( (!lstrcmpW(prfc->wszLocaleName, info_table[i].localename)) ||
1217 (info_table[i].broken_name && (
1218 broken(!lstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */
1219 broken(!lstrcmpW(prfc->wszLocaleName, short_broken_name)))),
1220 "#%02d: got %s (expected %s)\n", i,
1221 wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename));
1223 else
1224 ok( (!lstrcmpW(prfc->wszLocaleName, info_table[i].localename)) ||
1225 (info_table[i].broken_name && (
1226 broken(!lstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */
1227 broken(!lstrcmpW(prfc->wszLocaleName, short_broken_name)))),
1228 "#%02d: got %s (expected %s)\n", i,
1229 wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename));
1233 /* SUBLANG_NEUTRAL only allowed for English, Arabic, Chinese */
1234 ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1235 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1237 ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_ITALIAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1238 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1240 /* NULL not allowed */
1241 ret = IMultiLanguage2_GetRfc1766Info(iML2, 0, LANG_ENGLISH, prfc);
1242 ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1244 ret = IMultiLanguage2_GetRfc1766Info(iML2, LANG_ENGLISH, LANG_ENGLISH, NULL);
1245 ok(ret == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", ret);
1248 static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2)
1250 CHAR dest[MAX_PATH];
1251 CHAR invariate[MAX_PATH];
1252 UINT srcsz, destsz;
1253 HRESULT hr;
1255 static WCHAR src[] = {'a','b','c',0};
1257 memset(invariate, 'x', sizeof(invariate));
1259 /* pSrcStr NULL */
1260 memset(dest, 'x', sizeof(dest));
1261 srcsz = lstrlenW(src) + 1;
1262 destsz = sizeof(dest);
1263 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1264 &srcsz, dest, &destsz);
1265 ok(hr == S_OK || hr == E_FAIL,"expected S_OK or E_FAIL, got %08x\n",hr);
1266 if (hr == S_OK)
1268 ok(srcsz == lstrlenW(src) + 1,
1269 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1271 else if (hr == E_FAIL)
1273 ok(srcsz == 0,
1274 "Expected %u, got %u\n", 0, srcsz);
1277 ok(!memcmp(dest, invariate, sizeof(dest)),
1278 "Expected dest to be unchanged, got %s\n", dest);
1279 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1281 /* pcSrcSize NULL */
1282 memset(dest, 'x', sizeof(dest));
1283 destsz = sizeof(dest);
1284 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1285 NULL, dest, &destsz);
1286 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1287 ok(!strncmp(dest, "abc", 3),
1288 "Expected first three chars to be \"abc\"\n");
1289 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1290 "Expected rest of dest to be unchanged, got %s\n", dest);
1291 ok(destsz == lstrlenW(src),
1292 "Expected %u, got %u\n", lstrlenW(src), destsz);
1294 /* both pSrcStr and pcSrcSize NULL */
1295 memset(dest, 'x', sizeof(dest));
1296 destsz = sizeof(dest);
1297 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1298 NULL, dest, &destsz);
1299 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1300 ok(!memcmp(dest, invariate, sizeof(dest)),
1301 "Expected dest to be unchanged, got %s\n", dest);
1302 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1304 /* pDstStr NULL */
1305 memset(dest, 'x', sizeof(dest));
1306 srcsz = lstrlenW(src) + 1;
1307 destsz = sizeof(dest);
1308 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1309 &srcsz, NULL, &destsz);
1310 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1311 ok(srcsz == lstrlenW(src) + 1,
1312 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1313 ok(destsz == lstrlenW(src) + 1,
1314 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1316 /* pcDstSize NULL */
1317 memset(dest, 'x', sizeof(dest));
1318 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1319 &srcsz, dest, NULL);
1320 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1321 ok(srcsz == lstrlenW(src) + 1,
1322 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1323 ok(!memcmp(dest, invariate, sizeof(dest)),
1324 "Expected dest to be unchanged, got %s\n", dest);
1326 /* pcSrcSize is 0 */
1327 memset(dest, 'x', sizeof(dest));
1328 srcsz = 0;
1329 destsz = sizeof(dest);
1330 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1331 &srcsz, dest, &destsz);
1332 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1333 ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1334 ok(!memcmp(dest, invariate, sizeof(dest)),
1335 "Expected dest to be unchanged, got %s\n", dest);
1336 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1338 /* pcSrcSize does not include NULL terminator */
1339 memset(dest, 'x', sizeof(dest));
1340 srcsz = lstrlenW(src);
1341 destsz = sizeof(dest);
1342 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1343 &srcsz, dest, &destsz);
1344 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1345 ok(srcsz == lstrlenW(src),
1346 "Expected %u, got %u\n", lstrlenW(src), srcsz);
1347 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1348 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1349 "Expected rest of dest to be unchanged, got %s\n", dest);
1350 ok(destsz == lstrlenW(src),
1351 "Expected %u, got %u\n", lstrlenW(src), destsz);
1353 /* pcSrcSize includes NULL terminator */
1354 memset(dest, 'x', sizeof(dest));
1355 srcsz = lstrlenW(src) + 1;
1356 destsz = sizeof(dest);
1357 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1358 &srcsz, dest, &destsz);
1359 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1360 ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1361 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1362 ok(destsz == lstrlenW(src) + 1,
1363 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1365 /* pcSrcSize is -1 */
1366 memset(dest, 'x', sizeof(dest));
1367 srcsz = -1;
1368 destsz = sizeof(dest);
1369 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1370 &srcsz, dest, &destsz);
1371 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1372 ok(srcsz == lstrlenW(src),
1373 "Expected %u, got %u\n", lstrlenW(src), srcsz);
1374 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1375 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1376 "Expected rest of dest to be unchanged, got %s\n", dest);
1377 ok(destsz == lstrlenW(src),
1378 "Expected %u, got %u\n", lstrlenW(src), destsz);
1380 /* pcDstSize is 0 */
1381 memset(dest, 'x', sizeof(dest));
1382 srcsz = lstrlenW(src) + 1;
1383 destsz = 0;
1384 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1385 &srcsz, dest, &destsz);
1386 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1387 ok(srcsz == lstrlenW(src) + 1,
1388 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1389 ok(!memcmp(dest, invariate, sizeof(dest)),
1390 "Expected dest to be unchanged, got %s\n", dest);
1391 ok(destsz == lstrlenW(src) + 1,
1392 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1394 /* pcDstSize is not large enough */
1395 memset(dest, 'x', sizeof(dest));
1396 srcsz = lstrlenW(src) + 1;
1397 destsz = lstrlenW(src);
1398 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1399 &srcsz, dest, &destsz);
1400 ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1401 ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1402 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1403 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1404 "Expected rest of dest to be unchanged, got %s\n", dest);
1405 ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1407 /* pcDstSize (bytes) does not leave room for NULL terminator */
1408 memset(dest, 'x', sizeof(dest));
1409 srcsz = lstrlenW(src) + 1;
1410 destsz = lstrlenW(src) * sizeof(WCHAR);
1411 hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1412 &srcsz, dest, &destsz);
1413 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1414 ok(srcsz == lstrlenW(src) + 1,
1415 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1416 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1417 ok(destsz == lstrlenW(src) + 1,
1418 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1421 static void test_ConvertINetUnicodeToMultiByte(void)
1423 CHAR dest[MAX_PATH];
1424 CHAR invariate[MAX_PATH];
1425 INT srcsz, destsz;
1426 HRESULT hr;
1428 static WCHAR src[] = {'a','b','c',0};
1430 memset(invariate, 'x', sizeof(invariate));
1432 /* lpSrcStr NULL */
1433 memset(dest, 'x', sizeof(dest));
1434 srcsz = lstrlenW(src) + 1;
1435 destsz = sizeof(dest);
1436 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, &srcsz, dest, &destsz);
1437 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1438 if (hr == S_OK)
1439 ok(srcsz == lstrlenW(src) + 1,
1440 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1441 else if (hr == E_FAIL)
1442 ok(srcsz == 0,
1443 "Expected %u, got %u\n", 0, srcsz);
1444 ok(!memcmp(dest, invariate, sizeof(dest)),
1445 "Expected dest to be unchanged, got %s\n", dest);
1446 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1448 /* lpnWideCharCount NULL */
1449 memset(dest, 'x', sizeof(dest));
1450 destsz = sizeof(dest);
1451 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, NULL, dest, &destsz);
1452 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1453 ok(!strncmp(dest, "abc", 3),
1454 "Expected first three chars to be \"abc\"\n");
1455 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1456 "Expected rest of dest to be unchanged, got %s\n", dest);
1457 ok(destsz == lstrlenW(src),
1458 "Expected %u, got %u\n", lstrlenW(src), destsz);
1460 /* both lpSrcStr and lpnWideCharCount NULL */
1461 memset(dest, 'x', sizeof(dest));
1462 destsz = sizeof(dest);
1463 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, NULL, dest, &destsz);
1464 ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1465 ok(!memcmp(dest, invariate, sizeof(dest)),
1466 "Expected dest to be unchanged, got %s\n", dest);
1467 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1469 /* lpDstStr NULL */
1470 memset(dest, 'x', sizeof(dest));
1471 srcsz = lstrlenW(src) + 1;
1472 destsz = sizeof(dest);
1473 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, NULL, &destsz);
1474 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1475 ok(srcsz == lstrlenW(src) + 1,
1476 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1477 ok(destsz == lstrlenW(src) + 1,
1478 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1480 /* lpnMultiCharCount NULL */
1481 memset(dest, 'x', sizeof(dest));
1482 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, NULL);
1483 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1484 ok(srcsz == lstrlenW(src) + 1,
1485 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1486 ok(!memcmp(dest, invariate, sizeof(dest)),
1487 "Expected dest to be unchanged, got %s\n", dest);
1489 /* lpnWideCharCount is 0 */
1490 memset(dest, 'x', sizeof(dest));
1491 srcsz = 0;
1492 destsz = sizeof(dest);
1493 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1494 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1495 ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1496 ok(!memcmp(dest, invariate, sizeof(dest)),
1497 "Expected dest to be unchanged, got %s\n", dest);
1498 ok(destsz == 0, "Expected 0, got %u\n", destsz);
1500 /* lpnWideCharCount does not include NULL terminator */
1501 memset(dest, 'x', sizeof(dest));
1502 srcsz = lstrlenW(src);
1503 destsz = sizeof(dest);
1504 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1505 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1506 ok(srcsz == lstrlenW(src),
1507 "Expected %u, got %u\n", lstrlenW(src), srcsz);
1508 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1509 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1510 "Expected rest of dest to be unchanged, got %s\n", dest);
1511 ok(destsz == lstrlenW(src),
1512 "Expected %u, got %u\n", lstrlenW(src), destsz);
1514 /* lpnWideCharCount includes NULL terminator */
1515 memset(dest, 'x', sizeof(dest));
1516 srcsz = lstrlenW(src) + 1;
1517 destsz = sizeof(dest);
1518 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1519 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1520 ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1521 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1522 ok(destsz == lstrlenW(src) + 1,
1523 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1525 /* lpnWideCharCount is -1 */
1526 memset(dest, 'x', sizeof(dest));
1527 srcsz = -1;
1528 destsz = sizeof(dest);
1529 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1530 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1531 ok(srcsz == lstrlenW(src),
1532 "Expected %u, got %u\n", lstrlenW(src), srcsz);
1533 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1534 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1535 "Expected rest of dest to be unchanged, got %s\n", dest);
1536 ok(destsz == lstrlenW(src),
1537 "Expected %u, got %u\n", lstrlenW(src), destsz);
1539 /* lpnMultiCharCount is 0 */
1540 memset(dest, 'x', sizeof(dest));
1541 srcsz = lstrlenW(src) + 1;
1542 destsz = 0;
1543 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1544 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1545 ok(srcsz == lstrlenW(src) + 1,
1546 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1547 ok(!memcmp(dest, invariate, sizeof(dest)),
1548 "Expected dest to be unchanged, got %s\n", dest);
1549 ok(destsz == lstrlenW(src) + 1,
1550 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1552 /* lpnMultiCharCount is not large enough */
1553 memset(dest, 'x', sizeof(dest));
1554 srcsz = lstrlenW(src) + 1;
1555 destsz = lstrlenW(src);
1556 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1557 ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1558 ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1559 ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1560 ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1561 "Expected rest of dest to be unchanged, got %s\n", dest);
1562 ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1564 /* lpnMultiCharCount (bytes) does not leave room for NULL terminator */
1565 memset(dest, 'x', sizeof(dest));
1566 srcsz = lstrlenW(src) + 1;
1567 destsz = lstrlenW(src) * sizeof(WCHAR);
1568 hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1569 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1570 ok(srcsz == lstrlenW(src) + 1,
1571 "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1572 ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1573 ok(destsz == lstrlenW(src) + 1,
1574 "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1577 static void test_JapaneseConversion(void)
1579 /* Data */
1580 static WCHAR unc_jp[9][12] = {
1581 {9,0x31,0x20,0x3042,0x3044,0x3046,0x3048,0x304a,0x000d,0x000a},
1582 {9,0x31,0x20,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x000d,0x000a},
1583 {9,0x31,0x20,0xff71,0xff72,0xff73,0xff74,0xff75,0x000d,0x000a},
1584 {9,0x31,0x20,0x3041,0x3043,0x3045,0x3047,0x3049,0x000d,0x000a},
1585 {9,0x31,0x20,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x000d,0x000a},
1586 {9,0x31,0x20,0xff67,0xff68,0xff69,0xff6a,0xff6b,0x000d,0x000a},
1587 {9,0x31,0x20,0x300c,0x65e5,0x672c,0x8a9e,0x300d,0x000d,0x000a},
1588 {7,0x31,0x20,0x25c7,0x25c7,0x3012,0x000d,0x000a},
1589 {11,0x31,0x20,0x203b,0x3010,0x0074,0x0065,0x0073,0x0074,0x3011,0x000d,0x000a}
1591 static CHAR jis_jp[9][27] = {
1592 {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x22,0x24,0x24,0x24,0x26,0x24,0x28,
1593 0x24,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1594 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1595 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1596 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1597 0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1598 {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x21,0x24,0x23,0x24,0x25,0x24,0x27,
1599 0x24,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1600 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1601 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1602 {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1603 0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1604 {20,0x31,0x20,0x1b,0x24,0x42,0x21,0x56,0x46,0x7c,0x4b,0x5c,0x38,0x6c,
1605 0x21,0x57,0x1b,0x28,0x42,0x0d,0x0a},
1606 {16,0x31,0x20,0x1b,0x24,0x42,0x21,0x7e,0x21,0x7e,0x22,0x29,0x1b,0x28,
1607 0x42,0x0d,0x0a},
1608 {26,0x31,0x20,0x1b,0x24,0x42,0x22,0x28,0x21,0x5a,0x1b,0x28,0x42,0x74,
1609 0x65,0x73,0x74,0x1b,0x24,0x42,0x21,0x5b,0x1b,0x28,0x42,0x0d,0x0a}
1611 static CHAR sjis_jp[9][15] = {
1612 {14,0x31,0x20,0x82,0xa0,0x82,0xa2,0x82,0xa4,0x82,0xa6,0x82,0xa8,0x0d,0x0a},
1613 {14,0x31,0x20,0x83,0x41,0x83,0x43,0x83,0x45,0x83,0x47,0x83,0x49,0x0d,0x0a},
1614 {9,0x31,0x20,0xb1,0xb2,0xb3,0xb4,0xb5,0x0d,0x0a},
1615 {14,0x31,0x20,0x82,0x9f,0x82,0xa1,0x82,0xa3,0x82,0xa5,0x82,0xa7,0x0d,0x0a},
1616 {14,0x31,0x20,0x83,0x40,0x83,0x42,0x83,0x44,0x83,0x46,0x83,0x48,0x0d,0x0a},
1617 {9,0x31,0x20,0xa7,0xa8,0xa9,0xaa,0xab,0x0d,0x0a},
1618 {14,0x31,0x20,0x81,0x75,0x93,0xfa,0x96,0x7b,0x8c,0xea,0x81,0x76,0x0d,0x0a},
1619 {10,0x31,0x20,0x81,0x9e,0x81,0x9e,0x81,0xa7,0x0d,0x0a},
1620 {14,0x31,0x20,0x81,0xa6,0x81,0x79,0x74,0x65,0x73,0x74,0x81,0x7a,0x0d,0x0a}
1622 static CHAR euc_jp[9][15] = {
1623 {14,0x31,0x20,0xa4,0xa2,0xa4,0xa4,0xa4,0xa6,0xa4,0xa8,0xa4,0xaa,0x0d,0x0a},
1624 {14,0x31,0x20,0xa5,0xa2,0xa5,0xa4,0xa5,0xa6,0xa5,0xa8,0xa5,0xaa,0x0d,0x0a},
1625 {14,0x31,0x20,0x8e,0xb1,0x8e,0xb2,0x8e,0xb3,0x8e,0xb4,0x8e,0xb5,0x0d,0x0a},
1626 {14,0x31,0x20,0xa4,0xa1,0xa4,0xa3,0xa4,0xa5,0xa4,0xa7,0xa4,0xa9,0x0d,0x0a},
1627 {14,0x31,0x20,0xa5,0xa1,0xa5,0xa3,0xa5,0xa5,0xa5,0xa7,0xa5,0xa9,0x0d,0x0a},
1628 {14,0x31,0x20,0x8e,0xa7,0x8e,0xa8,0x8e,0xa9,0x8e,0xaa,0x8e,0xab,0x0d,0x0a},
1629 {14,0x31,0x20,0xa1,0xd6,0xc6,0xfc,0xcb,0xdc,0xb8,0xec,0xa1,0xd7,0x0d,0x0a},
1630 {10,0x31,0x20,0xa1,0xfe,0xa1,0xfe,0xa2,0xa9,0x0d,0x0a},
1631 {14,0x31,0x20,0xa2,0xa8,0xa1,0xda,0x74,0x65,0x73,0x74,0xa1,0xdb,0x0d,0x0a}
1634 INT srcsz, destsz;
1635 INT i;
1636 HRESULT hr;
1637 CHAR output[30];
1638 WCHAR outputW[30];
1639 int outlen;
1641 /* test unc->jis */
1642 for (i = 0; i < 9; i++)
1644 int j;
1645 destsz = 30;
1646 outlen = jis_jp[i][0];
1647 srcsz = unc_jp[i][0];
1648 hr = pConvertINetUnicodeToMultiByte(NULL, 50220, &unc_jp[i][1], &srcsz, output, &destsz);
1649 if (hr == S_FALSE)
1651 skip("Code page identifier 50220 is not supported\n");
1652 break;
1654 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
1655 ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
1656 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
1657 ok(memcmp(output,&jis_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1659 /* and back */
1660 srcsz = outlen;
1661 destsz = 30;
1662 hr = pConvertINetMultiByteToUnicode(NULL, 50220, output, &srcsz, outputW,&destsz);
1665 * JIS does not have hankata so it get automatically converted to
1666 * zenkata. this means that strings 1 and 2 are identical as well as
1667 * strings 4 and 5.
1669 j = i;
1670 if (i == 2) j = 1;
1671 if (i == 5) j = 4;
1673 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i, hr);
1674 ok(destsz == unc_jp[j][0],"(%i) Expected %i, got %i\n",i,unc_jp[j][0],destsz);
1675 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1676 ok(memcmp(outputW,&unc_jp[j][1],destsz)==0,"(%i) Strings do not match\n",i);
1679 /* test unc->sjis */
1680 for (i = 0; i < 9; i++)
1682 destsz = 30;
1683 outlen = sjis_jp[i][0];
1684 srcsz = unc_jp[i][0];
1686 hr = pConvertINetUnicodeToMultiByte(NULL, 932, &unc_jp[i][1], &srcsz, output, &destsz);
1687 if (hr == S_FALSE)
1689 skip("Code page identifier 932 is not supported\n");
1690 break;
1692 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1693 ok(destsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,destsz);
1694 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
1695 ok(memcmp(output,&sjis_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
1697 srcsz = outlen;
1698 destsz = 30;
1699 hr = pConvertINetMultiByteToUnicode(NULL, 932, output, &srcsz, outputW,&destsz);
1701 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
1702 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1703 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1704 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1707 /* test unc->euc */
1708 for (i = 0; i < 9; i++)
1710 destsz = 30;
1711 outlen = euc_jp[i][0];
1712 srcsz = unc_jp[i][0];
1714 hr = pConvertINetUnicodeToMultiByte(NULL, 51932, &unc_jp[i][1], &srcsz, output, &destsz);
1715 if (hr == S_FALSE)
1717 skip("Code page identifier 51932 is not supported\n");
1718 break;
1720 ok(hr == S_OK, "(%i) Expected S_OK, got %08x\n",i,hr);
1721 ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
1722 ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1723 ok(memcmp(output,&euc_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
1725 srcsz = outlen;
1726 destsz = 30;
1727 hr = pConvertINetMultiByteToUnicode(NULL, 51932, output, &srcsz, outputW,&destsz);
1729 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1730 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1731 ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
1732 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1735 /* Japanese autodetect */
1736 i = 0;
1737 destsz = 30;
1738 srcsz = jis_jp[i][0];
1739 hr = pConvertINetMultiByteToUnicode(NULL, 50932, &jis_jp[i][1], &srcsz, outputW, &destsz);
1740 if (hr == S_FALSE)
1742 skip("Code page identifier 50932 is not supported\n");
1743 return;
1745 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1746 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1747 ok(srcsz == jis_jp[i][0],"(%i) Expected %i, got %i\n",i,jis_jp[i][0],srcsz);
1748 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1750 i = 1;
1751 destsz = 30;
1752 srcsz = sjis_jp[i][0];
1753 hr = pConvertINetMultiByteToUnicode(NULL, 50932, &sjis_jp[i][1], &srcsz, outputW, &destsz);
1754 ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
1755 ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
1756 ok(srcsz == sjis_jp[i][0],"(%i) Expected %i, got %i\n",i,sjis_jp[i][0],srcsz);
1757 ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
1760 static void test_GetScriptFontInfo(IMLangFontLink2 *font_link)
1762 HRESULT hr;
1763 UINT nfonts;
1764 SCRIPTFONTINFO sfi[1];
1766 nfonts = 0;
1767 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, 0, &nfonts, NULL);
1768 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1769 ok(nfonts, "unexpected result\n");
1771 nfonts = 0;
1772 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, NULL);
1773 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1774 ok(nfonts, "unexpected result\n");
1776 nfonts = 0;
1777 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, NULL);
1778 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1779 ok(nfonts, "unexpected result\n");
1781 nfonts = 1;
1782 memset(sfi, 0, sizeof(sfi));
1783 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, sfi);
1784 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1785 ok(nfonts == 1, "got %u, expected 1\n", nfonts);
1786 ok(sfi[0].scripts != 0, "unexpected result\n");
1787 ok(sfi[0].wszFont[0], "unexpected result\n");
1789 nfonts = 1;
1790 memset(sfi, 0, sizeof(sfi));
1791 hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, sfi);
1792 ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
1793 ok(nfonts == 1, "got %u, expected 1\n", nfonts);
1794 ok(sfi[0].scripts != 0, "unexpected result\n");
1795 ok(sfi[0].wszFont[0], "unexpected result\n");
1798 static void test_CodePageToScriptID(IMLangFontLink2 *font_link)
1800 HRESULT hr;
1801 UINT i;
1802 SCRIPT_ID sid;
1803 static const struct
1805 UINT cp;
1806 SCRIPT_ID sid;
1807 HRESULT hr;
1809 cp_sid[] =
1811 {874, sidThai},
1812 {932, sidKana},
1813 {936, sidHan},
1814 {949, sidHangul},
1815 {950, sidBopomofo},
1816 {1250, sidAsciiLatin},
1817 {1251, sidCyrillic},
1818 {1252, sidAsciiLatin},
1819 {1253, sidGreek},
1820 {1254, sidAsciiLatin},
1821 {1255, sidHebrew},
1822 {1256, sidArabic},
1823 {1257, sidAsciiLatin},
1824 {1258, sidAsciiLatin},
1825 {CP_UNICODE, 0, E_FAIL}
1828 for (i = 0; i < sizeof(cp_sid)/sizeof(cp_sid[0]); i++)
1830 hr = IMLangFontLink2_CodePageToScriptID(font_link, cp_sid[i].cp, &sid);
1831 ok(hr == cp_sid[i].hr, "%u CodePageToScriptID failed 0x%08x %u\n", i, hr, GetLastError());
1832 if (SUCCEEDED(hr))
1834 ok(sid == cp_sid[i].sid,
1835 "%u got sid %u for codepage %u, expected %u\n", i, sid, cp_sid[i].cp, cp_sid[i].sid);
1840 static void test_GetFontUnicodeRanges(IMLangFontLink2 *font_link)
1842 HRESULT hr;
1843 UINT count;
1844 HFONT hfont, old_hfont;
1845 LOGFONTA lf;
1846 HDC hdc;
1847 UNICODERANGE *ur;
1849 hdc = CreateCompatibleDC(0);
1850 memset(&lf, 0, sizeof(lf));
1851 lstrcpyA(lf.lfFaceName, "Arial");
1852 hfont = CreateFontIndirectA(&lf);
1853 old_hfont = SelectObject(hdc, hfont);
1855 count = 0;
1856 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, NULL, &count, NULL);
1857 ok(hr == E_FAIL, "expected E_FAIL, got 0x%08x\n", hr);
1859 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, NULL, NULL);
1860 ok(hr == E_INVALIDARG, "expected E_FAIL, got 0x%08x\n", hr);
1862 count = 0;
1863 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, NULL);
1864 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1865 ok(count, "expected count > 0\n");
1867 ur = HeapAlloc(GetProcessHeap(), 0, sizeof(*ur) * count);
1869 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur);
1870 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1872 count--;
1873 hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur);
1874 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1876 HeapFree(GetProcessHeap(), 0, ur);
1878 SelectObject(hdc, old_hfont);
1879 DeleteObject(hfont);
1880 DeleteDC(hdc);
1883 static void test_IsCodePageInstallable(IMultiLanguage2 *ml2)
1885 UINT i;
1886 HRESULT hr;
1888 for (i = 0; i < 0xffff; i++)
1890 hr = IMultiLanguage2_IsCodePageInstallable(ml2, i);
1892 /* it would be better to use IMultiLanguage2_ValidateCodePageEx here but that brings
1893 * up an installation dialog on some platforms, even when specifying CPIOD_PEEK.
1895 if (IsValidCodePage(i))
1896 ok(hr == S_OK ||
1897 broken(hr == S_FALSE) || /* win2k */
1898 broken(hr == E_INVALIDARG), /* win2k */
1899 "code page %u is valid but not installable 0x%08x\n", i, hr);
1903 static void test_GetGlobalFontLinkObject(void)
1905 HRESULT ret;
1906 void *unknown;
1908 ret = GetGlobalFontLinkObject(NULL);
1909 ok(ret == E_INVALIDARG, "expected E_INVALIDARG got %#x\n", ret);
1911 unknown = (void *)0xdeadbeef;
1912 ret = GetGlobalFontLinkObject(&unknown);
1913 todo_wine {
1914 ok(ret == S_OK, "expected S_OK got %#x\n", ret);
1915 ok(unknown != NULL && unknown != (void *)0xdeadbeef,
1916 "GetGlobalFontLinkObject() returned %p\n", unknown);
1920 static void test_IMLangConvertCharset(IMultiLanguage *ml)
1922 IMLangConvertCharset *convert;
1923 WCHAR strW[] = {'a','b','c','d',0};
1924 UINT cp, src_size, dst_size;
1925 char strA[] = "abcd";
1926 WCHAR buffW[20];
1927 HRESULT hr;
1929 hr = IMultiLanguage_CreateConvertCharset(ml, CP_ACP, CP_UTF8, 0, &convert);
1930 todo_wine
1931 ok(hr == S_FALSE, "expected S_FALSE got 0x%08x\n", hr);
1933 hr = IMLangConvertCharset_GetSourceCodePage(convert, NULL);
1934 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1936 cp = CP_UTF8;
1937 hr = IMLangConvertCharset_GetSourceCodePage(convert, &cp);
1938 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
1939 ok(cp == CP_ACP, "got %d\n", cp);
1941 hr = IMLangConvertCharset_GetDestinationCodePage(convert, NULL);
1942 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1944 cp = CP_ACP;
1945 hr = IMLangConvertCharset_GetDestinationCodePage(convert, &cp);
1946 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
1947 ok(cp == CP_UTF8, "got %d\n", cp);
1949 /* DoConversionToUnicode */
1950 hr = IMLangConvertCharset_Initialize(convert, CP_UTF8, CP_UNICODE, 0);
1951 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
1953 hr = IMLangConvertCharset_DoConversionToUnicode(convert, NULL, NULL, NULL, NULL);
1954 ok(hr == E_FAIL || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1956 src_size = -1;
1957 dst_size = 20;
1958 buffW[0] = 0;
1959 buffW[4] = 4;
1960 hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size);
1961 ok(hr == S_OK, "got 0x%08x\n", hr);
1962 ok(!memcmp(buffW, strW, 4*sizeof(WCHAR)), "got converted string %s\n", wine_dbgstr_wn(buffW, dst_size));
1963 ok(dst_size == 4, "got %d\n", dst_size);
1964 ok(buffW[4] == 4, "got %d\n", buffW[4]);
1965 ok(src_size == 4, "got %d\n", src_size);
1967 src_size = -1;
1968 dst_size = 0;
1969 buffW[0] = 1;
1970 hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size);
1971 ok(hr == S_OK, "got 0x%08x\n", hr);
1972 ok(buffW[0] == 1, "got %d\n", buffW[0]);
1973 ok(dst_size == 4, "got %d\n", dst_size);
1974 ok(src_size == 4, "got %d\n", src_size);
1976 hr = IMLangConvertCharset_Initialize(convert, CP_UNICODE, CP_UNICODE, 0);
1977 ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
1979 IMLangConvertCharset_Release(convert);
1982 START_TEST(mlang)
1984 IMultiLanguage *iML = NULL;
1985 IMultiLanguage2 *iML2 = NULL;
1986 IMLangFontLink *iMLFL = NULL;
1987 IMLangFontLink2 *iMLFL2 = NULL;
1988 HRESULT ret;
1990 if (!init_function_ptrs())
1991 return;
1993 CoInitialize(NULL);
1994 test_Rfc1766ToLcid();
1995 test_LcidToRfc1766();
1997 test_ConvertINetUnicodeToMultiByte();
1998 test_JapaneseConversion();
2000 test_GetGlobalFontLinkObject();
2002 trace("IMultiLanguage\n");
2003 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2004 &IID_IMultiLanguage, (void **)&iML);
2005 if (ret != S_OK || !iML) return;
2007 test_GetNumberOfCodePageInfo((IMultiLanguage2 *)iML);
2008 test_IMLangConvertCharset(iML);
2009 IMultiLanguage_Release(iML);
2012 /* IMultiLanguage2 (IE5.0 and above) */
2013 trace("IMultiLanguage2\n");
2014 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2015 &IID_IMultiLanguage2, (void **)&iML2);
2016 if (ret != S_OK || !iML2) return;
2018 test_rfc1766(iML2);
2019 test_GetLcidFromRfc1766(iML2);
2020 test_GetRfc1766FromLcid(iML2);
2021 test_GetRfc1766Info(iML2);
2022 test_GetNumberOfCodePageInfo(iML2);
2024 test_EnumCodePages(iML2, 0);
2025 test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST);
2026 test_EnumCodePages(iML2, MIMECONTF_BROWSER);
2027 test_EnumCodePages(iML2, MIMECONTF_MINIMAL);
2028 test_EnumCodePages(iML2, MIMECONTF_VALID);
2029 /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
2030 /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
2032 test_EnumScripts(iML2, 0);
2033 test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER);
2034 test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM);
2036 ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE);
2037 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret);
2038 ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8);
2039 ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret);
2041 test_multibyte_to_unicode_translations(iML2);
2042 test_IMultiLanguage2_ConvertStringFromUnicode(iML2);
2044 test_IsCodePageInstallable(iML2);
2046 IMultiLanguage2_Release(iML2);
2049 /* IMLangFontLink */
2050 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2051 &IID_IMLangFontLink, (void **)&iMLFL);
2052 if (ret != S_OK || !iMLFL) return;
2054 IMLangFontLink_Test(iMLFL);
2055 IMLangFontLink_Release(iMLFL);
2057 /* IMLangFontLink2 */
2058 ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2059 &IID_IMLangFontLink2, (void **)&iMLFL2);
2060 if (ret != S_OK || !iMLFL2) return;
2062 test_GetScriptFontInfo(iMLFL2);
2063 test_GetFontUnicodeRanges(iMLFL2);
2064 test_CodePageToScriptID(iMLFL2);
2065 IMLangFontLink2_Release(iMLFL2);
2067 CoUninitialize();