2 * Unit test suite for MLANG APIs.
4 * Copyright 2004 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/test.h"
33 #define CP_UNICODE 1200
38 #define DUMP_SCRIPT_INFO
40 #if defined DUMP_CP_INFO || defined DUMP_SCRIPT_INFO
41 #include "wine/debug.h"
45 #define TRACE_2 OutputDebugStringA
47 static BOOL (WINAPI
*pGetCPInfoExA
)(UINT
,DWORD
,LPCPINFOEXA
);
49 static void test_multibyte_to_unicode_translations(IMultiLanguage2
*iML2
)
51 /* these APIs are broken regarding constness of the input buffer */
52 char stringA
[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
53 WCHAR stringW
[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
56 UINT lenA
, lenW
, expected_len
;
59 FARPROC pConvertINetMultiByteToUnicode
;
60 FARPROC pConvertINetUnicodeToMultiByte
;
62 hMlang
= LoadLibraryA("mlang.dll");
63 ok(hMlang
!= 0, "couldn't load mlang.dll\n");
65 pConvertINetMultiByteToUnicode
= GetProcAddress(hMlang
, "ConvertINetMultiByteToUnicode");
66 ok(pConvertINetMultiByteToUnicode
!= NULL
, "couldn't resolve ConvertINetMultiByteToUnicode\n");
67 pConvertINetUnicodeToMultiByte
= GetProcAddress(hMlang
, "ConvertINetUnicodeToMultiByte");
68 ok(pConvertINetUnicodeToMultiByte
!= NULL
, "couldn't resolve ConvertINetUnicodeToMultiByte\n");
70 /* IMultiLanguage2_ConvertStringToUnicode tests */
72 memset(bufW
, 'x', sizeof(bufW
));
74 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
75 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
76 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
77 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
78 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
79 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
81 memset(bufW
, 'x', sizeof(bufW
));
83 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
84 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
85 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
86 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
87 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
88 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
89 if (lenW
< sizeof(bufW
)/sizeof(bufW
[0])) {
90 /* can only happen if the convert call fails */
91 ok(bufW
[lenW
] != 0, "buf should not be 0 terminated\n");
92 bufW
[lenW
] = 0; /* -1 doesn't include 0 terminator */
94 ok(!lstrcmpW(bufW
, stringW
), "bufW/stringW mismatch\n");
96 memset(bufW
, 'x', sizeof(bufW
));
99 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
100 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
101 ok(ret
== E_FAIL
, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret
);
102 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
103 /* still has to do partial conversion */
104 ok(!memcmp(bufW
, stringW
, 5 * sizeof(WCHAR
)), "bufW/stringW mismatch\n");
106 memset(bufW
, 'x', sizeof(bufW
));
108 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
109 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
110 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, CP_UNICODE
, stringA
, &lenA
, bufW
, &lenW
);
111 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
112 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
113 ok(lenW
== lstrlenW(stringW
)/(int)sizeof(WCHAR
), "wrong lenW %u\n", lenW
);
114 ok(bufW
[lenW
] != 0, "buf should not be 0 terminated\n");
115 bufW
[lenW
] = 0; /* -1 doesn't include 0 terminator */
116 ok(!lstrcmpA((LPCSTR
)bufW
, stringA
), "bufW/stringA mismatch\n");
118 memset(bufW
, 'x', sizeof(bufW
));
119 lenA
= lstrlenA(stringA
);
121 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
122 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
123 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
124 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
125 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
127 memset(bufW
, 'x', sizeof(bufW
));
128 lenA
= lstrlenA(stringA
);
129 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
130 ret
= pConvertINetMultiByteToUnicode(NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
131 ok(ret
== S_OK
, "ConvertINetMultiByteToUnicode failed: %08x\n", ret
);
132 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
133 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
134 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
136 memset(bufW
, 'x', sizeof(bufW
));
137 lenA
= lstrlenA(stringA
);
139 ret
= pConvertINetMultiByteToUnicode(NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
140 ok(ret
== S_OK
, "ConvertINetMultiByteToUnicode failed: %08x\n", ret
);
141 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
142 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
143 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
145 /* IMultiLanguage2_ConvertStringFromUnicode tests */
147 memset(bufA
, 'x', sizeof(bufA
));
150 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
151 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
152 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
153 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
154 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
156 memset(bufA
, 'x', sizeof(bufA
));
159 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
160 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
161 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
162 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
163 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
164 ok(bufA
[lenA
] != 0, "buf should not be 0 terminated\n");
165 bufA
[lenA
] = 0; /* -1 doesn't include 0 terminator */
166 ok(!lstrcmpA(bufA
, stringA
), "bufA/stringA mismatch\n");
168 memset(bufA
, 'x', sizeof(bufA
));
171 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
172 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
173 ok(ret
== E_FAIL
, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret
);
174 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
175 /* still has to do partial conversion */
176 ok(!memcmp(bufA
, stringA
, 5), "bufW/stringW mismatch\n");
178 memset(bufA
, 'x', sizeof(bufA
));
181 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
182 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, CP_UNICODE
, stringW
, &lenW
, bufA
, &lenA
);
183 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
184 ok(lenA
== lstrlenA(stringA
) * (int)sizeof(WCHAR
), "wrong lenA %u\n", lenA
);
185 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
186 ok(bufA
[lenA
] != 0 && bufA
[lenA
+1] != 0, "buf should not be 0 terminated\n");
187 bufA
[lenA
] = 0; /* -1 doesn't include 0 terminator */
188 bufA
[lenA
+1] = 0; /* sizeof(WCHAR) */
189 ok(!lstrcmpW((LPCWSTR
)bufA
, stringW
), "bufA/stringW mismatch\n");
191 memset(bufA
, 'x', sizeof(bufA
));
192 lenW
= lstrlenW(stringW
);
194 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
195 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
196 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
197 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
198 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
200 memset(bufA
, 'x', sizeof(bufA
));
201 lenW
= lstrlenW(stringW
);
203 ret
= pConvertINetUnicodeToMultiByte(NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
204 ok(ret
== S_OK
, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret
);
205 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
206 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
207 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
209 memset(bufA
, 'x', sizeof(bufA
));
210 lenW
= lstrlenW(stringW
);
212 ret
= pConvertINetUnicodeToMultiByte(NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
213 ok(ret
== S_OK
, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret
);
214 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
215 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
216 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
219 static inline void cpinfo_cmp(MIMECPINFO
*cpinfo1
, MIMECPINFO
*cpinfo2
)
221 ok(cpinfo1
->dwFlags
== cpinfo2
->dwFlags
, "dwFlags mismatch: %08x != %08x\n", cpinfo1
->dwFlags
, cpinfo2
->dwFlags
);
222 ok(cpinfo1
->uiCodePage
== cpinfo2
->uiCodePage
, "uiCodePage mismatch: %u != %u\n", cpinfo1
->uiCodePage
, cpinfo2
->uiCodePage
);
223 ok(cpinfo1
->uiFamilyCodePage
== cpinfo2
->uiFamilyCodePage
, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1
->uiFamilyCodePage
, cpinfo2
->uiFamilyCodePage
);
224 ok(!lstrcmpW(cpinfo1
->wszDescription
, cpinfo2
->wszDescription
), "wszDescription mismatch\n");
225 ok(!lstrcmpW(cpinfo1
->wszWebCharset
, cpinfo2
->wszWebCharset
), "wszWebCharset mismatch\n");
226 ok(!lstrcmpW(cpinfo1
->wszHeaderCharset
, cpinfo2
->wszHeaderCharset
), "wszHeaderCharset mismatch\n");
227 ok(!lstrcmpW(cpinfo1
->wszBodyCharset
, cpinfo2
->wszBodyCharset
), "wszBodyCharset mismatch\n");
228 ok(!lstrcmpW(cpinfo1
->wszFixedWidthFont
, cpinfo2
->wszFixedWidthFont
), "wszFixedWidthFont mismatch\n");
229 ok(!lstrcmpW(cpinfo1
->wszProportionalFont
, cpinfo2
->wszProportionalFont
), "wszProportionalFont mismatch\n");
230 ok(cpinfo1
->bGDICharset
== cpinfo2
->bGDICharset
, "bGDICharset mismatch: %d != %d\n", cpinfo1
->bGDICharset
, cpinfo2
->bGDICharset
);
234 static const char *dump_mime_flags(DWORD flags
)
236 static char buf
[1024];
240 if (flags
& MIMECONTF_MAILNEWS
) strcat(buf
, " MIMECONTF_MAILNEWS");
241 if (flags
& MIMECONTF_BROWSER
) strcat(buf
, " MIMECONTF_BROWSER");
242 if (flags
& MIMECONTF_MINIMAL
) strcat(buf
, " MIMECONTF_MINIMAL");
243 if (flags
& MIMECONTF_IMPORT
) strcat(buf
, " MIMECONTF_IMPORT");
244 if (flags
& MIMECONTF_SAVABLE_MAILNEWS
) strcat(buf
, " MIMECONTF_SAVABLE_MAILNEWS");
245 if (flags
& MIMECONTF_SAVABLE_BROWSER
) strcat(buf
, " MIMECONTF_SAVABLE_BROWSER");
246 if (flags
& MIMECONTF_EXPORT
) strcat(buf
, " MIMECONTF_EXPORT");
247 if (flags
& MIMECONTF_PRIVCONVERTER
) strcat(buf
, " MIMECONTF_PRIVCONVERTER");
248 if (flags
& MIMECONTF_VALID
) strcat(buf
, " MIMECONTF_VALID");
249 if (flags
& MIMECONTF_VALID_NLS
) strcat(buf
, " MIMECONTF_VALID_NLS");
250 if (flags
& MIMECONTF_MIME_IE4
) strcat(buf
, " MIMECONTF_MIME_IE4");
251 if (flags
& MIMECONTF_MIME_LATEST
) strcat(buf
, " MIMECONTF_MIME_LATEST");
252 if (flags
& MIMECONTF_MIME_REGISTRY
) strcat(buf
, " MIMECONTF_MIME_REGISTRY");
258 static void test_EnumCodePages(IMultiLanguage2
*iML2
, DWORD flags
)
260 IEnumCodePage
*iEnumCP
= NULL
;
268 TRACE_2("Call IMultiLanguage2_GetNumberOfCodePageInfo\n");
269 ret
= IMultiLanguage2_GetNumberOfCodePageInfo(iML2
, &total
);
270 ok(ret
== S_OK
&& total
!= 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret
, total
);
272 trace("total mlang supported codepages %u\n", total
);
274 TRACE_2("Call IMultiLanguage2_EnumCodePages\n");
275 ret
= IMultiLanguage2_EnumCodePages(iML2
, flags
, LANG_NEUTRAL
, &iEnumCP
);
276 trace("IMultiLanguage2_EnumCodePages = %08x, iEnumCP = %p\n", ret
, iEnumCP
);
277 ok(ret
== S_OK
&& iEnumCP
, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret
, iEnumCP
);
279 TRACE_2("Call IEnumCodePage_Reset\n");
280 ret
= IEnumCodePage_Reset(iEnumCP
);
281 ok(ret
== S_OK
, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret
);
283 TRACE_2("Call IEnumCodePage_Next\n");
284 ret
= IEnumCodePage_Next(iEnumCP
, 0, NULL
, &n
);
285 ok(n
== 0 && ret
== S_FALSE
, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n
, ret
);
286 TRACE_2("Call IEnumCodePage_Next\n");
287 ret
= IEnumCodePage_Next(iEnumCP
, 0, NULL
, NULL
);
288 ok(ret
== S_FALSE
, "IEnumCodePage_Next: expected S_FALSE, got %08x\n", ret
);
290 cpinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo
) * total
* 2);
293 TRACE_2("Call IEnumCodePage_Next\n");
294 ret
= IEnumCodePage_Next(iEnumCP
, 0, cpinfo
, &n
);
295 trace("IEnumCodePage_Next = %08x, n = %u\n", ret
, n
);
296 ok(ret
== S_FALSE
&& n
== 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
299 TRACE_2("Call IEnumCodePage_Next\n");
300 ret
= IEnumCodePage_Next(iEnumCP
, n
, cpinfo
, &n
);
301 ok(ret
== S_OK
&& n
!= 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret
, n
);
303 trace("flags %08x, enumerated codepages %u\n", flags
, n
);
307 ok(n
== total
, "IEnumCodePage_Next: expected %u, got %u\n", total
, n
);
309 flags
= MIMECONTF_MIME_LATEST
;
314 for (i
= 0; i
< n
; i
++)
319 static const WCHAR autoW
[] = {'_','a','u','t','o',0};
322 trace("MIMECPINFO #%u:\n"
325 "uiFamilyCodePage %u\n"
326 "wszDescription %s\n"
328 "wszHeaderCharset %s\n"
329 "wszBodyCharset %s\n"
330 "wszFixedWidthFont %s\n"
331 "wszProportionalFont %s\n"
332 "bGDICharset %d\n\n",
334 cpinfo
[i
].dwFlags
, dump_mime_flags(cpinfo
[i
].dwFlags
),
335 cpinfo
[i
].uiCodePage
,
336 cpinfo
[i
].uiFamilyCodePage
,
337 wine_dbgstr_w(cpinfo
[i
].wszDescription
),
338 wine_dbgstr_w(cpinfo
[i
].wszWebCharset
),
339 wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
),
340 wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
),
341 wine_dbgstr_w(cpinfo
[i
].wszFixedWidthFont
),
342 wine_dbgstr_w(cpinfo
[i
].wszProportionalFont
),
343 cpinfo
[i
].bGDICharset
);
345 ok(cpinfo
[i
].dwFlags
& flags
, "enumerated flags %08x do not include requested %08x\n", cpinfo
[i
].dwFlags
, flags
);
347 if (TranslateCharsetInfo((DWORD
*)cpinfo
[i
].uiFamilyCodePage
, &csi
, TCI_SRCCODEPAGE
))
348 ok(cpinfo
[i
].bGDICharset
== csi
.ciCharset
, "%d != %d\n", cpinfo
[i
].bGDICharset
, csi
.ciCharset
);
350 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo
[i
].uiFamilyCodePage
);
354 if (pGetCPInfoExA(cpinfo
[i
].uiCodePage
, 0, &cpinfoex
))
355 trace("CodePage %u name: %s\n", cpinfo
[i
].uiCodePage
, cpinfoex
.CodePageName
);
357 trace("GetCPInfoExA failed for cp %u\n", cpinfo
[i
].uiCodePage
);
358 if (pGetCPInfoExA(cpinfo
[i
].uiFamilyCodePage
, 0, &cpinfoex
))
359 trace("CodePage %u name: %s\n", cpinfo
[i
].uiFamilyCodePage
, cpinfoex
.CodePageName
);
361 trace("GetCPInfoExA failed for cp %u\n", cpinfo
[i
].uiFamilyCodePage
);
364 /* Win95 does not support UTF-7 */
365 if (cpinfo
[i
].uiCodePage
== CP_UTF7
) continue;
367 /* support files for some codepages might be not installed, or
368 * the codepage is just an alias.
370 if (IsValidCodePage(cpinfo
[i
].uiCodePage
))
372 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
373 ret
= IMultiLanguage2_IsConvertible(iML2
, cpinfo
[i
].uiCodePage
, CP_UNICODE
);
374 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
375 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
376 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UNICODE
, cpinfo
[i
].uiCodePage
);
377 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
379 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
380 ret
= IMultiLanguage2_IsConvertible(iML2
, cpinfo
[i
].uiCodePage
, CP_UTF8
);
381 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
382 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
383 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UTF8
, cpinfo
[i
].uiCodePage
);
384 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
387 trace("IsValidCodePage failed for cp %u\n", cpinfo
[i
].uiCodePage
);
389 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszWebCharset
, &mcsi
);
390 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
391 if (memcmp(cpinfo
[i
].wszWebCharset
, autoW
, 5 * sizeof(WCHAR
)))
393 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
395 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszWebCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
397 ok(!lstrcmpiW(cpinfo
[i
].wszWebCharset
, mcsi
.wszCharset
),
400 wine_dbgstr_w(cpinfo
[i
].wszWebCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
402 "wszWebCharset mismatch");
407 /* native mlang returns completely messed up encodings in some cases */
408 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
409 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
410 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
411 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
415 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszHeaderCharset
, &mcsi
);
416 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
417 if (memcmp(cpinfo
[i
].wszHeaderCharset
, autoW
, 5 * sizeof(WCHAR
)))
419 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
421 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
423 ok(!lstrcmpiW(cpinfo
[i
].wszHeaderCharset
, mcsi
.wszCharset
),
426 wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
428 "wszHeaderCharset mismatch");
433 /* native mlang returns completely messed up encodings in some cases */
434 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
435 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
436 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
437 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
441 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszBodyCharset
, &mcsi
);
442 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
443 if (memcmp(cpinfo
[i
].wszBodyCharset
, autoW
, 5 * sizeof(WCHAR
)))
445 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
447 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
449 ok(!lstrcmpiW(cpinfo
[i
].wszBodyCharset
, mcsi
.wszCharset
),
452 wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
454 "wszBodyCharset mismatch");
459 /* native mlang returns completely messed up encodings in some cases */
460 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
461 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
462 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
463 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
470 /* now IEnumCodePage_Next should fail, since pointer is at the end */
472 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
473 ok(ret
== S_FALSE
&& n
== 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
475 ret
= IEnumCodePage_Reset(iEnumCP
);
476 ok(ret
== S_OK
, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret
);
478 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
479 ok(n
== 1 && ret
== S_OK
, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
480 cpinfo_cmp(&cpinfo
[0], &cpinfo2
);
484 /* Due to a bug in MS' implementation of IEnumCodePage_Skip
485 * it's not used here.
487 ret
= IEnumCodePage_Skip(iEnumCP
, 1);
488 ok(ret
== S_OK
, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret
);
490 for (i
= 0; i
< total
- 1; i
++)
493 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
494 ok(n
== 1 && ret
== S_OK
, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
495 cpinfo_cmp(&cpinfo
[i
+ 1], &cpinfo2
);
498 HeapFree(GetProcessHeap(), 0, cpinfo
);
499 IEnumCodePage_Release(iEnumCP
);
502 static inline void scriptinfo_cmp(SCRIPTINFO
*sinfo1
, SCRIPTINFO
*sinfo2
)
504 ok(sinfo1
->ScriptId
== sinfo2
->ScriptId
, "ScriptId mismatch: %d != %d\n", sinfo1
->ScriptId
, sinfo2
->ScriptId
);
505 ok(sinfo1
->uiCodePage
== sinfo2
->uiCodePage
, "uiCodePage mismatch: %u != %u\n", sinfo1
->uiCodePage
, sinfo2
->uiCodePage
);
506 ok(!lstrcmpW(sinfo1
->wszDescription
, sinfo2
->wszDescription
), "wszDescription mismatch\n");
507 ok(!lstrcmpW(sinfo1
->wszFixedWidthFont
, sinfo2
->wszFixedWidthFont
), "wszFixedWidthFont mismatch\n");
508 ok(!lstrcmpW(sinfo1
->wszProportionalFont
, sinfo2
->wszProportionalFont
), "wszProportionalFont mismatch\n");
511 static void test_EnumScripts(IMultiLanguage2
*iML2
, DWORD flags
)
513 IEnumScript
*iEnumScript
= NULL
;
521 TRACE_2("Call IMultiLanguage2_GetNumberOfScripts\n");
522 ret
= IMultiLanguage2_GetNumberOfScripts(iML2
, &total
);
523 ok(ret
== S_OK
&& total
!= 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret
, total
);
525 trace("total mlang supported scripts %u\n", total
);
527 TRACE_2("Call IMultiLanguage2_EnumScripts\n");
528 ret
= IMultiLanguage2_EnumScripts(iML2
, flags
, LANG_NEUTRAL
, &iEnumScript
);
529 trace("IMultiLanguage2_EnumScripts = %08x, iEnumScript = %p\n", ret
, iEnumScript
);
530 ok(ret
== S_OK
&& iEnumScript
, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret
, iEnumScript
);
532 TRACE_2("Call IEnumScript_Reset\n");
533 ret
= IEnumScript_Reset(iEnumScript
);
534 ok(ret
== S_OK
, "IEnumScript_Reset: expected S_OK, got %08x\n", ret
);
536 TRACE_2("Call IEnumScript_Next\n");
537 ret
= IEnumScript_Next(iEnumScript
, 0, NULL
, &n
);
538 ok(n
== 65536 && ret
== E_FAIL
, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n
, ret
);
539 TRACE_2("Call IEnumScript_Next\n");
540 ret
= IEnumScript_Next(iEnumScript
, 0, NULL
, NULL
);
541 ok(ret
== E_FAIL
, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret
);
543 sinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo
) * total
* 2);
546 TRACE_2("Call IEnumScript_Next\n");
547 ret
= IEnumScript_Next(iEnumScript
, 0, sinfo
, &n
);
548 ok(ret
== S_FALSE
&& n
== 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
551 TRACE_2("Call IEnumScript_Next\n");
552 ret
= IEnumScript_Next(iEnumScript
, n
, sinfo
, &n
);
553 ok(ret
== S_OK
&& n
!= 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret
, n
);
555 trace("flags %08x, enumerated scripts %u\n", flags
, n
);
559 ok(n
== total
, "IEnumScript_Next: expected %u, got %u\n", total
, n
);
560 flags
= SCRIPTCONTF_SCRIPT_USER
| SCRIPTCONTF_SCRIPT_HIDE
| SCRIPTCONTF_SCRIPT_SYSTEM
;
565 for (i
= 0; pGetCPInfoExA
&& i
< n
; i
++)
568 #ifdef DUMP_SCRIPT_INFO
569 trace("SCRIPTINFO #%u:\n"
572 "wszDescription %s\n"
573 "wszFixedWidthFont %s\n"
574 "wszProportionalFont %s\n\n",
578 wine_dbgstr_w(sinfo
[i
].wszDescription
),
579 wine_dbgstr_w(sinfo
[i
].wszFixedWidthFont
),
580 wine_dbgstr_w(sinfo
[i
].wszProportionalFont
));
582 if (pGetCPInfoExA(sinfo
[i
].uiCodePage
, 0, &cpinfoex
))
583 trace("CodePage %u name: %s\n", sinfo
[i
].uiCodePage
, cpinfoex
.CodePageName
);
585 trace("GetCPInfoExA failed for cp %u\n", sinfo
[i
].uiCodePage
);
590 /* now IEnumScript_Next should fail, since pointer is at the end */
592 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
593 ok(ret
== S_FALSE
&& n
== 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
595 ret
= IEnumScript_Reset(iEnumScript
);
596 ok(ret
== S_OK
, "IEnumScript_Reset: expected S_OK, got %08x\n", ret
);
598 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
599 ok(n
== 1 && ret
== S_OK
, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
600 scriptinfo_cmp(&sinfo
[0], &sinfo2
);
604 /* Due to a bug in MS' implementation of IEnumScript_Skip
605 * it's not used here.
607 ret
= IEnumScript_Skip(iEnumScript
, 1);
608 ok(ret
== S_OK
, "IEnumScript_Skip: expected S_OK, got %08x\n", ret
);
610 for (i
= 0; i
< total
- 1; i
++)
613 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
614 ok(n
== 1 && ret
== S_OK
, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
615 scriptinfo_cmp(&sinfo
[i
+ 1], &sinfo2
);
618 HeapFree(GetProcessHeap(), 0, sinfo
);
619 IEnumScript_Release(iEnumScript
);
622 static void IMLangFontLink_Test(IMLangFontLink
* iMLFL
)
624 DWORD dwCodePages
= 0;
625 DWORD dwManyCodePages
= 0;
628 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 932, &dwCodePages
)==S_OK
,
629 "IMLangFontLink_CodePageToCodePages failed\n");
630 ok (dwCodePages
!= 0, "No CodePages returned\n");
631 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwCodePages
, 1035,
633 "IMLangFontLink_CodePagesToCodePage failed\n");
634 ok(CodePage
== 932, "Incorrect CodePage Returned (%i)\n",CodePage
);
636 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 1252, &dwCodePages
)==S_OK
,
637 "IMLangFontLink_CodePageToCodePages failed\n");
638 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
639 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 1256, &dwCodePages
)==S_OK
,
640 "IMLangFontLink_CodePageToCodePages failed\n");
641 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
642 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 874, &dwCodePages
)==S_OK
,
643 "IMLangFontLink_CodePageToCodePages failed\n");
644 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
646 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwManyCodePages
, 1256,
648 "IMLangFontLink_CodePagesToCodePage failed\n");
649 ok(CodePage
== 1256, "Incorrect CodePage Returned (%i)\n",CodePage
);
651 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwManyCodePages
, 936,
653 "IMLangFontLink_CodePagesToCodePage failed\n");
654 ok(CodePage
== 1252, "Incorrect CodePage Returned (%i)\n",CodePage
);
657 static void test_rfc1766(IMultiLanguage2
*iML2
)
659 IEnumRfc1766
*pEnumRfc1766
;
664 ret
= IMultiLanguage2_EnumRfc1766(iML2
, LANG_NEUTRAL
, &pEnumRfc1766
);
665 ok(ret
== S_OK
, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret
);
669 ret
= IEnumRfc1766_Next(pEnumRfc1766
, 1, &info
, &n
);
670 if (ret
!= S_OK
) break;
673 trace("lcid %04x rfc_name %s locale_name %s\n",
674 info
.lcid
, wine_dbgstr_w(info
.wszRfc1766
), wine_dbgstr_w(info
.wszLocaleName
));
677 ok(n
== 1, "couldn't fetch 1 RFC1766INFO structure\n");
678 ok(IsValidLocale(info
.lcid
, LCID_SUPPORTED
), "invalid lcid %04x\n", info
.lcid
);
680 IEnumRfc1766_Release(pEnumRfc1766
);
683 static void test_GetLcidFromRfc1766(IMultiLanguage2
*iML2
)
688 static WCHAR e
[] = { 'e',0 };
689 static WCHAR en
[] = { 'e','n',0 };
690 static WCHAR empty
[] = { 0 };
691 static WCHAR dash
[] = { '-',0 };
692 static WCHAR e_dash
[] = { 'e','-',0 };
693 static WCHAR en_gb
[] = { 'e','n','-','g','b',0 };
694 static WCHAR en_us
[] = { 'e','n','-','u','s',0 };
695 static WCHAR en_them
[] = { 'e','n','-','t','h','e','m',0 };
696 static WCHAR english
[] = { 'e','n','g','l','i','s','h',0 };
698 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, NULL
, en
);
699 ok(ret
== E_INVALIDARG
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
701 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, NULL
);
702 ok(ret
== E_INVALIDARG
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
704 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, e
);
705 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
707 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, empty
);
708 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
710 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, dash
);
711 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
713 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, e_dash
);
714 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
716 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_them
);
717 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
719 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, english
);
720 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
724 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en
);
725 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
726 ok(lcid
== 9, "got wrong lcid: %04x\n", lcid
);
728 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_gb
);
729 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
730 ok(lcid
== 0x809, "got wrong lcid: %04x\n", lcid
);
732 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_us
);
733 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
734 ok(lcid
== 0x409, "got wrong lcid: %04x\n", lcid
);
739 IMultiLanguage2
*iML2
= NULL
;
740 IMLangFontLink
*iMLFL
= NULL
;
743 pGetCPInfoExA
= (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA");
746 TRACE_2("Call CoCreateInstance\n");
747 ret
= CoCreateInstance(&CLSID_CMultiLanguage
, NULL
, CLSCTX_INPROC_SERVER
,
748 &IID_IMultiLanguage2
, (void **)&iML2
);
750 trace("ret = %08x, MultiLanguage2 iML2 = %p\n", ret
, iML2
);
751 if (ret
!= S_OK
|| !iML2
) return;
754 test_GetLcidFromRfc1766(iML2
);
756 test_EnumCodePages(iML2
, 0);
757 test_EnumCodePages(iML2
, MIMECONTF_MIME_LATEST
);
758 test_EnumCodePages(iML2
, MIMECONTF_BROWSER
);
759 test_EnumCodePages(iML2
, MIMECONTF_MINIMAL
);
760 test_EnumCodePages(iML2
, MIMECONTF_VALID
);
761 /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
762 /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
764 test_EnumScripts(iML2
, 0);
765 test_EnumScripts(iML2
, SCRIPTCONTF_SCRIPT_USER
);
766 test_EnumScripts(iML2
, SCRIPTCONTF_SCRIPT_USER
| SCRIPTCONTF_SCRIPT_HIDE
| SCRIPTCONTF_SCRIPT_SYSTEM
);
768 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
769 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UTF8
, CP_UNICODE
);
770 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret
);
771 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
772 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UNICODE
, CP_UTF8
);
773 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret
);
775 test_multibyte_to_unicode_translations(iML2
);
777 IMultiLanguage2_Release(iML2
);
779 ret
= CoCreateInstance(&CLSID_CMultiLanguage
, NULL
, CLSCTX_INPROC_SERVER
,
780 &IID_IMLangFontLink
, (void **)&iMLFL
);
782 trace("ret = %08x, IMLangFontLink iMLFL = %p\n", ret
, iMLFL
);
783 if (ret
!= S_OK
|| !iML2
) return;
785 IMLangFontLink_Test(iMLFL
);
786 IMLangFontLink_Release(iMLFL
);