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 CHAR string1
[MAX_PATH
], string2
[MAX_PATH
];
49 #define ok_w2(format, szString1, szString2) \
51 if (lstrcmpW(szString1, szString2) != 0) \
53 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
54 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
55 ok(0, format, string1, string2); \
58 static BOOL (WINAPI
*pGetCPInfoExA
)(UINT
,DWORD
,LPCPINFOEXA
);
60 static void test_multibyte_to_unicode_translations(IMultiLanguage2
*iML2
)
62 /* these APIs are broken regarding constness of the input buffer */
63 char stringA
[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
64 WCHAR stringW
[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
67 UINT lenA
, lenW
, expected_len
;
70 FARPROC pConvertINetMultiByteToUnicode
;
71 FARPROC pConvertINetUnicodeToMultiByte
;
73 hMlang
= LoadLibraryA("mlang.dll");
74 ok(hMlang
!= 0, "couldn't load mlang.dll\n");
76 pConvertINetMultiByteToUnicode
= GetProcAddress(hMlang
, "ConvertINetMultiByteToUnicode");
77 ok(pConvertINetMultiByteToUnicode
!= NULL
, "couldn't resolve ConvertINetMultiByteToUnicode\n");
78 pConvertINetUnicodeToMultiByte
= GetProcAddress(hMlang
, "ConvertINetUnicodeToMultiByte");
79 ok(pConvertINetUnicodeToMultiByte
!= NULL
, "couldn't resolve ConvertINetUnicodeToMultiByte\n");
81 /* IMultiLanguage2_ConvertStringToUnicode tests */
83 memset(bufW
, 'x', sizeof(bufW
));
85 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
86 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
87 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
88 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
89 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
90 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
92 memset(bufW
, 'x', sizeof(bufW
));
94 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
95 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
96 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
97 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
98 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
99 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
100 if (lenW
< sizeof(bufW
)/sizeof(bufW
[0])) {
101 /* can only happen if the convert call fails */
102 ok(bufW
[lenW
] != 0, "buf should not be 0 terminated\n");
103 bufW
[lenW
] = 0; /* -1 doesn't include 0 terminator */
105 ok(!lstrcmpW(bufW
, stringW
), "bufW/stringW mismatch\n");
107 memset(bufW
, 'x', sizeof(bufW
));
110 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
111 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, bufW
, &lenW
);
112 ok(ret
== E_FAIL
, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret
);
113 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
114 /* still has to do partial conversion */
115 ok(!memcmp(bufW
, stringW
, 5 * sizeof(WCHAR
)), "bufW/stringW mismatch\n");
117 memset(bufW
, 'x', sizeof(bufW
));
119 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
120 TRACE_2("Call IMultiLanguage2_ConvertStringToUnicode\n");
121 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, CP_UNICODE
, stringA
, &lenA
, bufW
, &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 ok(lenW
== lstrlenW(stringW
)/(int)sizeof(WCHAR
), "wrong lenW %u\n", lenW
);
125 ok(bufW
[lenW
] != 0, "buf should not be 0 terminated\n");
126 bufW
[lenW
] = 0; /* -1 doesn't include 0 terminator */
127 ok(!lstrcmpA((LPCSTR
)bufW
, stringA
), "bufW/stringA mismatch\n");
129 memset(bufW
, 'x', sizeof(bufW
));
130 lenA
= lstrlenA(stringA
);
132 ret
= IMultiLanguage2_ConvertStringToUnicode(iML2
, NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
133 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret
);
134 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
135 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
136 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
138 memset(bufW
, 'x', sizeof(bufW
));
139 lenA
= lstrlenA(stringA
);
140 lenW
= sizeof(bufW
)/sizeof(bufW
[0]);
141 ret
= pConvertINetMultiByteToUnicode(NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
142 ok(ret
== S_OK
, "ConvertINetMultiByteToUnicode failed: %08x\n", ret
);
143 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
144 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
145 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
147 memset(bufW
, 'x', sizeof(bufW
));
148 lenA
= lstrlenA(stringA
);
150 ret
= pConvertINetMultiByteToUnicode(NULL
, 1252, stringA
, &lenA
, NULL
, &lenW
);
151 ok(ret
== S_OK
, "ConvertINetMultiByteToUnicode failed: %08x\n", ret
);
152 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
153 expected_len
= MultiByteToWideChar(1252, 0, stringA
, lenA
, NULL
, 0);
154 ok(lenW
== expected_len
, "expected lenW %u, got %u\n", expected_len
, lenW
);
156 /* IMultiLanguage2_ConvertStringFromUnicode tests */
158 memset(bufA
, 'x', sizeof(bufA
));
161 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
162 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
163 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
164 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
165 ok(lenW
== 0, "expected lenW 0, got %u\n", lenW
);
167 memset(bufA
, 'x', sizeof(bufA
));
170 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
171 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
172 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
173 ok(lenA
== lstrlenA(stringA
), "expected lenA %u, got %u\n", lstrlenA(stringA
), lenA
);
174 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
175 ok(bufA
[lenA
] != 0, "buf should not be 0 terminated\n");
176 bufA
[lenA
] = 0; /* -1 doesn't include 0 terminator */
177 ok(!lstrcmpA(bufA
, stringA
), "bufA/stringA mismatch\n");
179 memset(bufA
, 'x', sizeof(bufA
));
182 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
183 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, bufA
, &lenA
);
184 ok(ret
== E_FAIL
, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret
);
185 ok(lenA
== 0, "expected lenA 0, got %u\n", lenA
);
186 /* still has to do partial conversion */
187 ok(!memcmp(bufA
, stringA
, 5), "bufW/stringW mismatch\n");
189 memset(bufA
, 'x', sizeof(bufA
));
192 TRACE_2("Call IMultiLanguage2_ConvertStringFromUnicode\n");
193 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, CP_UNICODE
, stringW
, &lenW
, bufA
, &lenA
);
194 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
195 ok(lenA
== lstrlenA(stringA
) * (int)sizeof(WCHAR
), "wrong lenA %u\n", lenA
);
196 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
197 ok(bufA
[lenA
] != 0 && bufA
[lenA
+1] != 0, "buf should not be 0 terminated\n");
198 bufA
[lenA
] = 0; /* -1 doesn't include 0 terminator */
199 bufA
[lenA
+1] = 0; /* sizeof(WCHAR) */
200 ok(!lstrcmpW((LPCWSTR
)bufA
, stringW
), "bufA/stringW mismatch\n");
202 memset(bufA
, 'x', sizeof(bufA
));
203 lenW
= lstrlenW(stringW
);
205 ret
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
206 ok(ret
== S_OK
, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret
);
207 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
208 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
209 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
211 memset(bufA
, 'x', sizeof(bufA
));
212 lenW
= lstrlenW(stringW
);
214 ret
= pConvertINetUnicodeToMultiByte(NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
215 ok(ret
== S_OK
, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret
);
216 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
217 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
218 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
220 memset(bufA
, 'x', sizeof(bufA
));
221 lenW
= lstrlenW(stringW
);
223 ret
= pConvertINetUnicodeToMultiByte(NULL
, 1252, stringW
, &lenW
, NULL
, &lenA
);
224 ok(ret
== S_OK
, "ConvertINetUnicodeToMultiByte failed: %08x\n", ret
);
225 ok(lenW
== lstrlenW(stringW
), "expected lenW %u, got %u\n", lstrlenW(stringW
), lenW
);
226 expected_len
= WideCharToMultiByte(1252, 0, stringW
, lenW
, NULL
, 0, NULL
, NULL
);
227 ok(lenA
== expected_len
, "expected lenA %u, got %u\n", expected_len
, lenA
);
230 static inline void cpinfo_cmp(MIMECPINFO
*cpinfo1
, MIMECPINFO
*cpinfo2
)
232 ok(cpinfo1
->dwFlags
== cpinfo2
->dwFlags
, "dwFlags mismatch: %08x != %08x\n", cpinfo1
->dwFlags
, cpinfo2
->dwFlags
);
233 ok(cpinfo1
->uiCodePage
== cpinfo2
->uiCodePage
, "uiCodePage mismatch: %u != %u\n", cpinfo1
->uiCodePage
, cpinfo2
->uiCodePage
);
234 ok(cpinfo1
->uiFamilyCodePage
== cpinfo2
->uiFamilyCodePage
, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1
->uiFamilyCodePage
, cpinfo2
->uiFamilyCodePage
);
235 ok(!lstrcmpW(cpinfo1
->wszDescription
, cpinfo2
->wszDescription
), "wszDescription mismatch\n");
236 ok(!lstrcmpW(cpinfo1
->wszWebCharset
, cpinfo2
->wszWebCharset
), "wszWebCharset mismatch\n");
237 ok(!lstrcmpW(cpinfo1
->wszHeaderCharset
, cpinfo2
->wszHeaderCharset
), "wszHeaderCharset mismatch\n");
238 ok(!lstrcmpW(cpinfo1
->wszBodyCharset
, cpinfo2
->wszBodyCharset
), "wszBodyCharset mismatch\n");
239 ok(!lstrcmpW(cpinfo1
->wszFixedWidthFont
, cpinfo2
->wszFixedWidthFont
), "wszFixedWidthFont mismatch\n");
240 ok(!lstrcmpW(cpinfo1
->wszProportionalFont
, cpinfo2
->wszProportionalFont
), "wszProportionalFont mismatch\n");
241 ok(cpinfo1
->bGDICharset
== cpinfo2
->bGDICharset
, "bGDICharset mismatch: %d != %d\n", cpinfo1
->bGDICharset
, cpinfo2
->bGDICharset
);
245 static const char *dump_mime_flags(DWORD flags
)
247 static char buf
[1024];
251 if (flags
& MIMECONTF_MAILNEWS
) strcat(buf
, " MIMECONTF_MAILNEWS");
252 if (flags
& MIMECONTF_BROWSER
) strcat(buf
, " MIMECONTF_BROWSER");
253 if (flags
& MIMECONTF_MINIMAL
) strcat(buf
, " MIMECONTF_MINIMAL");
254 if (flags
& MIMECONTF_IMPORT
) strcat(buf
, " MIMECONTF_IMPORT");
255 if (flags
& MIMECONTF_SAVABLE_MAILNEWS
) strcat(buf
, " MIMECONTF_SAVABLE_MAILNEWS");
256 if (flags
& MIMECONTF_SAVABLE_BROWSER
) strcat(buf
, " MIMECONTF_SAVABLE_BROWSER");
257 if (flags
& MIMECONTF_EXPORT
) strcat(buf
, " MIMECONTF_EXPORT");
258 if (flags
& MIMECONTF_PRIVCONVERTER
) strcat(buf
, " MIMECONTF_PRIVCONVERTER");
259 if (flags
& MIMECONTF_VALID
) strcat(buf
, " MIMECONTF_VALID");
260 if (flags
& MIMECONTF_VALID_NLS
) strcat(buf
, " MIMECONTF_VALID_NLS");
261 if (flags
& MIMECONTF_MIME_IE4
) strcat(buf
, " MIMECONTF_MIME_IE4");
262 if (flags
& MIMECONTF_MIME_LATEST
) strcat(buf
, " MIMECONTF_MIME_LATEST");
263 if (flags
& MIMECONTF_MIME_REGISTRY
) strcat(buf
, " MIMECONTF_MIME_REGISTRY");
269 static BOOL
check_convertible(IMultiLanguage2
*iML2
, UINT from
, UINT to
)
271 CHAR convert
[MAX_PATH
];
276 static WCHAR strW
[] = {'a','b','c',0};
280 hr
= IMultiLanguage2_ConvertStringFromUnicode(iML2
, NULL
, from
, strW
,
281 &srcsz
, convert
, &destsz
);
287 hr
= IMultiLanguage2_ConvertString(iML2
, NULL
, from
, to
, (BYTE
*)convert
,
288 &srcsz
, dest
, &destsz
);
295 static void test_EnumCodePages(IMultiLanguage2
*iML2
, DWORD flags
)
297 IEnumCodePage
*iEnumCP
= NULL
;
305 TRACE_2("Call IMultiLanguage2_GetNumberOfCodePageInfo\n");
306 ret
= IMultiLanguage2_GetNumberOfCodePageInfo(iML2
, &total
);
307 ok(ret
== S_OK
&& total
!= 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret
, total
);
309 trace("total mlang supported codepages %u\n", total
);
311 TRACE_2("Call IMultiLanguage2_EnumCodePages\n");
312 ret
= IMultiLanguage2_EnumCodePages(iML2
, flags
, LANG_NEUTRAL
, &iEnumCP
);
313 trace("IMultiLanguage2_EnumCodePages = %08x, iEnumCP = %p\n", ret
, iEnumCP
);
314 ok(ret
== S_OK
&& iEnumCP
, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret
, iEnumCP
);
316 TRACE_2("Call IEnumCodePage_Reset\n");
317 ret
= IEnumCodePage_Reset(iEnumCP
);
318 ok(ret
== S_OK
, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret
);
320 TRACE_2("Call IEnumCodePage_Next\n");
321 ret
= IEnumCodePage_Next(iEnumCP
, 0, NULL
, &n
);
322 ok(n
== 0 && ret
== S_FALSE
, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n
, ret
);
323 TRACE_2("Call IEnumCodePage_Next\n");
324 ret
= IEnumCodePage_Next(iEnumCP
, 0, NULL
, NULL
);
325 ok(ret
== S_FALSE
, "IEnumCodePage_Next: expected S_FALSE, got %08x\n", ret
);
327 cpinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo
) * total
* 2);
330 TRACE_2("Call IEnumCodePage_Next\n");
331 ret
= IEnumCodePage_Next(iEnumCP
, 0, cpinfo
, &n
);
332 trace("IEnumCodePage_Next = %08x, n = %u\n", ret
, n
);
333 ok(ret
== S_FALSE
&& n
== 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
336 TRACE_2("Call IEnumCodePage_Next\n");
337 ret
= IEnumCodePage_Next(iEnumCP
, n
, cpinfo
, &n
);
338 ok(ret
== S_OK
&& n
!= 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret
, n
);
340 trace("flags %08x, enumerated codepages %u\n", flags
, n
);
344 ok(n
== total
, "IEnumCodePage_Next: expected %u, got %u\n", total
, n
);
346 flags
= MIMECONTF_MIME_LATEST
;
351 for (i
= 0; i
< n
; i
++)
356 HRESULT check
= S_OK
;
357 static const WCHAR autoW
[] = {'_','a','u','t','o',0};
360 trace("MIMECPINFO #%u:\n"
363 "uiFamilyCodePage %u\n"
364 "wszDescription %s\n"
366 "wszHeaderCharset %s\n"
367 "wszBodyCharset %s\n"
368 "wszFixedWidthFont %s\n"
369 "wszProportionalFont %s\n"
370 "bGDICharset %d\n\n",
372 cpinfo
[i
].dwFlags
, dump_mime_flags(cpinfo
[i
].dwFlags
),
373 cpinfo
[i
].uiCodePage
,
374 cpinfo
[i
].uiFamilyCodePage
,
375 wine_dbgstr_w(cpinfo
[i
].wszDescription
),
376 wine_dbgstr_w(cpinfo
[i
].wszWebCharset
),
377 wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
),
378 wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
),
379 wine_dbgstr_w(cpinfo
[i
].wszFixedWidthFont
),
380 wine_dbgstr_w(cpinfo
[i
].wszProportionalFont
),
381 cpinfo
[i
].bGDICharset
);
383 ok(cpinfo
[i
].dwFlags
& flags
, "enumerated flags %08x do not include requested %08x\n", cpinfo
[i
].dwFlags
, flags
);
385 if (TranslateCharsetInfo((DWORD
*)cpinfo
[i
].uiFamilyCodePage
, &csi
, TCI_SRCCODEPAGE
))
386 ok(cpinfo
[i
].bGDICharset
== csi
.ciCharset
, "%d != %d\n", cpinfo
[i
].bGDICharset
, csi
.ciCharset
);
388 trace("TranslateCharsetInfo failed for cp %u\n", cpinfo
[i
].uiFamilyCodePage
);
390 trace("%u: codepage %u family %u\n", i
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
392 /* Win95 does not support UTF-7 */
393 if (cpinfo
[i
].uiCodePage
== CP_UTF7
) continue;
395 /* support files for some codepages might be not installed, or
396 * the codepage is just an alias.
398 if (IsValidCodePage(cpinfo
[i
].uiCodePage
))
400 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
401 ret
= IMultiLanguage2_IsConvertible(iML2
, cpinfo
[i
].uiCodePage
, CP_UNICODE
);
402 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
403 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
404 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UNICODE
, cpinfo
[i
].uiCodePage
);
405 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
407 convertible
= check_convertible(iML2
, cpinfo
[i
].uiCodePage
, CP_UTF8
);
411 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
412 ret
= IMultiLanguage2_IsConvertible(iML2
, cpinfo
[i
].uiCodePage
, CP_UTF8
);
413 ok(ret
== check
, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
414 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
415 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UTF8
, cpinfo
[i
].uiCodePage
);
416 ok(ret
== check
, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo
[i
].uiCodePage
, ret
);
419 trace("IsValidCodePage failed for cp %u\n", cpinfo
[i
].uiCodePage
);
421 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszWebCharset
, &mcsi
);
422 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
423 if (memcmp(cpinfo
[i
].wszWebCharset
, autoW
, 5 * sizeof(WCHAR
)))
425 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
427 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszWebCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
429 ok(!lstrcmpiW(cpinfo
[i
].wszWebCharset
, mcsi
.wszCharset
),
432 wine_dbgstr_w(cpinfo
[i
].wszWebCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
434 "wszWebCharset mismatch\n");
439 /* native mlang returns completely messed up encodings in some cases */
440 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
441 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
442 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
443 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
447 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszHeaderCharset
, &mcsi
);
448 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
449 if (memcmp(cpinfo
[i
].wszHeaderCharset
, autoW
, 5 * sizeof(WCHAR
)))
451 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
453 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
455 ok(!lstrcmpiW(cpinfo
[i
].wszHeaderCharset
, mcsi
.wszCharset
),
458 wine_dbgstr_w(cpinfo
[i
].wszHeaderCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
460 "wszHeaderCharset mismatch\n");
465 /* native mlang returns completely messed up encodings in some cases */
466 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
467 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
468 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
469 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
473 ret
= IMultiLanguage2_GetCharsetInfo(iML2
, cpinfo
[i
].wszBodyCharset
, &mcsi
);
474 /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
475 if (memcmp(cpinfo
[i
].wszBodyCharset
, autoW
, 5 * sizeof(WCHAR
)))
477 ok (ret
== S_OK
, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret
);
479 trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
), mcsi
.uiCodePage
, mcsi
.uiInternetEncoding
, wine_dbgstr_w(mcsi
.wszCharset
));
481 ok(!lstrcmpiW(cpinfo
[i
].wszBodyCharset
, mcsi
.wszCharset
),
484 wine_dbgstr_w(cpinfo
[i
].wszBodyCharset
), wine_dbgstr_w(mcsi
.wszCharset
));
486 "wszBodyCharset mismatch\n");
491 /* native mlang returns completely messed up encodings in some cases */
492 ok(mcsi
.uiInternetEncoding
== cpinfo
[i
].uiCodePage
|| mcsi
.uiInternetEncoding
== cpinfo
[i
].uiFamilyCodePage
,
493 "%u != %u || %u\n", mcsi
.uiInternetEncoding
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
494 ok(mcsi
.uiCodePage
== cpinfo
[i
].uiCodePage
|| mcsi
.uiCodePage
== cpinfo
[i
].uiFamilyCodePage
,
495 "%u != %u || %u\n", mcsi
.uiCodePage
, cpinfo
[i
].uiCodePage
, cpinfo
[i
].uiFamilyCodePage
);
500 /* now IEnumCodePage_Next should fail, since pointer is at the end */
502 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
503 ok(ret
== S_FALSE
&& n
== 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
505 ret
= IEnumCodePage_Reset(iEnumCP
);
506 ok(ret
== S_OK
, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret
);
508 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
509 ok(n
== 1 && ret
== S_OK
, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
510 cpinfo_cmp(&cpinfo
[0], &cpinfo2
);
514 /* Due to a bug in MS' implementation of IEnumCodePage_Skip
515 * it's not used here.
517 ret
= IEnumCodePage_Skip(iEnumCP
, 1);
518 ok(ret
== S_OK
, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret
);
520 for (i
= 0; i
< total
- 1; i
++)
523 ret
= IEnumCodePage_Next(iEnumCP
, 1, &cpinfo2
, &n
);
524 ok(n
== 1 && ret
== S_OK
, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
525 cpinfo_cmp(&cpinfo
[i
+ 1], &cpinfo2
);
528 HeapFree(GetProcessHeap(), 0, cpinfo
);
529 IEnumCodePage_Release(iEnumCP
);
532 static inline void scriptinfo_cmp(SCRIPTINFO
*sinfo1
, SCRIPTINFO
*sinfo2
)
534 ok(sinfo1
->ScriptId
== sinfo2
->ScriptId
, "ScriptId mismatch: %d != %d\n", sinfo1
->ScriptId
, sinfo2
->ScriptId
);
535 ok(sinfo1
->uiCodePage
== sinfo2
->uiCodePage
, "uiCodePage mismatch: %u != %u\n", sinfo1
->uiCodePage
, sinfo2
->uiCodePage
);
536 ok(!lstrcmpW(sinfo1
->wszDescription
, sinfo2
->wszDescription
), "wszDescription mismatch\n");
537 ok(!lstrcmpW(sinfo1
->wszFixedWidthFont
, sinfo2
->wszFixedWidthFont
), "wszFixedWidthFont mismatch\n");
538 ok(!lstrcmpW(sinfo1
->wszProportionalFont
, sinfo2
->wszProportionalFont
), "wszProportionalFont mismatch\n");
541 static void test_EnumScripts(IMultiLanguage2
*iML2
, DWORD flags
)
543 IEnumScript
*iEnumScript
= NULL
;
551 TRACE_2("Call IMultiLanguage2_GetNumberOfScripts\n");
552 ret
= IMultiLanguage2_GetNumberOfScripts(iML2
, &total
);
553 ok(ret
== S_OK
&& total
!= 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret
, total
);
555 trace("total mlang supported scripts %u\n", total
);
557 TRACE_2("Call IMultiLanguage2_EnumScripts\n");
558 ret
= IMultiLanguage2_EnumScripts(iML2
, flags
, LANG_NEUTRAL
, &iEnumScript
);
559 trace("IMultiLanguage2_EnumScripts = %08x, iEnumScript = %p\n", ret
, iEnumScript
);
560 ok(ret
== S_OK
&& iEnumScript
, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret
, iEnumScript
);
562 TRACE_2("Call IEnumScript_Reset\n");
563 ret
= IEnumScript_Reset(iEnumScript
);
564 ok(ret
== S_OK
, "IEnumScript_Reset: expected S_OK, got %08x\n", ret
);
566 TRACE_2("Call IEnumScript_Next\n");
567 ret
= IEnumScript_Next(iEnumScript
, 0, NULL
, &n
);
568 ok(n
== 65536 && ret
== E_FAIL
, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n
, ret
);
569 TRACE_2("Call IEnumScript_Next\n");
570 ret
= IEnumScript_Next(iEnumScript
, 0, NULL
, NULL
);
571 ok(ret
== E_FAIL
, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret
);
573 sinfo
= HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo
) * total
* 2);
576 TRACE_2("Call IEnumScript_Next\n");
577 ret
= IEnumScript_Next(iEnumScript
, 0, sinfo
, &n
);
578 ok(ret
== S_FALSE
&& n
== 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
581 TRACE_2("Call IEnumScript_Next\n");
582 ret
= IEnumScript_Next(iEnumScript
, n
, sinfo
, &n
);
583 ok(ret
== S_OK
&& n
!= 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret
, n
);
585 trace("flags %08x, enumerated scripts %u\n", flags
, n
);
589 ok(n
== total
, "IEnumScript_Next: expected %u, got %u\n", total
, n
);
590 flags
= SCRIPTCONTF_SCRIPT_USER
| SCRIPTCONTF_SCRIPT_HIDE
| SCRIPTCONTF_SCRIPT_SYSTEM
;
595 for (i
= 0; pGetCPInfoExA
&& i
< n
; i
++)
597 #ifdef DUMP_SCRIPT_INFO
598 trace("SCRIPTINFO #%u:\n"
601 "wszDescription %s\n"
602 "wszFixedWidthFont %s\n"
603 "wszProportionalFont %s\n\n",
607 wine_dbgstr_w(sinfo
[i
].wszDescription
),
608 wine_dbgstr_w(sinfo
[i
].wszFixedWidthFont
),
609 wine_dbgstr_w(sinfo
[i
].wszProportionalFont
));
611 trace("%u codepage %u\n", i
, sinfo
[i
].uiCodePage
);
614 /* now IEnumScript_Next should fail, since pointer is at the end */
616 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
617 ok(ret
== S_FALSE
&& n
== 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret
, n
);
619 ret
= IEnumScript_Reset(iEnumScript
);
620 ok(ret
== S_OK
, "IEnumScript_Reset: expected S_OK, got %08x\n", ret
);
622 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
623 ok(n
== 1 && ret
== S_OK
, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
624 scriptinfo_cmp(&sinfo
[0], &sinfo2
);
628 /* Due to a bug in MS' implementation of IEnumScript_Skip
629 * it's not used here.
631 ret
= IEnumScript_Skip(iEnumScript
, 1);
632 ok(ret
== S_OK
, "IEnumScript_Skip: expected S_OK, got %08x\n", ret
);
634 for (i
= 0; i
< total
- 1; i
++)
637 ret
= IEnumScript_Next(iEnumScript
, 1, &sinfo2
, &n
);
638 ok(n
== 1 && ret
== S_OK
, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n
, ret
);
639 scriptinfo_cmp(&sinfo
[i
+ 1], &sinfo2
);
642 HeapFree(GetProcessHeap(), 0, sinfo
);
643 IEnumScript_Release(iEnumScript
);
646 static void IMLangFontLink_Test(IMLangFontLink
* iMLFL
)
648 DWORD dwCodePages
= 0;
649 DWORD dwManyCodePages
= 0;
652 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 932, &dwCodePages
)==S_OK
,
653 "IMLangFontLink_CodePageToCodePages failed\n");
654 ok (dwCodePages
!= 0, "No CodePages returned\n");
655 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwCodePages
, 1035,
657 "IMLangFontLink_CodePagesToCodePage failed\n");
658 ok(CodePage
== 932, "Incorrect CodePage Returned (%i)\n",CodePage
);
660 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 1252, &dwCodePages
)==S_OK
,
661 "IMLangFontLink_CodePageToCodePages failed\n");
662 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
663 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 1256, &dwCodePages
)==S_OK
,
664 "IMLangFontLink_CodePageToCodePages failed\n");
665 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
666 ok(IMLangFontLink_CodePageToCodePages(iMLFL
, 874, &dwCodePages
)==S_OK
,
667 "IMLangFontLink_CodePageToCodePages failed\n");
668 dwManyCodePages
= dwManyCodePages
| dwCodePages
;
670 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwManyCodePages
, 1256,
672 "IMLangFontLink_CodePagesToCodePage failed\n");
673 ok(CodePage
== 1256, "Incorrect CodePage Returned (%i)\n",CodePage
);
675 ok(IMLangFontLink_CodePagesToCodePage(iMLFL
, dwManyCodePages
, 936,
677 "IMLangFontLink_CodePagesToCodePage failed\n");
678 ok(CodePage
== 1252, "Incorrect CodePage Returned (%i)\n",CodePage
);
681 /* copied from libs/wine/string.c */
682 WCHAR
*strstrW(const WCHAR
*str
, const WCHAR
*sub
)
686 const WCHAR
*p1
= str
, *p2
= sub
;
687 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
688 if (!*p2
) return (WCHAR
*)str
;
694 static void test_rfc1766(IMultiLanguage2
*iML2
)
696 IEnumRfc1766
*pEnumRfc1766
;
702 ret
= IMultiLanguage2_EnumRfc1766(iML2
, LANG_NEUTRAL
, &pEnumRfc1766
);
703 ok(ret
== S_OK
, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret
);
707 ret
= IEnumRfc1766_Next(pEnumRfc1766
, 1, &info
, &n
);
708 if (ret
!= S_OK
) break;
711 trace("lcid %04x rfc_name %s locale_name %s\n",
712 info
.lcid
, wine_dbgstr_w(info
.wszRfc1766
), wine_dbgstr_w(info
.wszLocaleName
));
715 ok(n
== 1, "couldn't fetch 1 RFC1766INFO structure\n");
717 /* verify the Rfc1766 value */
718 ret
= IMultiLanguage2_GetRfc1766FromLcid(iML2
, info
.lcid
, &rfcstr
);
719 ok(ret
== S_OK
, "Expected S_OK, got %08x\n", ret
);
721 /* not an exact 1:1 correspondence between lcid and rfc1766 in the
722 * mlang database, e.g., nb-no -> 1044 -> no */
723 ok(strstrW(info
.wszRfc1766
, rfcstr
) != NULL
,
724 "Expected matching locale names\n");
726 SysFreeString(rfcstr
);
728 IEnumRfc1766_Release(pEnumRfc1766
);
731 static void test_GetLcidFromRfc1766(IMultiLanguage2
*iML2
)
736 static WCHAR e
[] = { 'e',0 };
737 static WCHAR en
[] = { 'e','n',0 };
738 static WCHAR empty
[] = { 0 };
739 static WCHAR dash
[] = { '-',0 };
740 static WCHAR e_dash
[] = { 'e','-',0 };
741 static WCHAR en_gb
[] = { 'e','n','-','g','b',0 };
742 static WCHAR en_us
[] = { 'e','n','-','u','s',0 };
743 static WCHAR en_them
[] = { 'e','n','-','t','h','e','m',0 };
744 static WCHAR english
[] = { 'e','n','g','l','i','s','h',0 };
746 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, NULL
, en
);
747 ok(ret
== E_INVALIDARG
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
749 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, NULL
);
750 ok(ret
== E_INVALIDARG
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
752 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, e
);
753 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
755 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, empty
);
756 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
758 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, dash
);
759 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
761 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, e_dash
);
762 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
764 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_them
);
765 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
767 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, english
);
768 ok(ret
== E_FAIL
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
772 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en
);
773 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
774 ok(lcid
== 9, "got wrong lcid: %04x\n", lcid
);
776 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_gb
);
777 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
778 ok(lcid
== 0x809, "got wrong lcid: %04x\n", lcid
);
780 ret
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, en_us
);
781 ok(ret
== S_OK
, "GetLcidFromRfc1766 returned: %08x\n", ret
);
782 ok(lcid
== 0x409, "got wrong lcid: %04x\n", lcid
);
785 static void test_GetRfc1766FromLcid(IMultiLanguage2
*iML2
)
791 static WCHAR kok
[] = {'k','o','k',0};
793 hr
= IMultiLanguage2_GetLcidFromRfc1766(iML2
, &lcid
, kok
);
794 ok(hr
== S_OK
, "Expected S_OK, got %08x\n", hr
);
796 hr
= IMultiLanguage2_GetRfc1766FromLcid(iML2
, lcid
, &rfcstr
);
797 ok(hr
== S_OK
, "Expected S_OK, got %08x\n", hr
);
798 ok_w2("Expected \"%s\", got \"%s\"n", kok
, rfcstr
);
800 SysFreeString(rfcstr
);
805 IMultiLanguage2
*iML2
= NULL
;
806 IMLangFontLink
*iMLFL
= NULL
;
809 pGetCPInfoExA
= (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA");
812 TRACE_2("Call CoCreateInstance\n");
813 ret
= CoCreateInstance(&CLSID_CMultiLanguage
, NULL
, CLSCTX_INPROC_SERVER
,
814 &IID_IMultiLanguage2
, (void **)&iML2
);
816 trace("ret = %08x, MultiLanguage2 iML2 = %p\n", ret
, iML2
);
817 if (ret
!= S_OK
|| !iML2
) return;
820 test_GetLcidFromRfc1766(iML2
);
821 test_GetRfc1766FromLcid(iML2
);
823 test_EnumCodePages(iML2
, 0);
824 test_EnumCodePages(iML2
, MIMECONTF_MIME_LATEST
);
825 test_EnumCodePages(iML2
, MIMECONTF_BROWSER
);
826 test_EnumCodePages(iML2
, MIMECONTF_MINIMAL
);
827 test_EnumCodePages(iML2
, MIMECONTF_VALID
);
828 /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
829 /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
831 test_EnumScripts(iML2
, 0);
832 test_EnumScripts(iML2
, SCRIPTCONTF_SCRIPT_USER
);
833 test_EnumScripts(iML2
, SCRIPTCONTF_SCRIPT_USER
| SCRIPTCONTF_SCRIPT_HIDE
| SCRIPTCONTF_SCRIPT_SYSTEM
);
835 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
836 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UTF8
, CP_UNICODE
);
837 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret
);
838 TRACE_2("Call IMultiLanguage2_IsConvertible\n");
839 ret
= IMultiLanguage2_IsConvertible(iML2
, CP_UNICODE
, CP_UTF8
);
840 ok(ret
== S_OK
, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret
);
842 test_multibyte_to_unicode_translations(iML2
);
844 IMultiLanguage2_Release(iML2
);
846 ret
= CoCreateInstance(&CLSID_CMultiLanguage
, NULL
, CLSCTX_INPROC_SERVER
,
847 &IID_IMLangFontLink
, (void **)&iMLFL
);
849 trace("ret = %08x, IMLangFontLink iMLFL = %p\n", ret
, iMLFL
);
850 if (ret
!= S_OK
|| !iML2
) return;
852 IMLangFontLink_Test(iMLFL
);
853 IMLangFontLink_Release(iMLFL
);