ReactOS  0.4.13-dev-257-gfabbd7c
mlang.c
Go to the documentation of this file.
1 /*
2  * Unit test suite for MLANG APIs.
3  *
4  * Copyright 2004 Dmitry Timoshkov
5  * Copyright 2009 Detlef Riekenberg
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #define COBJMACROS
23 #ifdef __REACTOS__
24 #define CONST_VTABLE
25 #endif
26 
27 #include <stdarg.h>
28 #include <stdio.h>
29 
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "initguid.h"
34 #include "mlang.h"
35 
36 #include "wine/test.h"
37 
38 #ifndef CP_UNICODE
39 #define CP_UNICODE 1200
40 #endif
41 
42 /* #define DUMP_CP_INFO */
43 /* #define DUMP_SCRIPT_INFO */
44 
45 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
46 static HRESULT (WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD, DWORD, LPCSTR,
47  LPINT, LPWSTR, LPINT);
48 static HRESULT (WINAPI *pConvertINetUnicodeToMultiByte)(LPDWORD, DWORD, LPCWSTR,
49  LPINT, LPSTR, LPINT);
50 static HRESULT (WINAPI *pRfc1766ToLcidA)(LCID *, LPCSTR);
51 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
52 
53 typedef struct lcid_tag_table {
60 
61 /* en, ar and zh use SUBLANG_NEUTRAL for the rfc1766 name without the country
62  all others suppress the country with SUBLANG_DEFAULT.
63  For 3 letter language codes, the rfc1766 is too small for the country */
64 
65 static const lcid_table_entry lcid_table[] = {
66  {"e", -1, E_FAIL},
67  {"", -1, E_FAIL},
68  {"-", -1, E_FAIL},
69  {"e-", -1, E_FAIL},
70 
71  {"ar", 1, S_OK},
72  {"zh", 4, S_OK},
73 
74  {"de", 0x0407, S_OK},
75  {"de-ch", 0x0807, S_OK},
76  {"de-at", 0x0c07, S_OK},
77  {"de-lu", 0x1007, S_OK},
78  {"de-li", 0x1407, S_OK},
79 
80  {"en", 9, S_OK},
81  {"en-gb", 0x809, S_OK},
82  {"en-GB", 0x809, S_OK},
83  {"EN-GB", 0x809, S_OK},
84  {"en-US", 0x409, S_OK},
85  {"en-us", 0x409, S_OK},
86 
87  {"fr", 0x040c, S_OK},
88  {"fr-be", 0x080c, S_OK},
89  {"fr-ca", 0x0c0c, S_OK},
90  {"fr-ch", 0x100c, S_OK},
91  {"fr-lu", 0x140c, S_OK},
92  {"fr-mc", 0x180c, S_OK, 0x040c, "fr"},
93 
94  {"it", 0x0410, S_OK},
95  {"it-ch", 0x0810, S_OK},
96 
97  {"nl", 0x0413, S_OK},
98  {"nl-be", 0x0813, S_OK},
99  {"pl", 0x0415, S_OK},
100  {"ru", 0x0419, S_OK},
101 
102  {"kok", 0x0457, S_OK, 0x0412, "x-kok"}
103 
104 };
105 
106 #define TODO_NAME 1
107 
108 typedef struct info_table_tag {
116 
117 static const WCHAR de_en[] = {'E','n','g','l','i','s','c','h',0};
118 static const WCHAR de_enca[] = {'E','n','g','l','i','s','c','h',' ',
119  '(','K','a','n','a','d','a',')',0};
120 static const WCHAR de_engb[] = {'E','n','g','l','i','s','c','h',' ',
121  '(','G','r','o',0xDF,'b','r','i','t','a','n','n','i','e','n',')',0};
122 static const WCHAR de_engb2[] ={'E','n','g','l','i','s','c','h',' ',
123  '(','V','e','r','e','i','n','i','g','t','e','s',' ',
124  'K',0xF6,'n','i','g','r','e','i','c',0};
125 static const WCHAR de_enus[] = {'E','n','g','l','i','s','c','h',' ',
126  '(','U','S','A',')',0};
127 static const WCHAR de_enus2[] ={'E','n','g','l','i','s','c','h',' ',
128  '(','V','e','r','e','i','n','i','g','t','e',' ',
129  'S','t','a','a','t','e','n',')',0};
130 static const WCHAR de_de[] = {'D','e','u','t','s','c','h',' ',
131  '(','D','e','u','t','s','c','h','l','a','n','d',')',0};
132 static const WCHAR de_deat[] = {'D','e','u','t','s','c','h',' ',
133  '(',0xD6,'s','t','e','r','r','e','i','c','h',')',0};
134 static const WCHAR de_dech[] = {'D','e','u','t','s','c','h',' ',
135  '(','S','c','h','w','e','i','z',')',0};
136 
137 static const WCHAR en_en[] = {'E','n','g','l','i','s','h',0};
138 static const WCHAR en_enca[] = {'E','n','g','l','i','s','h',' ',
139  '(','C','a','n','a','d','a',')',0};
140 static const WCHAR en_engb[] = {'E','n','g','l','i','s','h',' ',
141  '(','U','n','i','t','e','d',' ','K','i','n','g','d','o','m',')',0};
142 static const WCHAR en_enus[] = {'E','n','g','l','i','s','h',' ',
143  '(','U','n','i','t','e','d',' ','S','t','a','t','e','s',')',0};
144 static const WCHAR en_de[] = {'G','e','r','m','a','n',' ',
145  '(','G','e','r','m','a','n','y',')',0};
146 static const WCHAR en_deat[] = {'G','e','r','m','a','n',' ',
147  '(','A','u','s','t','r','i','a',')',0};
148 static const WCHAR en_dech[] = {'G','e','r','m','a','n',' ',
149  '(','S','w','i','t','z','e','r','l','a','n','d',')',0};
150 
151 static const WCHAR fr_en[] = {'A','n','g','l','a','i','s',0};
152 static const WCHAR fr_enca[] = {'A','n','g','l','a','i','s',' ',
153  '(','C','a','n','a','d','a',')',0};
154 static const WCHAR fr_engb[] = {'A','n','g','l','a','i','s',' ',
155  '(','R','o','y','a','u','m','e','-','U','n','i',')',0};
156 static const WCHAR fr_enus[] = {'A','n','g','l','a','i','s',' ',
157  '(',0xC9, 't','a','t','s','-','U','n','i','s',')',0};
158 static const WCHAR fr_enus2[] ={'A','n','g','l','a','i','s',' ',
159  '(','U','.','S','.',')',0};
160 static const WCHAR fr_de[] = {'A','l','l','e','m','a','n','d',' ',
161  '(','A','l','l','e','m','a','g','n','e',')',0};
162 static const WCHAR fr_de2[] = {'A','l','l','e','m','a','n','d',' ',
163  '(','S','t','a','n','d','a','r','d',')',0};
164 static const WCHAR fr_deat[] = {'A','l','l','e','m','a','n','d',' ',
165  '(','A','u','t','r','i','c','h','e',')',0};
166 static const WCHAR fr_dech[] = {'A','l','l','e','m','a','n','d',' ',
167  '(','S','u','i','s','s','e',')',0};
168 
169 static const info_table_entry info_table[] = {
171  0, "en", en_en},
173  0, "en-us", en_enus},
175  0, "en-gb", en_engb},
177  0, "en-us", en_enus},
179  0, "en-ca", en_enca},
180 
182  0, "de", en_de},
184  0, "de", en_de},
186  0, "de-ch", en_dech},
188  0, "de-at", en_deat},
189 
191  TODO_NAME, "en", de_en},
193  TODO_NAME, "en-us", de_enus, de_enus2},
195  TODO_NAME, "en-gb", de_engb, de_engb2},
197  TODO_NAME, "en-us", de_enus, de_enus2},
199  TODO_NAME, "en-ca", de_enca},
200 
202  TODO_NAME, "de", de_de},
204  TODO_NAME, "de",de_de},
206  TODO_NAME, "de-ch", de_dech},
208  TODO_NAME, "de-at", de_deat},
209 
211  TODO_NAME, "en", fr_en},
213  TODO_NAME, "en-us", fr_enus, fr_enus2},
215  TODO_NAME, "en-gb", fr_engb},
217  TODO_NAME, "en-us", fr_enus, fr_enus2},
219  TODO_NAME, "en-ca", fr_enca},
220 
222  TODO_NAME, "de", fr_de, fr_de2},
224  TODO_NAME, "de", fr_de, fr_de2},
226  TODO_NAME, "de-ch", fr_dech},
228  TODO_NAME, "de-at", fr_deat}
229 
230 };
231 
233 {
234  MIMECPINFO cpinfo;
235 
245 };
246 
247 static const struct cpinfo_test_data iml2_cpinfo_data[] =
248 {
249  /* 0. Chinese Simplified (Auto-Select) */
250  {
251  {
252  MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
253  50936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','A','u','t','o','-','S','e','l','e','c','t',')',0},
254  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0},
255  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0},
256  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','s',0},
257  {'S','i','m','s','u','n',0},
258  {'S','i','m','s','u','n',0}, 134
259  },
260  },
261  /* 1. Chinese Simplified (GB2312) */
262  {
263  {
264  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
265  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
266  MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
267  936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','2','3','1','2',')',0},
268  {'g','b','2','3','1','2',0},
269  {'g','b','2','3','1','2',0},
270  {'g','b','2','3','1','2',0},
271  {'S','i','m','s','u','n',0},
272  {'S','i','m','s','u','n',0}, 134
273  },
274  },
275  /* 2. Chinese Simplified (GB2312-80) */
276  {
277  {
278  MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
279  MIMECONTF_MIME_LATEST,
280  20936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','2','3','1','2','-','8','0',')',0},
281  {'x','-','c','p','2','0','9','3','6',0},
282  {'x','-','c','p','2','0','9','3','6',0},
283  {'x','-','c','p','2','0','9','3','6',0},
284  {'S','i','m','s','u','n',0},
285  {'S','i','m','s','u','n',0}, 134
286  },
287  },
288  /* 3. Chinese Simplified (HZ) */
289  {
290  {
291  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
292  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
293  MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
294  52936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','H','Z',')',0},
295  {'h','z','-','g','b','-','2','3','1','2',0},
296  {'h','z','-','g','b','-','2','3','1','2',0},
297  {'h','z','-','g','b','-','2','3','1','2',0},
298  {'S','i','m','s','u','n',0},
299  {'S','i','m','s','u','n',0}, 134
300  },
301  },
302  /* 4. Chinese Simplified (GB18030) */
303  {
304  {
305  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
306  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
307  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
308  54936, 936, {'C','h','i','n','e','s','e',' ','S','i','m','p','l','i','f','i','e','d',' ','(','G','B','1','8','0','3','0',')',0},
309  {'G','B','1','8','0','3','0',0},
310  {'G','B','1','8','0','3','0',0},
311  {'G','B','1','8','0','3','0',0},
312  {'S','i','m','s','u','n',0},
313  {'S','i','m','s','u','n',0}, 134
314  },
315  },
316  /* 5. Chinese Traditional (Auto-Select) */
317  {
318  {
319  MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
320  50950, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','A','u','t','o','-','S','e','l','e','c','t',')',0},
321  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0},
322  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0},
323  {'_','a','u','t','o','d','e','t','e','c','t','_','c','h','t',0},
324  {'M','i','n','g','L','i','u',0},
325  {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136
326  },
327  },
328  /* 6. Chinese Traditional (Big5) */
329  {
330  {
331  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
332  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
333  MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
334  950, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','B','i','g','5',')',0},
335  {'b','i','g','5',0},
336  {'b','i','g','5',0},
337  {'b','i','g','5',0},
338  {'M','i','n','g','L','i','u',0},
339  {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136
340  },
341  },
342  /* 7. Chinese Traditional (CNS) */
343  {
344  {
345  MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
346  MIMECONTF_MIME_LATEST,
347  20000, 950, {'C','h','i','n','e','s','e',' ','T','r','a','d','i','t','i','o','n','a','l',' ','(','C','N','S',')',0},
348  {'x','-','C','h','i','n','e','s','e','-','C','N','S',0},
349  {'x','-','C','h','i','n','e','s','e','-','C','N','S',0},
350  {'x','-','C','h','i','n','e','s','e','-','C','N','S',0},
351  {'M','i','n','g','L','i','u',0},
352  {'N','e','w',' ','M','i','n','g','L','i','u',0}, 136
353  },
354  },
355  /* 8. Arabic (Windows) */
356  {
357  {
358  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
359  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
360  MIMECONTF_MIME_LATEST,
361  1256, 1256, {'A','r','a','b','i','c',' ','(','W','i','n','d','o','w','s',')',0},
362  {'w','i','n','d','o','w','s','-','1','2','5','6',0},
363  {'w','i','n','d','o','w','s','-','1','2','5','6',0},
364  {'w','i','n','d','o','w','s','-','1','2','5','6',0},
365  {'S','i','m','p','l','i','f','i','e','d',' ','A','r','a','b','i','c',' ','F','i','x','e','d',0},
366  {'S','i','m','p','l','i','f','i','e','d',' ','A','r','a','b','i','c',0}, 178
367  },
368  },
369  /* 9. Baltic (Windows) */
370  {
371  {
372  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
373  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
374  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
375  1257, 1257, {'B','a','l','t','i','c',' ','(','W','i','n','d','o','w','s',')',0},
376  {'w','i','n','d','o','w','s','-','1','2','5','7',0},
377  {'w','i','n','d','o','w','s','-','1','2','5','7',0},
378  {'w','i','n','d','o','w','s','-','1','2','5','7',0},
379  {'C','o','u','r','i','e','r',' ','N','e','w',0},
380  {'A','r','i','a','l',0}, 186
381  },
382  },
383  /* 10. Central European (Windows) */
384  {
385  {
386  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
387  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
388  MIMECONTF_MIME_LATEST,
389  1250, 1250, {'C','e','n','t','r','a','l',' ','E','u','r','o','p','e','a','n',' ','(','W','i','n','d','o','w','s',')',0},
390  {'w','i','n','d','o','w','s','-','1','2','5','0',0},
391  {'w','i','n','d','o','w','s','-','1','2','5','0',0},
392  {'i','s','o','-','8','8','5','9','-','2',0},
393  {'C','o','u','r','i','e','r',' ','N','e','w',0},
394  {'A','r','i','a','l',0}, 238
395  },
397  },
398  /* 11. Cyrillic (Windows) */
399  {
400  {
401  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
402  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
403  MIMECONTF_MIME_LATEST,
404  1251, 1251, {'C','y','r','i','l','l','i','c',' ','(','W','i','n','d','o','w','s',')',0},
405  {'w','i','n','d','o','w','s','-','1','2','5','1',0},
406  {'w','i','n','d','o','w','s','-','1','2','5','1',0},
407  {'k','o','i','8','-','r',0},
408  {'C','o','u','r','i','e','r',' ','N','e','w',0},
409  {'A','r','i','a','l',0}, 204
410  },
412  },
413  /* 12. Greek (Windows) */
414  {
415  {
416  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
417  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
418  MIMECONTF_MIME_LATEST,
419  1253, 1253, {'G','r','e','e','k',' ','(','W','i','n','d','o','w','s',')',0},
420  {'w','i','n','d','o','w','s','-','1','2','5','3',0},
421  {'w','i','n','d','o','w','s','-','1','2','5','3',0},
422  {'i','s','o','-','8','8','5','9','-','7',0},
423  {'C','o','u','r','i','e','r',' ','N','e','w',0},
424  {'A','r','i','a','l',0}, 161
425  },
427  },
428  /* 13. Hebrew (Windows) */
429  {
430  {
431  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
432  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
433  MIMECONTF_MIME_LATEST,
434  1255, 1255, {'H','e','b','r','e','w',' ','(','W','i','n','d','o','w','s',')',0},
435  {'w','i','n','d','o','w','s','-','1','2','5','5',0},
436  {'w','i','n','d','o','w','s','-','1','2','5','5',0},
437  {'w','i','n','d','o','w','s','-','1','2','5','5',0},
438  {'M','i','r','i','a','m',' ','F','i','x','e','d',0},
439  {'D','a','v','i','d',0}, 177
440  },
441  },
442  /* 14. Japanese (Shift-JIS) */
443  {
444  {
445  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
446  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
447  MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
448  932, 932, {'J','a','p','a','n','e','s','e',' ','(','S','h','i','f','t','-','J','I','S',')',0},
449  {'s','h','i','f','t','_','j','i','s',0},
450  {'i','s','o','-','2','0','2','2','-','j','p',0},
451  {'i','s','o','-','2','0','2','2','-','j','p',0},
452  {'M','S',' ','G','o','t','h','i','c',0},
453  {'M','S',' ','P','G','o','t','h','i','c',0}, 128
454  }
455  },
456  /* 15. Korean */
457  {
458  {
459  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
460  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
461  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
462  949, 949, {'K','o','r','e','a','n',0},
463  {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0},
464  {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0},
465  {'k','s','_','c','_','5','6','0','1','-','1','9','8','7',0},
466  {'G','u','l','i','m','C','h','e',0},
467  {'G','u','l','i','m',0}, 129
468  },
469  },
470  /* 16. Thai (Windows) */
471  {
472  {
473  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
474  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
475  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
476  874, 874, {'T','h','a','i',' ','(','W','i','n','d','o','w','s',')',0},
477  {'w','i','n','d','o','w','s','-','8','7','4',0},
478  {'w','i','n','d','o','w','s','-','8','7','4',0},
479  {'w','i','n','d','o','w','s','-','8','7','4',0},
480  {'T','a','h','o','m','a',0},
481  {'T','a','h','o','m','a',0}, 222
482  },
484  },
485  /* 17. Turkish (Windows) */
486  {
487  {
488  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
489  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
490  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
491  1254, 1254, {'T','u','r','k','i','s','h',' ','(','W','i','n','d','o','w','s',')',0},
492  {'w','i','n','d','o','w','s','-','1','2','5','4',0},
493  {'w','i','n','d','o','w','s','-','1','2','5','4',0},
494  {'i','s','o','-','8','8','5','9','-','9',0},
495  {'C','o','u','r','i','e','r',' ','N','e','w',0},
496  {'A','r','i','a','l',0}, 162
497  },
499  },
500  /* 18. Vietnamese (Windows) */
501  {
502  {
503  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
504  MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
505  MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
506  1258, 1258, {'V','i','e','t','n','a','m','e','s','e',' ','(','W','i','n','d','o','w','s',')',0},
507  {'w','i','n','d','o','w','s','-','1','2','5','8',0},
508  {'w','i','n','d','o','w','s','-','1','2','5','8',0},
509  {'w','i','n','d','o','w','s','-','1','2','5','8',0},
510  {'C','o','u','r','i','e','r',' ','N','e','w',0},
511  {'A','r','i','a','l',0}, 163
512  },
513  },
514  /* 19. Western European (Windows) */
515  {
516  {
517  MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
518  MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
519  MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
520  1252, 1252, {'W','e','s','t','e','r','n',' ','E','u','r','o','p','e','a','n',' ','(','W','i','n','d','o','w','s',')',0},
521  {'W','i','n','d','o','w','s','-','1','2','5','2',0},
522  {'W','i','n','d','o','w','s','-','1','2','5','2',0},
523  {'i','s','o','-','8','8','5','9','-','1',0},
524  {'C','o','u','r','i','e','r',' ','N','e','w',0},
525  {'A','r','i','a','l',0}, 0
526  },
528  },
529  /* 20. Unicode */
530  {
531  {
532  MIMECONTF_MINIMAL | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
533  MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
534  1200, 1200, {'U','n','i','c','o','d','e',0},
535  {'u','n','i','c','o','d','e',0},
536  {'u','n','i','c','o','d','e',0},
537  {'u','n','i','c','o','d','e',0},
538  {'C','o','u','r','i','e','r',' ','N','e','w',0},
539  {'A','r','i','a','l',0}, 1
540  },
541  }
542 };
543 
545 {
546  HMODULE hMlang;
547 
548  hMlang = GetModuleHandleA("mlang.dll");
549  pConvertINetMultiByteToUnicode = (void *)GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode");
550  pConvertINetUnicodeToMultiByte = (void *)GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte");
551  pRfc1766ToLcidA = (void *)GetProcAddress(hMlang, "Rfc1766ToLcidA");
552  pLcidToRfc1766A = (void *)GetProcAddress(hMlang, "LcidToRfc1766A");
553 
554  pGetCPInfoExA = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCPInfoExA");
555 
556  return TRUE;
557 }
558 
559 #define ok_w2(format, szString1, szString2) \
560 \
561  if (lstrcmpW((szString1), (szString2)) != 0) \
562  { \
563  CHAR string1[256], string2[256]; \
564  WideCharToMultiByte(CP_ACP, 0, (szString1), -1, string1, 256, NULL, NULL); \
565  WideCharToMultiByte(CP_ACP, 0, (szString2), -1, string2, 256, NULL, NULL); \
566  ok(0, (format), string1, string2); \
567  }
568 
569 static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
570 {
571  /* these APIs are broken regarding constness of the input buffer */
572  char stringA[] = "Just a test string\0"; /* double 0 for CP_UNICODE tests */
573  WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
574  char bufA[256];
575  WCHAR bufW[256];
576  UINT lenA, lenW, expected_len;
577  HRESULT ret;
578 
579  /* IMultiLanguage2_ConvertStringToUnicode tests */
580 
581  memset(bufW, 'x', sizeof(bufW));
582  lenA = 0;
583  lenW = ARRAY_SIZE(bufW);
584  ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
585  ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
586  ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
587  ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
588 
589  memset(bufW, 'x', sizeof(bufW));
590  lenA = -1;
591  lenW = ARRAY_SIZE(bufW);
592  ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
593  ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
594  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
595  ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
596  if (lenW < ARRAY_SIZE(bufW)) {
597  /* can only happen if the convert call fails */
598  ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
599  bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
600  }
601  ok(!lstrcmpW(bufW, stringW), "bufW/stringW mismatch\n");
602 
603  memset(bufW, 'x', sizeof(bufW));
604  lenA = -1;
605  lenW = 5;
606  ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, bufW, &lenW);
607  ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringToUnicode should fail: %08x\n", ret);
608  ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
609  /* still has to do partial conversion */
610  ok(!memcmp(bufW, stringW, 5 * sizeof(WCHAR)), "bufW/stringW mismatch\n");
611 
612  memset(bufW, 'x', sizeof(bufW));
613  lenA = -1;
614  lenW = ARRAY_SIZE(bufW);
615  ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, CP_UNICODE, stringA, &lenA, bufW, &lenW);
616  ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
617  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
618  ok(lenW == lstrlenW(stringW)/(int)sizeof(WCHAR), "wrong lenW %u\n", lenW);
619  ok(bufW[lenW] != 0, "buf should not be 0 terminated\n");
620  bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
621  ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n");
622 
623  memset(bufW, 'x', sizeof(bufW));
624  lenA = lstrlenA(stringA);
625  lenW = 0;
626  ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, NULL, &lenW);
627  ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08x\n", ret);
628  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
629  expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
630  ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
631 
632  memset(bufW, 'x', sizeof(bufW));
633  lenA = lstrlenA(stringA);
634  lenW = ARRAY_SIZE(bufW);
635  ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
636  ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
637  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
638  expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
639  ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
640 
641  memset(bufW, 'x', sizeof(bufW));
642  lenA = lstrlenA(stringA);
643  lenW = 0;
644  ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, (INT *)&lenA, NULL, (INT *)&lenW);
645  ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08x\n", ret);
646  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
647  expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
648  ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
649 
650  /* IMultiLanguage2_ConvertStringFromUnicode tests */
651 
652  memset(bufA, 'x', sizeof(bufA));
653  lenW = 0;
654  lenA = sizeof(bufA);
655  ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
656  ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
657  ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
658  ok(lenW == 0, "expected lenW 0, got %u\n", lenW);
659 
660  memset(bufA, 'x', sizeof(bufA));
661  lenW = -1;
662  lenA = sizeof(bufA);
663  ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
664  ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
665  ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
666  ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
667  ok(bufA[lenA] != 0, "buf should not be 0 terminated\n");
668  bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
669  ok(!lstrcmpA(bufA, stringA), "bufA/stringA mismatch\n");
670 
671  memset(bufA, 'x', sizeof(bufA));
672  lenW = -1;
673  lenA = 5;
674  ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, bufA, &lenA);
675  ok(ret == E_FAIL, "IMultiLanguage2_ConvertStringFromUnicode should fail: %08x\n", ret);
676  ok(lenA == 0, "expected lenA 0, got %u\n", lenA);
677  /* still has to do partial conversion */
678  ok(!memcmp(bufA, stringA, 5), "bufW/stringW mismatch\n");
679 
680  memset(bufA, 'x', sizeof(bufA));
681  lenW = -1;
682  lenA = sizeof(bufA);
683  ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, CP_UNICODE, stringW, &lenW, bufA, &lenA);
684  ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
685  ok(lenA == lstrlenA(stringA) * (int)sizeof(WCHAR), "wrong lenA %u\n", lenA);
686  ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
687  ok(bufA[lenA] != 0 && bufA[lenA+1] != 0, "buf should not be 0 terminated\n");
688  bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
689  bufA[lenA+1] = 0; /* sizeof(WCHAR) */
690  ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n");
691 
692  memset(bufA, 'x', sizeof(bufA));
693  lenW = lstrlenW(stringW);
694  lenA = 0;
695  ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, NULL, &lenA);
696  ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08x\n", ret);
697  ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
698  expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
699  ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
700 }
701 
702 static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
703 {
704  ok(cpinfo1->dwFlags == cpinfo2->dwFlags, "dwFlags mismatch: %08x != %08x\n", cpinfo1->dwFlags, cpinfo2->dwFlags);
705  ok(cpinfo1->uiCodePage == cpinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", cpinfo1->uiCodePage, cpinfo2->uiCodePage);
706  ok(cpinfo1->uiFamilyCodePage == cpinfo2->uiFamilyCodePage, "uiFamilyCodePage mismatch: %u != %u\n", cpinfo1->uiFamilyCodePage, cpinfo2->uiFamilyCodePage);
707  ok(!lstrcmpW(cpinfo1->wszDescription, cpinfo2->wszDescription), "wszDescription mismatch\n");
708  ok(!lstrcmpW(cpinfo1->wszWebCharset, cpinfo2->wszWebCharset), "wszWebCharset mismatch\n");
709  ok(!lstrcmpW(cpinfo1->wszHeaderCharset, cpinfo2->wszHeaderCharset), "wszHeaderCharset mismatch\n");
710  ok(!lstrcmpW(cpinfo1->wszBodyCharset, cpinfo2->wszBodyCharset), "wszBodyCharset mismatch\n");
711  ok(!lstrcmpW(cpinfo1->wszFixedWidthFont, cpinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
712  ok(!lstrcmpW(cpinfo1->wszProportionalFont, cpinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
713  ok(cpinfo1->bGDICharset == cpinfo2->bGDICharset, "bGDICharset mismatch: %d != %d\n", cpinfo1->bGDICharset, cpinfo2->bGDICharset);
714 }
715 
716 #ifdef DUMP_CP_INFO
717 static const char *dump_mime_flags(DWORD flags)
718 {
719  static char buf[1024];
720 
721  buf[0] = 0;
722 
723  if (flags & MIMECONTF_MAILNEWS) strcat(buf, " MIMECONTF_MAILNEWS");
724  if (flags & MIMECONTF_BROWSER) strcat(buf, " MIMECONTF_BROWSER");
725  if (flags & MIMECONTF_MINIMAL) strcat(buf, " MIMECONTF_MINIMAL");
726  if (flags & MIMECONTF_IMPORT) strcat(buf, " MIMECONTF_IMPORT");
727  if (flags & MIMECONTF_SAVABLE_MAILNEWS) strcat(buf, " MIMECONTF_SAVABLE_MAILNEWS");
728  if (flags & MIMECONTF_SAVABLE_BROWSER) strcat(buf, " MIMECONTF_SAVABLE_BROWSER");
729  if (flags & MIMECONTF_EXPORT) strcat(buf, " MIMECONTF_EXPORT");
730  if (flags & MIMECONTF_PRIVCONVERTER) strcat(buf, " MIMECONTF_PRIVCONVERTER");
731  if (flags & MIMECONTF_VALID) strcat(buf, " MIMECONTF_VALID");
732  if (flags & MIMECONTF_VALID_NLS) strcat(buf, " MIMECONTF_VALID_NLS");
733  if (flags & MIMECONTF_MIME_IE4) strcat(buf, " MIMECONTF_MIME_IE4");
734  if (flags & MIMECONTF_MIME_LATEST) strcat(buf, " MIMECONTF_MIME_LATEST");
735  if (flags & MIMECONTF_MIME_REGISTRY) strcat(buf, " MIMECONTF_MIME_REGISTRY");
736 
737  return buf;
738 }
739 #endif
740 
741 static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to)
742 {
744  BYTE dest[MAX_PATH];
745  HRESULT hr;
746  UINT srcsz, destsz;
747 
748  static WCHAR strW[] = {'a','b','c',0};
749 
750  /* Check to see if the target codepage has these characters or not */
751  if (from != CP_UTF8)
752  {
753  BOOL fDefaultChar;
754  char ch[10];
755  int cb;
757  strW, 3, ch, sizeof(ch), NULL, &fDefaultChar);
758 
759  if(cb == 0 || fDefaultChar)
760  {
761  trace("target codepage %i does not contain 'abc'\n",from);
762  return E_FAIL;
763  }
764  }
765 
766  srcsz = lstrlenW(strW) + 1;
767  destsz = MAX_PATH;
768  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW,
769  &srcsz, convert, &destsz);
770  if (hr != S_OK)
771  return S_FALSE;
772 
773  srcsz = -1;
774  destsz = MAX_PATH;
775  hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert,
776  &srcsz, dest, &destsz);
777  if (hr != S_OK)
778  return S_FALSE;
779 
780  return S_OK;
781 }
782 
783 static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
784 {
785  IEnumCodePage *iEnumCP = NULL;
786  MIMECPINFO *cpinfo;
787  MIMECPINFO cpinfo2;
788  HRESULT ret;
789  ULONG i, n;
790  UINT total;
791 
792  total = 0;
793  ret = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &total);
794  ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfCodePageInfo: expected S_OK/!0, got %08x/%u\n", ret, total);
795 
796  trace("total mlang supported codepages %u\n", total);
797 
798  ret = IMultiLanguage2_EnumCodePages(iML2, flags, LANG_NEUTRAL, &iEnumCP);
799  ok(ret == S_OK && iEnumCP, "IMultiLanguage2_EnumCodePages: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumCP);
800 
801  ret = IEnumCodePage_Reset(iEnumCP);
802  ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
803  n = 65536;
804  ret = IEnumCodePage_Next(iEnumCP, 0, NULL, &n);
805  ok(ret == S_FALSE || ret == E_FAIL,
806  "IEnumCodePage_Next: expected S_FALSE or E_FAIL, got %08x\n", ret);
807  if (ret == S_FALSE)
808  ok(n == 0, "IEnumCodePage_Next: expected 0/S_FALSE, got %u/%08x\n", n, ret);
809  else if (ret == E_FAIL)
810  ok(n == 65536, "IEnumCodePage_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
811  ret = IEnumCodePage_Next(iEnumCP, 0, NULL, NULL);
812  ok(ret == S_FALSE || ret == E_FAIL,
813  "IEnumCodePage_Next: expected S_FALSE or E_FAIL, got %08x\n", ret);
814 
815  cpinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*cpinfo) * total * 2);
816 
817  n = total * 2;
818  ret = IEnumCodePage_Next(iEnumCP, 0, cpinfo, &n);
819  ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
820 
821  n = total * 2;
822  ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n);
823  ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08x/%u\n", ret, n);
824 
825  trace("flags %08x, enumerated codepages %u\n", flags, n);
826 
827  if (!flags)
828  {
829  ok(n == total, "IEnumCodePage_Next: expected %u, got %u\n", total, n);
830 
831  flags = MIMECONTF_MIME_LATEST;
832  }
833 
834  total = n;
835 
836  for (i = 0; i < n; i++)
837  {
838  CHARSETINFO csi;
839  MIMECSETINFO mcsi;
840  HRESULT convertible = S_OK;
841  static const WCHAR autoW[] = {'_','a','u','t','o',0};
842  static const WCHAR feffW[] = {'u','n','i','c','o','d','e','F','E','F','F',0};
843 
844 #ifdef DUMP_CP_INFO
845  trace("MIMECPINFO #%u:\n"
846  "dwFlags %08x %s\n"
847  "uiCodePage %u\n"
848  "uiFamilyCodePage %u\n"
849  "wszDescription %s\n"
850  "wszWebCharset %s\n"
851  "wszHeaderCharset %s\n"
852  "wszBodyCharset %s\n"
853  "wszFixedWidthFont %s\n"
854  "wszProportionalFont %s\n"
855  "bGDICharset %d\n\n",
856  i,
857  cpinfo[i].dwFlags, dump_mime_flags(cpinfo[i].dwFlags),
858  cpinfo[i].uiCodePage,
859  cpinfo[i].uiFamilyCodePage,
860  wine_dbgstr_w(cpinfo[i].wszDescription),
861  wine_dbgstr_w(cpinfo[i].wszWebCharset),
862  wine_dbgstr_w(cpinfo[i].wszHeaderCharset),
863  wine_dbgstr_w(cpinfo[i].wszBodyCharset),
864  wine_dbgstr_w(cpinfo[i].wszFixedWidthFont),
865  wine_dbgstr_w(cpinfo[i].wszProportionalFont),
866  cpinfo[i].bGDICharset);
867 #endif
868  ok(cpinfo[i].dwFlags & flags, "enumerated flags %08x do not include requested %08x\n", cpinfo[i].dwFlags, flags);
869 
870  if (TranslateCharsetInfo((DWORD *)(INT_PTR)cpinfo[i].uiFamilyCodePage, &csi, TCI_SRCCODEPAGE))
871  ok(cpinfo[i].bGDICharset == csi.ciCharset, "%d != %d\n", cpinfo[i].bGDICharset, csi.ciCharset);
872  else
873  if (winetest_debug > 1)
874  trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage);
875 
876 #ifdef DUMP_CP_INFO
877  trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
878 #endif
879 
880  /* support files for some codepages might be not installed, or
881  * the codepage is just an alias.
882  */
883  if (IsValidCodePage(cpinfo[i].uiCodePage))
884  {
885  ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UNICODE);
886  ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UNICODE) = %08x\n", cpinfo[i].uiCodePage, ret);
887  ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage);
888  ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
889 
890  convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
891  if (convertible != E_FAIL)
892  {
893  ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8);
894  ok(ret == convertible, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret);
895  ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage);
896  ok(ret == convertible, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret);
897  }
898  }
899  else
900  if (winetest_debug > 1)
901  trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage);
902 
903  if (memcmp(cpinfo[i].wszWebCharset,feffW,sizeof(WCHAR)*11)==0)
904  skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
905  else
906  {
907  ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszWebCharset, &mcsi);
908  /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
909  if (memcmp(cpinfo[i].wszWebCharset, autoW, 5 * sizeof(WCHAR)))
910  {
911  ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
912 #ifdef DUMP_CP_INFO
913  trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszWebCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
914 #endif
915  ok(!lstrcmpiW(cpinfo[i].wszWebCharset, mcsi.wszCharset), "%s != %s\n",
916  wine_dbgstr_w(cpinfo[i].wszWebCharset), wine_dbgstr_w(mcsi.wszCharset));
917 
918  if (0)
919  {
920  /* native mlang returns completely messed up encodings in some cases */
921  ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
922  "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
923  ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
924  "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
925  }
926  }
927  }
928 
929  if (memcmp(cpinfo[i].wszHeaderCharset,feffW,sizeof(WCHAR)*11)==0)
930  skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
931  else
932  {
933  ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszHeaderCharset, &mcsi);
934  /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
935  if (memcmp(cpinfo[i].wszHeaderCharset, autoW, 5 * sizeof(WCHAR)))
936  {
937  ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
938 #ifdef DUMP_CP_INFO
939  trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszHeaderCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
940 #endif
941  ok(!lstrcmpiW(cpinfo[i].wszHeaderCharset, mcsi.wszCharset), "%s != %s\n",
942  wine_dbgstr_w(cpinfo[i].wszHeaderCharset), wine_dbgstr_w(mcsi.wszCharset));
943 
944  if (0)
945  {
946  /* native mlang returns completely messed up encodings in some cases */
947  ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
948  "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
949  ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
950  "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
951  }
952  }
953  }
954 
955  if (memcmp(cpinfo[i].wszBodyCharset,feffW,sizeof(WCHAR)*11)==0)
956  skip("Legacy windows bug returning invalid charset of unicodeFEFF\n");
957  else
958  {
959  ret = IMultiLanguage2_GetCharsetInfo(iML2, cpinfo[i].wszBodyCharset, &mcsi);
960  /* _autoxxx charsets are a fake and GetCharsetInfo fails for them */
961  if (memcmp(cpinfo[i].wszBodyCharset, autoW, 5 * sizeof(WCHAR)))
962  {
963  ok (ret == S_OK, "IMultiLanguage2_GetCharsetInfo failed: %08x\n", ret);
964 #ifdef DUMP_CP_INFO
965  trace("%s: %u %u %s\n", wine_dbgstr_w(cpinfo[i].wszBodyCharset), mcsi.uiCodePage, mcsi.uiInternetEncoding, wine_dbgstr_w(mcsi.wszCharset));
966 #endif
967  ok(!lstrcmpiW(cpinfo[i].wszBodyCharset, mcsi.wszCharset), "%s != %s\n",
968  wine_dbgstr_w(cpinfo[i].wszBodyCharset), wine_dbgstr_w(mcsi.wszCharset));
969 
970  if (0)
971  {
972  /* native mlang returns completely messed up encodings in some cases */
973  ok(mcsi.uiInternetEncoding == cpinfo[i].uiCodePage || mcsi.uiInternetEncoding == cpinfo[i].uiFamilyCodePage,
974  "%u != %u || %u\n", mcsi.uiInternetEncoding, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
975  ok(mcsi.uiCodePage == cpinfo[i].uiCodePage || mcsi.uiCodePage == cpinfo[i].uiFamilyCodePage,
976  "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage);
977  }
978  }
979  }
980  }
981 
982  /* now IEnumCodePage_Next should fail, since pointer is at the end */
983  n = 1;
984  ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
985  ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
986 
987  ret = IEnumCodePage_Reset(iEnumCP);
988  ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08x\n", ret);
989  n = 0;
990  ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
991  ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
992  cpinfo_cmp(cpinfo, &cpinfo2);
993 
994  if (0)
995  {
996  /* Due to a bug in MS' implementation of IEnumCodePage_Skip
997  * it's not used here.
998  */
999  ret = IEnumCodePage_Skip(iEnumCP, 1);
1000  ok(ret == S_OK, "IEnumCodePage_Skip: expected S_OK, got %08x\n", ret);
1001  }
1002  for (i = 0; i < total - 1; i++)
1003  {
1004  n = 0;
1005  ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
1006  ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
1007  cpinfo_cmp(&cpinfo[i + 1], &cpinfo2);
1008  }
1009 
1011  IEnumCodePage_Release(iEnumCP);
1012 }
1013 
1014 static void test_GetCharsetInfo_other(IMultiLanguage *ml)
1015 {
1016  WCHAR asciiW[] = {'a','s','c','i','i',0};
1017  WCHAR iso88591_1W[] = {'I','S','O','-','8','8','5','9','-','1',0};
1018  WCHAR iso88591_1retW[] = {'i','s','o','-','8','8','5','9','-','1',0};
1019  WCHAR iso88591_2W[] = {'I','S','O','8','8','5','9','-','1',0};
1020  WCHAR iso88591_2retW[] = {'i','s','o','8','8','5','9','-','1',0};
1021  WCHAR iso88591_3W[] = {'I','S','O','8','8','5','9','1',0};
1022  WCHAR iso88591_4W[] = {'I','S','O','-','8','8','5','9','1',0};
1023  WCHAR iso88591_5W[] = {'I','S','O','8','8','-','5','9','1',0};
1024  WCHAR iso88591_6W[] = {'-','I','S','O','8','8','5','9','1',0};
1025  WCHAR iso88591_7W[] = {' ','I','S','O','-','8','8','5','9','-','1',0};
1026  struct other {
1027  int todo;
1028  HRESULT hr;
1029  WCHAR* charset;
1030  WCHAR* ret_charset;
1031  } other[] = {
1032  { 0, S_OK, asciiW, asciiW },
1033  { 0, S_OK, iso88591_1W, iso88591_1retW },
1034  { 1, S_OK, iso88591_2W, iso88591_2retW },
1035  { 0, E_FAIL, iso88591_3W, 0 },
1036  { 0, E_FAIL, iso88591_4W, 0 },
1037  { 0, E_FAIL, iso88591_5W, 0 },
1038  { 0, E_FAIL, iso88591_6W, 0 },
1039  { 0, E_FAIL, iso88591_7W, 0 },
1040  };
1041  MIMECSETINFO info;
1042  HRESULT hr;
1043  int i;
1044 
1045  for (i = 0; i < ARRAY_SIZE(other); i++)
1046  {
1047  hr = IMultiLanguage_GetCharsetInfo(ml, other[i].charset, &info);
1048 
1050  ok(hr == other[i].hr, "#%d: got %08x, expected %08x\n", i, hr, other[i].hr);
1051 
1052  if (hr == S_OK)
1054  ok(!lstrcmpW(info.wszCharset, other[i].ret_charset), "#%d: got %s, expected %s\n",
1055  i, wine_dbgstr_w(info.wszCharset), wine_dbgstr_w(other[i].ret_charset));
1056  }
1057 }
1058 
1059 static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2)
1060 {
1061  ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId);
1062  ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage);
1063  ok(!lstrcmpW(sinfo1->wszDescription, sinfo2->wszDescription), "wszDescription mismatch\n");
1064  ok(!lstrcmpW(sinfo1->wszFixedWidthFont, sinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
1065  ok(!lstrcmpW(sinfo1->wszProportionalFont, sinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
1066 }
1067 
1068 static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags)
1069 {
1070  IEnumScript *iEnumScript = NULL;
1071  SCRIPTINFO *sinfo;
1072  SCRIPTINFO sinfo2;
1073  HRESULT ret;
1074  ULONG i, n;
1075  UINT total;
1076 
1077  total = 0;
1078  ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total);
1079  ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08x/%u\n", ret, total);
1080 
1081  trace("total mlang supported scripts %u\n", total);
1082 
1083  ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript);
1084  ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08x/%p\n", ret, iEnumScript);
1085 
1086  ret = IEnumScript_Reset(iEnumScript);
1087  ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
1088  n = 65536;
1089  ret = IEnumScript_Next(iEnumScript, 0, NULL, &n);
1090  ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %u/%08x\n", n, ret);
1091  ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL);
1092  ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08x\n", ret);
1093 
1094  sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2);
1095 
1096  n = total * 2;
1097  ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n);
1098  ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
1099 
1100  n = total * 2;
1101  ret = IEnumScript_Next(iEnumScript, n, sinfo, &n);
1102  ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08x/%u\n", ret, n);
1103 
1104  trace("flags %08x, enumerated scripts %u\n", flags, n);
1105 
1106  if (!flags)
1107  {
1108  ok(n == total, "IEnumScript_Next: expected %u, got %u\n", total, n);
1109  }
1110 
1111  total = n;
1112 
1113  for (i = 0; pGetCPInfoExA && i < n; i++)
1114  {
1115 #ifdef DUMP_SCRIPT_INFO
1116  trace("SCRIPTINFO #%u:\n"
1117  "ScriptId %08x\n"
1118  "uiCodePage %u\n"
1119  "wszDescription %s\n"
1120  "wszFixedWidthFont %s\n"
1121  "wszProportionalFont %s\n\n",
1122  i,
1123  sinfo[i].ScriptId,
1124  sinfo[i].uiCodePage,
1125  wine_dbgstr_w(sinfo[i].wszDescription),
1126  wine_dbgstr_w(sinfo[i].wszFixedWidthFont),
1127  wine_dbgstr_w(sinfo[i].wszProportionalFont));
1128  trace("%u codepage %u\n", i, sinfo[i].uiCodePage);
1129 #endif
1130  }
1131 
1132  /* now IEnumScript_Next should fail, since pointer is at the end */
1133  n = 1;
1134  ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
1135  ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08x/%u\n", ret, n);
1136 
1137  ret = IEnumScript_Reset(iEnumScript);
1138  ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08x\n", ret);
1139  n = 0;
1140  ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
1141  ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
1142  scriptinfo_cmp(sinfo, &sinfo2);
1143 
1144  if (0)
1145  {
1146  /* Due to a bug in MS' implementation of IEnumScript_Skip
1147  * it's not used here.
1148  */
1149  ret = IEnumScript_Skip(iEnumScript, 1);
1150  ok(ret == S_OK, "IEnumScript_Skip: expected S_OK, got %08x\n", ret);
1151  }
1152  for (i = 0; i < total - 1; i++)
1153  {
1154  n = 0;
1155  ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
1156  ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %u/%08x\n", n, ret);
1157  scriptinfo_cmp(&sinfo[i + 1], &sinfo2);
1158  }
1159 
1160  HeapFree(GetProcessHeap(), 0, sinfo);
1161  IEnumScript_Release(iEnumScript);
1162 }
1163 
1164 static void IMLangFontLink_Test(IMLangFontLink* iMLFL)
1165 {
1166  DWORD dwCodePages, dwManyCodePages;
1167  DWORD dwCmpCodePages;
1168  UINT CodePage;
1169  static const WCHAR str[] = { 'd', 0x0436, 0xff90 };
1170  LONG processed;
1171  HRESULT ret;
1172 
1173  dwCodePages = ~0u;
1174  ret = IMLangFontLink_CodePageToCodePages(iMLFL, -1, &dwCodePages);
1175  ok(ret == E_FAIL, "IMLangFontLink_CodePageToCodePages should fail: %x\n", ret);
1176  ok(dwCodePages == 0, "expected 0, got %u\n", dwCodePages);
1177 
1178  dwCodePages = 0;
1179  ret = IMLangFontLink_CodePageToCodePages(iMLFL, 932, &dwCodePages);
1180  ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
1181  ok(dwCodePages == FS_JISJAPAN, "expected FS_JISJAPAN, got %08x\n", dwCodePages);
1182  CodePage = 0;
1183  ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwCodePages, 1035, &CodePage);
1184  ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
1185  ok(CodePage == 932, "Incorrect CodePage Returned (%i)\n",CodePage);
1186 
1187  dwManyCodePages = 0;
1188  ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1252, &dwManyCodePages);
1189  ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
1190  ok(dwManyCodePages == FS_LATIN1, "expected FS_LATIN1, got %08x\n", dwManyCodePages);
1191  dwCodePages = 0;
1192  ret = IMLangFontLink_CodePageToCodePages(iMLFL, 1256, &dwCodePages);
1193  ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
1194  ok(dwCodePages == FS_ARABIC, "expected FS_ARABIC, got %08x\n", dwCodePages);
1195  dwManyCodePages |= dwCodePages;
1196  ret = IMLangFontLink_CodePageToCodePages(iMLFL, 874, &dwCodePages);
1197  ok(ret == S_OK, "IMLangFontLink_CodePageToCodePages error %x\n", ret);
1198  ok(dwCodePages == FS_THAI, "expected FS_THAI, got %08x\n", dwCodePages);
1199  dwManyCodePages |= dwCodePages;
1200 
1201  ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 1256, &CodePage);
1202  ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
1203  ok(CodePage == 1256, "Incorrect CodePage Returned (%i)\n",CodePage);
1204 
1205  ret = IMLangFontLink_CodePagesToCodePage(iMLFL, dwManyCodePages, 936, &CodePage);
1206  ok(ret == S_OK, "IMLangFontLink_CodePagesToCodePage error %x\n", ret);
1207  ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage);
1208 
1209  /* Tests for GetCharCodePages */
1210 
1211  /* Latin 1 */
1212  dwCmpCodePages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH
1215  ret = IMLangFontLink_GetCharCodePages(iMLFL, 'd', &dwCodePages);
1216  ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
1217  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1218 
1219  dwCodePages = 0;
1220  processed = 0;
1221  ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 1, 0, &dwCodePages, &processed);
1222  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1223  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1224  ok(processed == 1, "expected 1, got %d\n", processed);
1225 
1226  /* Cyrillic */
1227  dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
1228  ret = IMLangFontLink_GetCharCodePages(iMLFL, 0x0436, &dwCodePages);
1229  ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
1230  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1231 
1232  dwCodePages = 0;
1233  processed = 0;
1234  ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[1], 1, 0, &dwCodePages, &processed);
1235  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1236  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1237  ok(processed == 1, "expected 1, got %d\n", processed);
1238 
1239  /* Japanese */
1240  dwCmpCodePages = FS_JISJAPAN;
1241  ret = IMLangFontLink_GetCharCodePages(iMLFL, 0xff90, &dwCodePages);
1242  ok(ret == S_OK, "IMLangFontLink_GetCharCodePages error %x\n", ret);
1243  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1244 
1245  dwCodePages = 0;
1246  processed = 0;
1247  ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
1248  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1249  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1250  ok(processed == 1, "expected 1, got %d\n", processed);
1251 
1252  dwCmpCodePages = FS_CYRILLIC | FS_JISJAPAN | FS_CHINESESIMP | FS_WANSUNG;
1253  dwCodePages = 0;
1254  processed = 0;
1255  ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 2, 0, &dwCodePages, &processed);
1256  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1257  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1258  ok(processed == 2, "expected 2, got %d\n", processed);
1259 
1260  dwCmpCodePages = FS_JISJAPAN;
1261  dwCodePages = 0;
1262  processed = 0;
1263  ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 3, 0, &dwCodePages, &processed);
1264  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1265  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1266  ok(processed == 3, "expected 3, got %d\n", processed);
1267 
1268  dwCodePages = 0xffff;
1269  processed = -1;
1270  ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, &dwCodePages, &processed);
1271  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1272  ok(dwCodePages == dwCmpCodePages, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1273  ok(processed == 1, "expected 0, got %d\n", processed);
1274 
1275  ret = IMLangFontLink_GetStrCodePages(iMLFL, &str[2], 1, 0, NULL, NULL);
1276  ok(ret == S_OK, "IMLangFontLink_GetStrCodePages error %x\n", ret);
1277 
1278  dwCodePages = 0xffff;
1279  processed = -1;
1280  ret = IMLangFontLink_GetStrCodePages(iMLFL, str, -1, 0, &dwCodePages, &processed);
1281  ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1282  ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1283  ok(processed == 0, "expected 0, got %d\n", processed);
1284 
1285  dwCodePages = 0xffff;
1286  processed = -1;
1287  ret = IMLangFontLink_GetStrCodePages(iMLFL, NULL, 1, 0, &dwCodePages, &processed);
1288  ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1289  ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1290  ok(processed == 0, "expected 0, got %d\n", processed);
1291 
1292  dwCodePages = 0xffff;
1293  processed = -1;
1294  ret = IMLangFontLink_GetStrCodePages(iMLFL, str, 0, 0, &dwCodePages, &processed);
1295  ok(ret == E_INVALIDARG, "IMLangFontLink_GetStrCodePages should fail: %x\n", ret);
1296  ok(dwCodePages == 0, "expected %x, got %x\n", dwCmpCodePages, dwCodePages);
1297  ok(processed == 0, "expected 0, got %d\n", processed);
1298 }
1299 
1300 /* copied from libs/wine/string.c */
1301 static WCHAR *strstrW(const WCHAR *str, const WCHAR *sub)
1302 {
1303  while (*str)
1304  {
1305  const WCHAR *p1 = str, *p2 = sub;
1306  while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
1307  if (!*p2) return (WCHAR *)str;
1308  str++;
1309  }
1310  return NULL;
1311 }
1312 
1313 static void test_rfc1766(IMultiLanguage2 *iML2)
1314 {
1315  IEnumRfc1766 *pEnumRfc1766;
1316  RFC1766INFO info;
1317  ULONG n;
1318  HRESULT ret;
1319  BSTR rfcstr;
1320 
1321  ret = IMultiLanguage2_EnumRfc1766(iML2, LANG_NEUTRAL, &pEnumRfc1766);
1322  ok(ret == S_OK, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret);
1323 
1324  while (1)
1325  {
1326  ret = IEnumRfc1766_Next(pEnumRfc1766, 1, &info, &n);
1327  if (ret != S_OK) break;
1328 
1329 #ifdef DUMP_CP_INFO
1330  trace("lcid %04x rfc_name %s locale_name %s\n",
1331  info.lcid, wine_dbgstr_w(info.wszRfc1766), wine_dbgstr_w(info.wszLocaleName));
1332 #endif
1333 
1334  ok(n == 1, "couldn't fetch 1 RFC1766INFO structure\n");
1335 
1336  /* verify the Rfc1766 value */
1337  ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, info.lcid, &rfcstr);
1338  ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1339 
1340  /* not an exact 1:1 correspondence between lcid and rfc1766 in the
1341  * mlang database, e.g., nb-no -> 1044 -> no */
1342  ok(strstrW(info.wszRfc1766, rfcstr) != NULL,
1343  "Expected matching locale names\n");
1344 
1345  SysFreeString(rfcstr);
1346  }
1347  IEnumRfc1766_Release(pEnumRfc1766);
1348 }
1349 
1350 static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2)
1351 {
1352  WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1353  LCID lcid;
1354  HRESULT ret;
1355  DWORD i;
1356 
1357  static WCHAR en[] = { 'e','n',0 };
1358  static WCHAR en_them[] = { 'e','n','-','t','h','e','m',0 };
1359  static WCHAR english[] = { 'e','n','g','l','i','s','h',0 };
1360 
1361 
1362  for(i = 0; i < ARRAY_SIZE(lcid_table); i++) {
1363  lcid = -1;
1364  MultiByteToWideChar(CP_ACP, 0, lcid_table[i].rfc1766, -1, rfc1766W, MAX_RFC1766_NAME);
1365  ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, rfc1766W);
1366 
1367  /* IE <6.0 guess 0x412 (ko) from "kok" */
1368  ok((ret == lcid_table[i].hr) ||
1369  broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1370  "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1371 
1372  ok((lcid == lcid_table[i].lcid) ||
1373  broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */
1374  "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1375  }
1376 
1377 
1378  ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, NULL, en);
1379  ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1380 
1381  ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, NULL);
1382  ok(ret == E_INVALIDARG, "GetLcidFromRfc1766 returned: %08x\n", ret);
1383 
1384  ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, en_them);
1385  ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1386  if (ret == S_FALSE)
1387  {
1388  BSTR rfcstr;
1389  static WCHAR en[] = {'e','n',0};
1390 
1391  ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1392  ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1393  ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr);
1394  }
1395 
1396  ret = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, english);
1397  ok((ret == E_FAIL || ret == S_FALSE), "GetLcidFromRfc1766 returned: %08x\n", ret);
1398  if (ret == S_FALSE)
1399  {
1400  BSTR rfcstr;
1401  static WCHAR en[] = {'e','n',0};
1402 
1403  ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr);
1404  ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
1405  ok_w2("Expected \"%s\", got \"%s\"n", en, rfcstr);
1406  }
1407 
1408 }
1409 
1410 static void test_Rfc1766ToLcid(void)
1411 {
1412  LCID lcid;
1413  HRESULT ret;
1414  DWORD i;
1415 
1416  for(i = 0; i < ARRAY_SIZE(lcid_table); i++) {
1417  lcid = -1;
1418  ret = pRfc1766ToLcidA(&lcid, lcid_table[i].rfc1766);
1419 
1420  /* IE <6.0 guess 0x412 (ko) from "kok" */
1421  ok( (ret == lcid_table[i].hr) ||
1422  broken(lcid_table[i].broken_lcid && (ret == S_FALSE)),
1423  "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, ret, lcid_table[i].hr);
1424 
1425  ok( (lcid == lcid_table[i].lcid) ||
1426  broken(lcid == lcid_table[i].broken_lcid), /* IE <6.0 */
1427  "#%02d: got LCID 0x%x (expected 0x%x)\n", i, lcid, lcid_table[i].lcid);
1428  }
1429 
1430  ret = pRfc1766ToLcidA(&lcid, NULL);
1431  ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1432 
1433  ret = pRfc1766ToLcidA(NULL, "en");
1434  ok(ret == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", ret);
1435 }
1436 
1437 static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2)
1438 {
1439  HRESULT hr;
1440  UINT value;
1441 
1442  value = 0xdeadbeef;
1443  hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, &value);
1444  ok( (hr == S_OK) && value,
1445  "got 0x%x with %d (expected S_OK with '!= 0')\n", hr, value);
1446 
1447  hr = IMultiLanguage2_GetNumberOfCodePageInfo(iML2, NULL);
1448  ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1449 
1450 }
1451 
1452 static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2)
1453 {
1454  CHAR expected[MAX_RFC1766_NAME];
1455  CHAR buffer[MAX_RFC1766_NAME + 1];
1456  DWORD i;
1457  HRESULT hr;
1458  BSTR rfcstr;
1459 
1460  for(i = 0; i < ARRAY_SIZE(lcid_table); i++) {
1461  buffer[0] = '\0';
1462 
1463  rfcstr = NULL;
1464  hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid_table[i].lcid, &rfcstr);
1465  ok(hr == lcid_table[i].hr,
1466  "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1467 
1468  if (hr != S_OK)
1469  continue; /* no result-string created */
1470 
1471  WideCharToMultiByte(CP_ACP, 0, rfcstr, -1, buffer, sizeof(buffer), NULL, NULL);
1473  lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1474 
1475  /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1476  ok( (!lstrcmpA(buffer, expected)) ||
1477  broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1478  "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1479 
1480  SysFreeString(rfcstr);
1481  }
1482 
1483  hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL);
1484  ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
1485 }
1486 
1487 static void test_LcidToRfc1766(void)
1488 {
1489  CHAR expected[MAX_RFC1766_NAME];
1490  CHAR buffer[MAX_RFC1766_NAME * 2];
1491  HRESULT hr;
1492  DWORD i;
1493 
1494  for(i = 0; i < ARRAY_SIZE(lcid_table); i++) {
1495 
1496  memset(buffer, '#', sizeof(buffer)-1);
1497  buffer[sizeof(buffer)-1] = '\0';
1498 
1499  hr = pLcidToRfc1766A(lcid_table[i].lcid, buffer, MAX_RFC1766_NAME);
1500 
1501  /* IE <5.0 does not recognize 0x180c (fr-mc) and 0x457 (kok) */
1502  ok( (hr == lcid_table[i].hr) ||
1503  broken(lcid_table[i].broken_lcid && (hr == E_FAIL)),
1504  "#%02d: HRESULT 0x%x (expected 0x%x)\n", i, hr, lcid_table[i].hr);
1505 
1506  if (hr != S_OK)
1507  continue;
1508 
1510  lstrlenA(lcid_table[i].rfc1766) + 1, expected, MAX_RFC1766_NAME);
1511 
1512  /* IE <6.0 return "x-kok" for LCID 0x457 ("kok") */
1513  /* IE <5.0 return "fr" for LCID 0x180c ("fr-mc") */
1514  ok( (!lstrcmpA(buffer, expected)) ||
1515  broken(!lstrcmpA(buffer, lcid_table[i].broken_rfc)),
1516  "#%02d: got '%s' (expected '%s')\n", i, buffer, expected);
1517 
1518  }
1519 
1520  memset(buffer, '#', sizeof(buffer)-1);
1521  buffer[sizeof(buffer)-1] = '\0';
1522  hr = pLcidToRfc1766A(-1, buffer, MAX_RFC1766_NAME);
1523  ok(hr == E_FAIL, "got 0x%08x and '%s' (expected E_FAIL)\n", hr, buffer);
1524 
1525  hr = pLcidToRfc1766A(LANG_ENGLISH, NULL, MAX_RFC1766_NAME);
1526  ok(hr == E_INVALIDARG, "got 0x%08x (expected E_INVALIDARG)\n", hr);
1527 
1528  memset(buffer, '#', sizeof(buffer)-1);
1529  buffer[sizeof(buffer)-1] = '\0';
1530  hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, -1);
1531  ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1532 
1533  memset(buffer, '#', sizeof(buffer)-1);
1534  buffer[sizeof(buffer)-1] = '\0';
1535  hr = pLcidToRfc1766A(LANG_ENGLISH, buffer, 0);
1536  ok(hr == E_INVALIDARG, "got 0x%08x and '%s' (expected E_INVALIDARG)\n", hr, buffer);
1537 }
1538 
1539 static void test_GetRfc1766Info(IMultiLanguage2 *iML2)
1540 {
1541  WCHAR short_broken_name[MAX_LOCALE_NAME];
1542  CHAR rfc1766A[MAX_RFC1766_NAME + 1];
1543  BYTE buffer[sizeof(RFC1766INFO) + 4];
1544  PRFC1766INFO prfc = (RFC1766INFO *) buffer;
1545  HRESULT ret;
1546  DWORD i;
1547 
1548  for(i = 0; i < ARRAY_SIZE(info_table); i++) {
1549  memset(buffer, 'x', sizeof(RFC1766INFO) + 2);
1550  buffer[sizeof(buffer) -1] = 0;
1551  buffer[sizeof(buffer) -2] = 0;
1552 
1553  ret = IMultiLanguage2_GetRfc1766Info(iML2, info_table[i].lcid, info_table[i].lang, prfc);
1554  WideCharToMultiByte(CP_ACP, 0, prfc->wszRfc1766, -1, rfc1766A, MAX_RFC1766_NAME, NULL, NULL);
1555  ok(ret == S_OK, "#%02d: got 0x%x (expected S_OK)\n", i, ret);
1556  ok(prfc->lcid == info_table[i].lcid,
1557  "#%02d: got 0x%04x (expected 0x%04x)\n", i, prfc->lcid, info_table[i].lcid);
1558 
1559  ok(!lstrcmpA(rfc1766A, info_table[i].rfc1766),
1560  "#%02d: got '%s' (expected '%s')\n", i, rfc1766A, info_table[i].rfc1766);
1561 
1562  /* Some IE versions truncate an oversized name one character too short */
1563  if (info_table[i].broken_name) {
1564  lstrcpyW(short_broken_name, info_table[i].broken_name);
1565  short_broken_name[MAX_LOCALE_NAME - 2] = 0;
1566  }
1567 
1569  ok( (!lstrcmpW(prfc->wszLocaleName, info_table[i].localename)) ||
1570  (info_table[i].broken_name && (
1571  broken(!lstrcmpW(prfc->wszLocaleName, info_table[i].broken_name)) || /* IE < 6.0 */
1572  broken(!lstrcmpW(prfc->wszLocaleName, short_broken_name)))),
1573  "#%02d: got %s (expected %s)\n", i,
1574  wine_dbgstr_w(prfc->wszLocaleName), wine_dbgstr_w(info_table[i].localename));
1575  }
1576  }
1577 
1578  /* SUBLANG_NEUTRAL only allowed for English, Arabic, Chinese */
1579  ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_GERMAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1580  ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1581 
1582  ret = IMultiLanguage2_GetRfc1766Info(iML2, MAKELANGID(LANG_ITALIAN, SUBLANG_NEUTRAL), LANG_ENGLISH, prfc);
1583  ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1584 
1585  /* NULL not allowed */
1586  ret = IMultiLanguage2_GetRfc1766Info(iML2, 0, LANG_ENGLISH, prfc);
1587  ok(ret == E_FAIL, "got 0x%x (expected E_FAIL)\n", ret);
1588 
1589  ret = IMultiLanguage2_GetRfc1766Info(iML2, LANG_ENGLISH, LANG_ENGLISH, NULL);
1590  ok(ret == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", ret);
1591 }
1592 
1593 static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2)
1594 {
1595  CHAR dest[MAX_PATH];
1596  CHAR invariate[MAX_PATH];
1597  UINT srcsz, destsz;
1598  HRESULT hr;
1599 
1600  static WCHAR src[] = {'a','b','c',0};
1601 
1602  memset(invariate, 'x', sizeof(invariate));
1603 
1604  /* pSrcStr NULL */
1605  memset(dest, 'x', sizeof(dest));
1606  srcsz = lstrlenW(src) + 1;
1607  destsz = sizeof(dest);
1608  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1609  &srcsz, dest, &destsz);
1610  ok(hr == S_OK || hr == E_FAIL,"expected S_OK or E_FAIL, got %08x\n",hr);
1611  if (hr == S_OK)
1612  {
1613  ok(srcsz == lstrlenW(src) + 1,
1614  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1615  }
1616  else if (hr == E_FAIL)
1617  {
1618  ok(srcsz == 0,
1619  "Expected %u, got %u\n", 0, srcsz);
1620  }
1621 
1622  ok(!memcmp(dest, invariate, sizeof(dest)),
1623  "Expected dest to be unchanged, got %s\n", dest);
1624  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1625 
1626  /* pcSrcSize NULL */
1627  memset(dest, 'x', sizeof(dest));
1628  destsz = sizeof(dest);
1629  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1630  NULL, dest, &destsz);
1631  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1632  ok(!strncmp(dest, "abc", 3),
1633  "Expected first three chars to be \"abc\"\n");
1634  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1635  "Expected rest of dest to be unchanged, got %s\n", dest);
1636  ok(destsz == lstrlenW(src),
1637  "Expected %u, got %u\n", lstrlenW(src), destsz);
1638 
1639  /* both pSrcStr and pcSrcSize NULL */
1640  memset(dest, 'x', sizeof(dest));
1641  destsz = sizeof(dest);
1642  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, NULL,
1643  NULL, dest, &destsz);
1644  ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1645  ok(!memcmp(dest, invariate, sizeof(dest)),
1646  "Expected dest to be unchanged, got %s\n", dest);
1647  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1648 
1649  /* pDstStr NULL */
1650  memset(dest, 'x', sizeof(dest));
1651  srcsz = lstrlenW(src) + 1;
1652  destsz = sizeof(dest);
1653  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1654  &srcsz, NULL, &destsz);
1655  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1656  ok(srcsz == lstrlenW(src) + 1,
1657  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1658  ok(destsz == lstrlenW(src) + 1,
1659  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1660 
1661  /* pcDstSize NULL */
1662  memset(dest, 'x', sizeof(dest));
1663  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1664  &srcsz, dest, NULL);
1665  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1666  ok(srcsz == lstrlenW(src) + 1,
1667  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1668  ok(!memcmp(dest, invariate, sizeof(dest)),
1669  "Expected dest to be unchanged, got %s\n", dest);
1670 
1671  /* pcSrcSize is 0 */
1672  memset(dest, 'x', sizeof(dest));
1673  srcsz = 0;
1674  destsz = sizeof(dest);
1675  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1676  &srcsz, dest, &destsz);
1677  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1678  ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1679  ok(!memcmp(dest, invariate, sizeof(dest)),
1680  "Expected dest to be unchanged, got %s\n", dest);
1681  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1682 
1683  /* pcSrcSize does not include NULL terminator */
1684  memset(dest, 'x', sizeof(dest));
1685  srcsz = lstrlenW(src);
1686  destsz = sizeof(dest);
1687  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1688  &srcsz, dest, &destsz);
1689  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1690  ok(srcsz == lstrlenW(src),
1691  "Expected %u, got %u\n", lstrlenW(src), srcsz);
1692  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1693  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1694  "Expected rest of dest to be unchanged, got %s\n", dest);
1695  ok(destsz == lstrlenW(src),
1696  "Expected %u, got %u\n", lstrlenW(src), destsz);
1697 
1698  /* pcSrcSize includes NULL terminator */
1699  memset(dest, 'x', sizeof(dest));
1700  srcsz = lstrlenW(src) + 1;
1701  destsz = sizeof(dest);
1702  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1703  &srcsz, dest, &destsz);
1704  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1705  ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1706  ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1707  ok(destsz == lstrlenW(src) + 1,
1708  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1709 
1710  /* pcSrcSize is -1 */
1711  memset(dest, 'x', sizeof(dest));
1712  srcsz = -1;
1713  destsz = sizeof(dest);
1714  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1715  &srcsz, dest, &destsz);
1716  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1717  ok(srcsz == lstrlenW(src),
1718  "Expected %u, got %u\n", lstrlenW(src), srcsz);
1719  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1720  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1721  "Expected rest of dest to be unchanged, got %s\n", dest);
1722  ok(destsz == lstrlenW(src),
1723  "Expected %u, got %u\n", lstrlenW(src), destsz);
1724 
1725  /* pcDstSize is 0 */
1726  memset(dest, 'x', sizeof(dest));
1727  srcsz = lstrlenW(src) + 1;
1728  destsz = 0;
1729  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1730  &srcsz, dest, &destsz);
1731  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1732  ok(srcsz == lstrlenW(src) + 1,
1733  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1734  ok(!memcmp(dest, invariate, sizeof(dest)),
1735  "Expected dest to be unchanged, got %s\n", dest);
1736  ok(destsz == lstrlenW(src) + 1,
1737  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1738 
1739  /* pcDstSize is not large enough */
1740  memset(dest, 'x', sizeof(dest));
1741  srcsz = lstrlenW(src) + 1;
1742  destsz = lstrlenW(src);
1743  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1744  &srcsz, dest, &destsz);
1745  ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1746  ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1747  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1748  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1749  "Expected rest of dest to be unchanged, got %s\n", dest);
1750  ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1751 
1752  /* pcDstSize (bytes) does not leave room for NULL terminator */
1753  memset(dest, 'x', sizeof(dest));
1754  srcsz = lstrlenW(src) + 1;
1755  destsz = lstrlenW(src) * sizeof(WCHAR);
1756  hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, src,
1757  &srcsz, dest, &destsz);
1758  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1759  ok(srcsz == lstrlenW(src) + 1,
1760  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1761  ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1762  ok(destsz == lstrlenW(src) + 1,
1763  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1764 }
1765 
1767 {
1768  CHAR dest[MAX_PATH];
1769  CHAR invariate[MAX_PATH];
1770  INT srcsz, destsz;
1771  HRESULT hr;
1772 
1773  static WCHAR src[] = {'a','b','c',0};
1774 
1775  memset(invariate, 'x', sizeof(invariate));
1776 
1777  /* lpSrcStr NULL */
1778  memset(dest, 'x', sizeof(dest));
1779  srcsz = lstrlenW(src) + 1;
1780  destsz = sizeof(dest);
1781  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, &srcsz, dest, &destsz);
1782  ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1783  if (hr == S_OK)
1784  ok(srcsz == lstrlenW(src) + 1,
1785  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1786  else if (hr == E_FAIL)
1787  ok(srcsz == 0,
1788  "Expected %u, got %u\n", 0, srcsz);
1789  ok(!memcmp(dest, invariate, sizeof(dest)),
1790  "Expected dest to be unchanged, got %s\n", dest);
1791  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1792 
1793  /* lpnWideCharCount NULL */
1794  memset(dest, 'x', sizeof(dest));
1795  destsz = sizeof(dest);
1796  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, NULL, dest, &destsz);
1797  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1798  ok(!strncmp(dest, "abc", 3),
1799  "Expected first three chars to be \"abc\"\n");
1800  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1801  "Expected rest of dest to be unchanged, got %s\n", dest);
1802  ok(destsz == lstrlenW(src),
1803  "Expected %u, got %u\n", lstrlenW(src), destsz);
1804 
1805  /* both lpSrcStr and lpnWideCharCount NULL */
1806  memset(dest, 'x', sizeof(dest));
1807  destsz = sizeof(dest);
1808  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, NULL, NULL, dest, &destsz);
1809  ok(hr == S_OK || hr == E_FAIL, "Expected S_OK or E_FAIL, got %08x\n", hr);
1810  ok(!memcmp(dest, invariate, sizeof(dest)),
1811  "Expected dest to be unchanged, got %s\n", dest);
1812  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1813 
1814  /* lpDstStr NULL */
1815  memset(dest, 'x', sizeof(dest));
1816  srcsz = lstrlenW(src) + 1;
1817  destsz = sizeof(dest);
1818  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, NULL, &destsz);
1819  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1820  ok(srcsz == lstrlenW(src) + 1,
1821  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1822  ok(destsz == lstrlenW(src) + 1,
1823  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1824 
1825  /* lpnMultiCharCount NULL */
1826  memset(dest, 'x', sizeof(dest));
1827  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, NULL);
1828  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1829  ok(srcsz == lstrlenW(src) + 1,
1830  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1831  ok(!memcmp(dest, invariate, sizeof(dest)),
1832  "Expected dest to be unchanged, got %s\n", dest);
1833 
1834  /* lpnWideCharCount is 0 */
1835  memset(dest, 'x', sizeof(dest));
1836  srcsz = 0;
1837  destsz = sizeof(dest);
1838  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1839  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1840  ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1841  ok(!memcmp(dest, invariate, sizeof(dest)),
1842  "Expected dest to be unchanged, got %s\n", dest);
1843  ok(destsz == 0, "Expected 0, got %u\n", destsz);
1844 
1845  /* lpnWideCharCount does not include NULL terminator */
1846  memset(dest, 'x', sizeof(dest));
1847  srcsz = lstrlenW(src);
1848  destsz = sizeof(dest);
1849  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1850  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1851  ok(srcsz == lstrlenW(src),
1852  "Expected %u, got %u\n", lstrlenW(src), srcsz);
1853  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1854  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1855  "Expected rest of dest to be unchanged, got %s\n", dest);
1856  ok(destsz == lstrlenW(src),
1857  "Expected %u, got %u\n", lstrlenW(src), destsz);
1858 
1859  /* lpnWideCharCount includes NULL terminator */
1860  memset(dest, 'x', sizeof(dest));
1861  srcsz = lstrlenW(src) + 1;
1862  destsz = sizeof(dest);
1863  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1864  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1865  ok(srcsz == lstrlenW(src) + 1, "Expected 3, got %u\n", srcsz);
1866  ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1867  ok(destsz == lstrlenW(src) + 1,
1868  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1869 
1870  /* lpnWideCharCount is -1 */
1871  memset(dest, 'x', sizeof(dest));
1872  srcsz = -1;
1873  destsz = sizeof(dest);
1874  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1875  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1876  ok(srcsz == lstrlenW(src),
1877  "Expected %u, got %u\n", lstrlenW(src), srcsz);
1878  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1879  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1880  "Expected rest of dest to be unchanged, got %s\n", dest);
1881  ok(destsz == lstrlenW(src),
1882  "Expected %u, got %u\n", lstrlenW(src), destsz);
1883 
1884  /* lpnMultiCharCount is 0 */
1885  memset(dest, 'x', sizeof(dest));
1886  srcsz = lstrlenW(src) + 1;
1887  destsz = 0;
1888  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1889  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1890  ok(srcsz == lstrlenW(src) + 1,
1891  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1892  ok(!memcmp(dest, invariate, sizeof(dest)),
1893  "Expected dest to be unchanged, got %s\n", dest);
1894  ok(destsz == lstrlenW(src) + 1,
1895  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1896 
1897  /* lpnMultiCharCount is not large enough */
1898  memset(dest, 'x', sizeof(dest));
1899  srcsz = lstrlenW(src) + 1;
1900  destsz = lstrlenW(src);
1901  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1902  ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1903  ok(srcsz == 0, "Expected 0, got %u\n", srcsz);
1904  ok(!strncmp(dest, "abc", 3), "Expected first three chars to be \"abc\"\n");
1905  ok(!memcmp(&dest[3], invariate, sizeof(dest) - 3),
1906  "Expected rest of dest to be unchanged, got %s\n", dest);
1907  ok(destsz == 0, "Expected 0, got %u\n", srcsz);
1908 
1909  /* lpnMultiCharCount (bytes) does not leave room for NULL terminator */
1910  memset(dest, 'x', sizeof(dest));
1911  srcsz = lstrlenW(src) + 1;
1912  destsz = lstrlenW(src) * sizeof(WCHAR);
1913  hr = pConvertINetUnicodeToMultiByte(NULL, 1252, src, &srcsz, dest, &destsz);
1914  ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1915  ok(srcsz == lstrlenW(src) + 1,
1916  "Expected %u, got %u\n", lstrlenW(src) + 1, srcsz);
1917  ok(!lstrcmpA(dest, "abc"), "Expected \"abc\", got \"%s\"\n", dest);
1918  ok(destsz == lstrlenW(src) + 1,
1919  "Expected %u, got %u\n", lstrlenW(src) + 1, destsz);
1920 }
1921 
1922 static void test_JapaneseConversion(void)
1923 {
1924  /* Data */
1925  static WCHAR unc_jp[9][12] = {
1926  {9,0x31,0x20,0x3042,0x3044,0x3046,0x3048,0x304a,0x000d,0x000a},
1927  {9,0x31,0x20,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x000d,0x000a},
1928  {9,0x31,0x20,0xff71,0xff72,0xff73,0xff74,0xff75,0x000d,0x000a},
1929  {9,0x31,0x20,0x3041,0x3043,0x3045,0x3047,0x3049,0x000d,0x000a},
1930  {9,0x31,0x20,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x000d,0x000a},
1931  {9,0x31,0x20,0xff67,0xff68,0xff69,0xff6a,0xff6b,0x000d,0x000a},
1932  {9,0x31,0x20,0x300c,0x65e5,0x672c,0x8a9e,0x300d,0x000d,0x000a},
1933  {7,0x31,0x20,0x25c7,0x25c7,0x3012,0x000d,0x000a},
1934  {11,0x31,0x20,0x203b,0x3010,0x0074,0x0065,0x0073,0x0074,0x3011,0x000d,0x000a}
1935  };
1936  static CHAR jis_jp[9][27] = {
1937  {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x22,0x24,0x24,0x24,0x26,0x24,0x28,
1938  0x24,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1939  {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1940  0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1941  {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x22,0x25,0x24,0x25,0x26,0x25,0x28,
1942  0x25,0x2a,0x1b,0x28,0x42,0x0d,0x0a},
1943  {20,0x31,0x20,0x1b,0x24,0x42,0x24,0x21,0x24,0x23,0x24,0x25,0x24,0x27,
1944  0x24,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1945  {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1946  0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1947  {20,0x31,0x20,0x1b,0x24,0x42,0x25,0x21,0x25,0x23,0x25,0x25,0x25,0x27,
1948  0x25,0x29,0x1b,0x28,0x42,0x0d,0x0a},
1949  {20,0x31,0x20,0x1b,0x24,0x42,0x21,0x56,0x46,0x7c,0x4b,0x5c,0x38,0x6c,
1950  0x21,0x57,0x1b,0x28,0x42,0x0d,0x0a},
1951  {16,0x31,0x20,0x1b,0x24,0x42,0x21,0x7e,0x21,0x7e,0x22,0x29,0x1b,0x28,
1952  0x42,0x0d,0x0a},
1953  {26,0x31,0x20,0x1b,0x24,0x42,0x22,0x28,0x21,0x5a,0x1b,0x28,0x42,0x74,
1954  0x65,0x73,0x74,0x1b,0x24,0x42,0x21,0x5b,0x1b,0x28,0x42,0x0d,0x0a}
1955  };
1956  static CHAR sjis_jp[9][15] = {
1957  {14,0x31,0x20,0x82,0xa0,0x82,0xa2,0x82,0xa4,0x82,0xa6,0x82,0xa8,0x0d,0x0a},
1958  {14,0x31,0x20,0x83,0x41,0x83,0x43,0x83,0x45,0x83,0x47,0x83,0x49,0x0d,0x0a},
1959  {9,0x31,0x20,0xb1,0xb2,0xb3,0xb4,0xb5,0x0d,0x0a},
1960  {14,0x31,0x20,0x82,0x9f,0x82,0xa1,0x82,0xa3,0x82,0xa5,0x82,0xa7,0x0d,0x0a},
1961  {14,0x31,0x20,0x83,0x40,0x83,0x42,0x83,0x44,0x83,0x46,0x83,0x48,0x0d,0x0a},
1962  {9,0x31,0x20,0xa7,0xa8,0xa9,0xaa,0xab,0x0d,0x0a},
1963  {14,0x31,0x20,0x81,0x75,0x93,0xfa,0x96,0x7b,0x8c,0xea,0x81,0x76,0x0d,0x0a},
1964  {10,0x31,0x20,0x81,0x9e,0x81,0x9e,0x81,0xa7,0x0d,0x0a},
1965  {14,0x31,0x20,0x81,0xa6,0x81,0x79,0x74,0x65,0x73,0x74,0x81,0x7a,0x0d,0x0a}
1966  };
1967  static CHAR euc_jp[9][15] = {
1968  {14,0x31,0x20,0xa4,0xa2,0xa4,0xa4,0xa4,0xa6,0xa4,0xa8,0xa4,0xaa,0x0d,0x0a},
1969  {14,0x31,0x20,0xa5,0xa2,0xa5,0xa4,0xa5,0xa6,0xa5,0xa8,0xa5,0xaa,0x0d,0x0a},
1970  {14,0x31,0x20,0x8e,0xb1,0x8e,0xb2,0x8e,0xb3,0x8e,0xb4,0x8e,0xb5,0x0d,0x0a},
1971  {14,0x31,0x20,0xa4,0xa1,0xa4,0xa3,0xa4,0xa5,0xa4,0xa7,0xa4,0xa9,0x0d,0x0a},
1972  {14,0x31,0x20,0xa5,0xa1,0xa5,0xa3,0xa5,0xa5,0xa5,0xa7,0xa5,0xa9,0x0d,0x0a},
1973  {14,0x31,0x20,0x8e,0xa7,0x8e,0xa8,0x8e,0xa9,0x8e,0xaa,0x8e,0xab,0x0d,0x0a},
1974  {14,0x31,0x20,0xa1,0xd6,0xc6,0xfc,0xcb,0xdc,0xb8,0xec,0xa1,0xd7,0x0d,0x0a},
1975  {10,0x31,0x20,0xa1,0xfe,0xa1,0xfe,0xa2,0xa9,0x0d,0x0a},
1976  {14,0x31,0x20,0xa2,0xa8,0xa1,0xda,0x74,0x65,0x73,0x74,0xa1,0xdb,0x0d,0x0a}
1977  };
1978 
1979  INT srcsz, destsz;
1980  INT i;
1981  HRESULT hr;
1982  CHAR output[30];
1983  WCHAR outputW[30];
1984  int outlen;
1985 
1986  /* test unc->jis */
1987  for (i = 0; i < 9; i++)
1988  {
1989  int j;
1990  destsz = 30;
1991  outlen = jis_jp[i][0];
1992  srcsz = unc_jp[i][0];
1993  hr = pConvertINetUnicodeToMultiByte(NULL, 50220, &unc_jp[i][1], &srcsz, output, &destsz);
1994  if (hr == S_FALSE)
1995  {
1996  skip("Code page identifier 50220 is not supported\n");
1997  break;
1998  }
1999  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
2000  ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
2001  ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
2002  ok(memcmp(output,&jis_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
2003 
2004  /* and back */
2005  srcsz = outlen;
2006  destsz = 30;
2007  hr = pConvertINetMultiByteToUnicode(NULL, 50220, output, &srcsz, outputW,&destsz);
2008 
2009  /*
2010  * JIS does not have hankata so it get automatically converted to
2011  * zenkata. this means that strings 1 and 2 are identical as well as
2012  * strings 4 and 5.
2013  */
2014  j = i;
2015  if (i == 2) j = 1;
2016  if (i == 5) j = 4;
2017 
2018  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i, hr);
2019  ok(destsz == unc_jp[j][0],"(%i) Expected %i, got %i\n",i,unc_jp[j][0],destsz);
2020  ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
2021  ok(memcmp(outputW,&unc_jp[j][1],destsz)==0,"(%i) Strings do not match\n",i);
2022  }
2023 
2024  /* test unc->sjis */
2025  for (i = 0; i < 9; i++)
2026  {
2027  destsz = 30;
2028  outlen = sjis_jp[i][0];
2029  srcsz = unc_jp[i][0];
2030 
2031  hr = pConvertINetUnicodeToMultiByte(NULL, 932, &unc_jp[i][1], &srcsz, output, &destsz);
2032  if (hr == S_FALSE)
2033  {
2034  skip("Code page identifier 932 is not supported\n");
2035  break;
2036  }
2037  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
2038  ok(destsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,destsz);
2039  ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],srcsz);
2040  ok(memcmp(output,&sjis_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
2041 
2042  srcsz = outlen;
2043  destsz = 30;
2044  hr = pConvertINetMultiByteToUnicode(NULL, 932, output, &srcsz, outputW,&destsz);
2045 
2046  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n", i, hr);
2047  ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
2048  ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
2049  ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
2050  }
2051 
2052  /* test unc->euc */
2053  for (i = 0; i < 9; i++)
2054  {
2055  destsz = 30;
2056  outlen = euc_jp[i][0];
2057  srcsz = unc_jp[i][0];
2058 
2059  hr = pConvertINetUnicodeToMultiByte(NULL, 51932, &unc_jp[i][1], &srcsz, output, &destsz);
2060  if (hr == S_FALSE)
2061  {
2062  skip("Code page identifier 51932 is not supported\n");
2063  break;
2064  }
2065  ok(hr == S_OK, "(%i) Expected S_OK, got %08x\n",i,hr);
2066  ok(destsz == outlen, "(%i) Expected %i, got %i\n",i,outlen,destsz);
2067  ok(srcsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
2068  ok(memcmp(output,&euc_jp[i][1],outlen)==0,"(%i) Strings do not match\n",i);
2069 
2070  srcsz = outlen;
2071  destsz = 30;
2072  hr = pConvertINetMultiByteToUnicode(NULL, 51932, output, &srcsz, outputW,&destsz);
2073 
2074  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
2075  ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
2076  ok(srcsz == outlen,"(%i) Expected %i, got %i\n",i,outlen,srcsz);
2077  ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
2078  }
2079 
2080  /* Japanese autodetect */
2081  i = 0;
2082  destsz = 30;
2083  srcsz = jis_jp[i][0];
2084  hr = pConvertINetMultiByteToUnicode(NULL, 50932, &jis_jp[i][1], &srcsz, outputW, &destsz);
2085  if (hr == S_FALSE)
2086  {
2087  skip("Code page identifier 50932 is not supported\n");
2088  return;
2089  }
2090  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
2091  ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
2092  ok(srcsz == jis_jp[i][0],"(%i) Expected %i, got %i\n",i,jis_jp[i][0],srcsz);
2093  ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
2094 
2095  i = 1;
2096  destsz = 30;
2097  srcsz = sjis_jp[i][0];
2098  hr = pConvertINetMultiByteToUnicode(NULL, 50932, &sjis_jp[i][1], &srcsz, outputW, &destsz);
2099  ok(hr == S_OK,"(%i) Expected S_OK, got %08x\n",i,hr);
2100  ok(destsz == unc_jp[i][0],"(%i) Expected %i, got %i\n",i,unc_jp[i][0],destsz);
2101  ok(srcsz == sjis_jp[i][0],"(%i) Expected %i, got %i\n",i,sjis_jp[i][0],srcsz);
2102  ok(memcmp(outputW,&unc_jp[i][1],destsz)==0,"(%i) Strings do not match\n",i);
2103 }
2104 
2105 static void test_GetScriptFontInfo(IMLangFontLink2 *font_link)
2106 {
2107  HRESULT hr;
2108  UINT nfonts;
2109  SCRIPTFONTINFO sfi[1];
2110 
2111  nfonts = 0;
2112  hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, 0, &nfonts, NULL);
2113  ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
2114  ok(nfonts, "unexpected result\n");
2115 
2116  nfonts = 0;
2117  hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, NULL);
2118  ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
2119  ok(nfonts, "unexpected result\n");
2120 
2121  nfonts = 0;
2122  hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, NULL);
2123  ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
2124  ok(nfonts, "unexpected result\n");
2125 
2126  nfonts = 1;
2127  memset(sfi, 0, sizeof(sfi));
2128  hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_FIXED_FONT, &nfonts, sfi);
2129  ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
2130  ok(nfonts == 1, "got %u, expected 1\n", nfonts);
2131  ok(sfi[0].scripts != 0, "unexpected result\n");
2132  ok(sfi[0].wszFont[0], "unexpected result\n");
2133 
2134  nfonts = 1;
2135  memset(sfi, 0, sizeof(sfi));
2136  hr = IMLangFontLink2_GetScriptFontInfo(font_link, sidAsciiLatin, SCRIPTCONTF_PROPORTIONAL_FONT, &nfonts, sfi);
2137  ok(hr == S_OK, "GetScriptFontInfo failed %u\n", GetLastError());
2138  ok(nfonts == 1, "got %u, expected 1\n", nfonts);
2139  ok(sfi[0].scripts != 0, "unexpected result\n");
2140  ok(sfi[0].wszFont[0], "unexpected result\n");
2141 }
2142 
2143 static void test_CodePageToScriptID(IMLangFontLink2 *font_link)
2144 {
2145  HRESULT hr;
2146  UINT i;
2147  SCRIPT_ID sid;
2148  static const struct
2149  {
2150  UINT cp;
2151  SCRIPT_ID sid;
2152  HRESULT hr;
2153  }
2154  cp_sid[] =
2155  {
2156  {874, sidThai},
2157  {932, sidKana},
2158  {936, sidHan},
2159  {949, sidHangul},
2160  {950, sidBopomofo},
2161  {1250, sidAsciiLatin},
2162  {1251, sidCyrillic},
2163  {1252, sidAsciiLatin},
2164  {1253, sidGreek},
2165  {1254, sidAsciiLatin},
2166  {1255, sidHebrew},
2167  {1256, sidArabic},
2168  {1257, sidAsciiLatin},
2169  {1258, sidAsciiLatin},
2170  {CP_UNICODE, 0, E_FAIL}
2171  };
2172 
2173  for (i = 0; i < ARRAY_SIZE(cp_sid); i++)
2174  {
2175  hr = IMLangFontLink2_CodePageToScriptID(font_link, cp_sid[i].cp, &sid);
2176  ok(hr == cp_sid[i].hr, "%u CodePageToScriptID failed 0x%08x %u\n", i, hr, GetLastError());
2177  if (SUCCEEDED(hr))
2178  {
2179  ok(sid == cp_sid[i].sid,
2180  "%u got sid %u for codepage %u, expected %u\n", i, sid, cp_sid[i].cp, cp_sid[i].sid);
2181  }
2182  }
2183 }
2184 
2185 static void test_GetFontUnicodeRanges(IMLangFontLink2 *font_link)
2186 {
2187  HRESULT hr;
2188  UINT count;
2189  HFONT hfont, old_hfont;
2190  LOGFONTA lf;
2191  HDC hdc;
2192  UNICODERANGE *ur;
2193 
2194  hdc = CreateCompatibleDC(0);
2195  memset(&lf, 0, sizeof(lf));
2196  lstrcpyA(lf.lfFaceName, "Arial");
2197  hfont = CreateFontIndirectA(&lf);
2198  old_hfont = SelectObject(hdc, hfont);
2199 
2200  count = 0;
2201  hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, NULL, &count, NULL);
2202  ok(hr == E_FAIL, "expected E_FAIL, got 0x%08x\n", hr);
2203 
2204  hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, NULL, NULL);
2205  ok(hr == E_INVALIDARG, "expected E_FAIL, got 0x%08x\n", hr);
2206 
2207  count = 0;
2208  hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, NULL);
2209  ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2210  ok(count, "expected count > 0\n");
2211 
2212  ur = HeapAlloc(GetProcessHeap(), 0, sizeof(*ur) * count);
2213 
2214  hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur);
2215  ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2216 
2217  count--;
2218  hr = IMLangFontLink2_GetFontUnicodeRanges(font_link, hdc, &count, ur);
2219  ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2220 
2221  HeapFree(GetProcessHeap(), 0, ur);
2222 
2223  SelectObject(hdc, old_hfont);
2225  DeleteDC(hdc);
2226 }
2227 
2228 static void test_IsCodePageInstallable(IMultiLanguage2 *ml2)
2229 {
2230  UINT i;
2231  HRESULT hr;
2232 
2233  for (i = 0; i < 0xffff; i++)
2234  {
2235  hr = IMultiLanguage2_IsCodePageInstallable(ml2, i);
2236 
2237  /* it would be better to use IMultiLanguage2_ValidateCodePageEx here but that brings
2238  * up an installation dialog on some platforms, even when specifying CPIOD_PEEK.
2239  */
2240  if (IsValidCodePage(i))
2241  ok(hr == S_OK ||
2242  broken(hr == S_FALSE) || /* win2k */
2243  broken(hr == E_INVALIDARG), /* win2k */
2244  "code page %u is valid but not installable 0x%08x\n", i, hr);
2245  }
2246 }
2247 
2249 {
2250  HRESULT ret;
2251  void *unknown;
2252 
2254  ok(ret == E_INVALIDARG, "expected E_INVALIDARG got %#x\n", ret);
2255 
2256  unknown = (void *)0xdeadbeef;
2258 todo_wine {
2259  ok(ret == S_OK, "expected S_OK got %#x\n", ret);
2260  ok(unknown != NULL && unknown != (void *)0xdeadbeef,
2261  "GetGlobalFontLinkObject() returned %p\n", unknown);
2262  }
2263 }
2264 
2265 static void test_IMLangConvertCharset(IMultiLanguage *ml)
2266 {
2267  IMLangConvertCharset *convert;
2268  WCHAR strW[] = {'a','b','c','d',0};
2269  UINT cp, src_size, dst_size;
2270  char strA[] = "abcd";
2271  WCHAR buffW[20];
2272  HRESULT hr;
2273 
2274  hr = IMultiLanguage_CreateConvertCharset(ml, CP_ACP, CP_UTF8, 0, &convert);
2275 todo_wine
2276  ok(hr == S_FALSE, "expected S_FALSE got 0x%08x\n", hr);
2277 
2278  hr = IMLangConvertCharset_GetSourceCodePage(convert, NULL);
2279  ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2280 
2281  cp = CP_UTF8;
2282  hr = IMLangConvertCharset_GetSourceCodePage(convert, &cp);
2283  ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
2284  ok(cp == CP_ACP, "got %d\n", cp);
2285 
2286  hr = IMLangConvertCharset_GetDestinationCodePage(convert, NULL);
2287  ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2288 
2289  cp = CP_ACP;
2290  hr = IMLangConvertCharset_GetDestinationCodePage(convert, &cp);
2291  ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
2292  ok(cp == CP_UTF8, "got %d\n", cp);
2293 
2294  /* DoConversionToUnicode */
2295  hr = IMLangConvertCharset_Initialize(convert, CP_UTF8, CP_UNICODE, 0);
2296  ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
2297 
2298  hr = IMLangConvertCharset_DoConversionToUnicode(convert, NULL, NULL, NULL, NULL);
2299  ok(hr == E_FAIL || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
2300 
2301  src_size = -1;
2302  dst_size = 20;
2303  buffW[0] = 0;
2304  buffW[4] = 4;
2305  hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size);
2306  ok(hr == S_OK, "got 0x%08x\n", hr);
2307  ok(!memcmp(buffW, strW, 4*sizeof(WCHAR)), "got converted string %s\n", wine_dbgstr_wn(buffW, dst_size));
2308  ok(dst_size == 4, "got %d\n", dst_size);
2309  ok(buffW[4] == 4, "got %d\n", buffW[4]);
2310  ok(src_size == 4, "got %d\n", src_size);
2311 
2312  src_size = -1;
2313  dst_size = 0;
2314  buffW[0] = 1;
2315  hr = IMLangConvertCharset_DoConversionToUnicode(convert, strA, &src_size, buffW, &dst_size);
2316  ok(hr == S_OK, "got 0x%08x\n", hr);
2317  ok(buffW[0] == 1, "got %d\n", buffW[0]);
2318  ok(dst_size == 4, "got %d\n", dst_size);
2319  ok(src_size == 4, "got %d\n", src_size);
2320 
2321  hr = IMLangConvertCharset_Initialize(convert, CP_UNICODE, CP_UNICODE, 0);
2322  ok(hr == S_OK, "expected S_OK got 0x%08x\n", hr);
2323 
2324  IMLangConvertCharset_Release(convert);
2325 }
2326 
2327 static const char stream_data[] = "VCARD2.1test;test";
2329 
2331 {
2332  ok(FALSE, "unexpected call\n");
2333  return E_NOINTERFACE;
2334 }
2335 
2337 {
2338  ok(FALSE, "unexpected call\n");
2339  return 2;
2340 }
2341 
2343 {
2344  ok(FALSE, "unexpected call\n");
2345  return 1;
2346 }
2347 
2349 {
2350  ULONG size;
2351 
2352  if (stream_pos == sizeof(stream_data) - 1)
2353  {
2354  *read = 0;
2355  return S_FALSE;
2356  }
2357  size = min(sizeof(stream_data) - 1 - stream_pos, len);
2359  stream_pos += size;
2360  *read = size;
2361  return S_OK;
2362 }
2363 
2364 static HRESULT WINAPI stream_Write(IStream *iface, const void *buf, ULONG len, ULONG *written)
2365 {
2366  ok(FALSE, "unexpected call\n");
2367  return E_NOTIMPL;
2368 }
2369 
2371  ULARGE_INTEGER *newpos)
2372 {
2373  if (origin == STREAM_SEEK_SET)
2374  stream_pos = move.QuadPart;
2375  else if (origin == STREAM_SEEK_CUR)
2376  stream_pos += move.QuadPart;
2377  else if (origin == STREAM_SEEK_END)
2378  stream_pos = sizeof(stream_data) - 1 - move.QuadPart;
2379 
2380  if (newpos) newpos->QuadPart = stream_pos;
2381  return S_OK;
2382 }
2383 
2385 {
2386  ok(FALSE, "unexpected call\n");
2387  return E_NOTIMPL;
2388 }
2389 
2391  ULARGE_INTEGER *read, ULARGE_INTEGER *written)
2392 {
2393  ok(FALSE, "unexpected call\n");
2394  return E_NOTIMPL;
2395 }
2396 
2398 {
2399  ok(FALSE, "unexpected call\n");
2400  return E_NOTIMPL;
2401 }
2402 
2404 {
2405  ok(FALSE, "unexpected call\n");
2406  return E_NOTIMPL;
2407 }
2408 
2410  ULARGE_INTEGER len, DWORD locktype)
2411 {
2412  ok(FALSE, "unexpected call\n");
2413  return E_NOTIMPL;
2414 }
2415 
2417  ULARGE_INTEGER len, DWORD locktype)
2418 {
2419  ok(FALSE, "unexpected call\n");
2420  return E_NOTIMPL;
2421 }
2422 
2423 static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stg, DWORD flag)
2424 {
2425  ok(FALSE, "unexpected call\n");
2426  return E_NOTIMPL;
2427 }
2428 
2430 {
2431  ok(FALSE, "unexpected call\n");
2432  return E_NOTIMPL;
2433 }
2434 
2435 static const IStreamVtbl stream_vtbl =
2436 {
2438  stream_AddRef,
2440  stream_Read,
2441  stream_Write,
2442  stream_Seek,
2444  stream_CopyTo,
2445  stream_Commit,
2446  stream_Revert,
2449  stream_Stat,
2450  stream_Clone
2451 };
2452 
2454 
2455 static void test_DetectOutboundCodePageInIStream(IMultiLanguage3 *ml)
2456 {
2457  HRESULT hr;
2458  UINT nb_detected, detected[4];
2459  UINT preferred[] = {1250,1251,1252,65001};
2460  UINT preferred2[] = {1250,1251,1252};
2461 
2462  nb_detected = 0;
2463  memset(detected, 0, sizeof(detected));
2464  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2465  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2466  ARRAY_SIZE(preferred), detected, &nb_detected, NULL);
2467  ok(hr == E_INVALIDARG, "got %08x\n", hr);
2468 
2469  nb_detected = 1;
2470  memset(detected, 0, sizeof(detected));
2471  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2472  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2473  ARRAY_SIZE(preferred), NULL, &nb_detected, NULL);
2474  ok(hr == E_INVALIDARG, "got %08x\n", hr);
2475 
2476  nb_detected = 1;
2477  memset(detected, 0, sizeof(detected));
2478  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2479  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2480  ARRAY_SIZE(preferred), detected, &nb_detected, NULL);
2481  ok(hr == S_OK, "got %08x\n", hr);
2482  ok(nb_detected == 1, "got %u\n", nb_detected);
2483  ok(detected[0] == 65001, "got %u\n", detected[0]);
2484 
2485  nb_detected = 2;
2486  memset(detected, 0, sizeof(detected));
2487  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2488  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2489  ARRAY_SIZE(preferred), detected, &nb_detected, NULL);
2490  ok(hr == S_OK, "got %08x\n", hr);
2491  todo_wine ok(nb_detected == 2, "got %u\n", nb_detected);
2492  ok(detected[0] == 65001, "got %u\n", detected[0]);
2493  todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]);
2494 
2495  nb_detected = 3;
2496  memset(detected, 0, sizeof(detected));
2497  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2498  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2499  ARRAY_SIZE(preferred), detected, &nb_detected, NULL);
2500  ok(hr == S_OK, "got %08x\n", hr);
2501  todo_wine ok(nb_detected == 3, "got %u\n", nb_detected);
2502  ok(detected[0] == 65001, "got %u\n", detected[0]);
2503  todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]);
2504  todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]);
2505 
2506  nb_detected = 4;
2507  memset(detected, 0, sizeof(detected));
2508  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2509  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred,
2510  ARRAY_SIZE(preferred), detected, &nb_detected, NULL);
2511  ok(hr == S_OK, "got %08x\n", hr);
2512  todo_wine ok(nb_detected == 3, "got %u\n", nb_detected);
2513  ok(detected[0] == 65001, "got %u\n", detected[0]);
2514  todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]);
2515  todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]);
2516  ok(detected[3] == 0, "got %u\n", detected[3]);
2517 
2518  nb_detected = 3;
2519  memset(detected, 0, sizeof(detected));
2520  hr = IMultiLanguage3_DetectOutboundCodePageInIStream(ml,
2521  MLDETECTF_PRESERVE_ORDER, &test_stream, preferred2,
2522  ARRAY_SIZE(preferred2), detected, &nb_detected, NULL);
2523  ok(hr == S_OK, "got %08x\n", hr);
2524  todo_wine ok(nb_detected == 3, "got %u\n", nb_detected);
2525  ok(detected[0] == 65001, "got %u\n", detected[0]);
2526  todo_wine ok(detected[1] == 65000, "got %u\n", detected[1]);
2527  todo_wine ok(detected[2] == 1200, "got %u\n", detected[2]);
2528 }
2529 
2530 static void test_GetCodePageInfo(IMultiLanguage2 *iML2)
2531 {
2532  static const DWORD VALID_MASK = (DWORD)(~(MIMECONTF_VALID_NLS | MIMECONTF_VALID));
2533 
2534  const struct cpinfo_test_data *test_data = NULL;
2535  UINT test_data_num;
2536  MIMECPINFO cpinfo_cmp;
2537  MIMECPINFO cpinfo;
2538  UINT i;
2539  HRESULT ret;
2540 
2542  test_data_num = ARRAY_SIZE(iml2_cpinfo_data);
2543  for (i = 0; i < test_data_num; i++)
2544  {
2545  ret = IMultiLanguage2_GetCodePageInfo(iML2, test_data[i].cpinfo.uiCodePage, LANG_NEUTRAL, &cpinfo);
2547  ok(ret == S_OK, "%d: IMultiLanguage2_GetCodePageInfo failed: 0x%08x.\n", i, ret);
2548 
2549  if (ret == S_OK)
2550  {
2551  cpinfo_cmp = test_data[i].cpinfo;
2553  ok((cpinfo.dwFlags == cpinfo_cmp.dwFlags ) ||
2554  /* some code pages are not installed on the Wine Test Bot */
2555  ((cpinfo.dwFlags & VALID_MASK) == (cpinfo_cmp.dwFlags & VALID_MASK)),
2556  "%d: got wrong dwFlags expected 0x%x return 0x%x.\n",
2557  i, cpinfo_cmp.dwFlags, cpinfo.dwFlags);
2558  ok(cpinfo.uiCodePage == cpinfo_cmp.uiCodePage,
2559  "%d: got wrong uiCodePage expected %u return %u.\n",
2560  i, cpinfo_cmp.uiCodePage, cpinfo.uiCodePage);
2562  ok(cpinfo.uiFamilyCodePage == cpinfo_cmp.uiFamilyCodePage,
2563  "%d: got wrong uiFamilyCodePage expected %u return %u.\n",
2564  i, cpinfo_cmp.uiFamilyCodePage, cpinfo.uiFamilyCodePage);
2565 
2567  ok(!lstrcmpW(cpinfo.wszWebCharset, cpinfo_cmp.wszWebCharset),
2568  "%d: got wrong wszWebCharset expected %s return %s.\n",
2569  i, wine_dbgstr_w(cpinfo_cmp.wszWebCharset), wine_dbgstr_w(cpinfo.wszWebCharset));
2571  ok(!lstrcmpW(cpinfo.wszHeaderCharset, cpinfo_cmp.wszHeaderCharset),
2572  "%d: got wrong wszHeaderCharset expected %s return %s.\n",
2573  i, wine_dbgstr_w(cpinfo_cmp.wszHeaderCharset), wine_dbgstr_w(cpinfo.wszHeaderCharset));
2575  ok(!lstrcmpW(cpinfo.wszBodyCharset, cpinfo_cmp.wszBodyCharset),
2576  "%d: got wrong wszBodyCharset expected %s return %s.\n",
2577  i, wine_dbgstr_w(cpinfo_cmp.wszBodyCharset), wine_dbgstr_w(cpinfo.wszBodyCharset));
2578 
2581  {
2582  /* FIXME: Windows returns description and font name in system's language */
2583  skip("Non-English locale\n");
2584  }
2585  else
2586  {
2588  ok(!lstrcmpW(cpinfo.wszDescription, cpinfo_cmp.wszDescription),
2589  "%d: got wrong wszDescription expected %s return %s.\n",
2590  i, wine_dbgstr_w(cpinfo_cmp.wszDescription), wine_dbgstr_w(cpinfo.wszDescription));
2592  ok(!lstrcmpW(cpinfo.wszFixedWidthFont, cpinfo_cmp.wszFixedWidthFont),
2593  "%d: got wrong wszFixedWidthFont expected %s return %s.\n",
2594  i, wine_dbgstr_w(cpinfo_cmp.wszFixedWidthFont), wine_dbgstr_w(cpinfo.wszFixedWidthFont));
2596  ok(!lstrcmpW(cpinfo.wszProportionalFont, cpinfo_cmp.wszProportionalFont),
2597  "%d: got wrong wszProportionalFont expected %s return %s.\n",
2598  i, wine_dbgstr_w(cpinfo_cmp.wszProportionalFont), wine_dbgstr_w(cpinfo.wszProportionalFont));
2599  }
2600  }
2601  }
2602 }
2603 
2604 static void test_MapFont(IMLangFontLink *font_link, IMLangFontLink2 *font_link2)
2605 {
2606  HFONT old_font = NULL;
2607  HFONT new_font = NULL;
2608  HFONT last_font = NULL;
2609  HFONT font1 = NULL;
2610  HFONT font2 = NULL;
2611  DWORD codepages;
2612  DWORD font_codepages;
2613  HRESULT ret;
2614  HDC hdc;
2615  WCHAR ch;
2616 
2617  hdc = GetDC(NULL);
2618  codepages = FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC | FS_GREEK | FS_TURKISH |
2621  old_font = GetCurrentObject(hdc, OBJ_FONT);
2622  ch = 0xfeed;
2623 
2624  /* Tests for IMLangFontLink */
2625 
2626  ret = IMLangFontLink_ResetFontMapping(font_link);
2627  ok(ret == S_OK, "IMLangFontLink_ResetFontMapping: expected S_OK, got %08x\n", ret);
2628 
2629  ret = IMLangFontLink_MapFont(font_link, NULL, 0, NULL, NULL);
2630  ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret);
2631  ret = IMLangFontLink_MapFont(font_link, NULL, codepages, old_font, &new_font);
2632  ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret);
2633  ret = IMLangFontLink_MapFont(font_link, hdc, codepages, NULL, &new_font);
2634  ok(ret == E_FAIL, "IMLangFontLink_MapFont: expected E_FAIL, got %08x\n", ret);
2635 
2636  ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, NULL);
2637  ok(ret == S_OK, "IMLangFontLink_MapFont: expected S_OK, got %08x\n", ret);
2638  ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &new_font);
2639  ok(ret == S_OK && new_font != NULL, "IMLangFontLink_MapFont: expected S_OK/!NULL, got %08x/%p\n", ret, new_font);
2640  last_font = new_font;
2641  ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &new_font);
2642  ok(ret == S_OK && new_font == last_font, "IMLangFontLink_MapFont: expected S_OK/%p, got %08x/%p\n", last_font, ret, new_font);
2643 
2644  ret = IMLangFontLink_ReleaseFont(font_link, NULL);
2645  ok(ret == E_FAIL, "IMLangFontLink_ReleaseFont: expected E_FAIL, got %08x\n", ret);
2646  ret = IMLangFontLink_ReleaseFont(font_link, new_font);
2647  ok(ret == S_OK, "IMLangFontLink_ReleaseFont: expected S_OK, got %08x\n", ret);
2648  ret = IMLangFontLink_ResetFontMapping(font_link);
2649  ok(ret == S_OK, "IMLangFontLink_ResetFontMapping: expected S_OK, got %08x\n", ret);
2650 
2651  /* Tests for IMLangFontLink2 */
2652 
2653  ret = IMLangFontLink2_ResetFontMapping(font_link2);
2654  ok(ret == S_OK, "IMLangFontLink2_ResetFontMapping: expected S_OK, got %08x\n", ret);
2655 
2656  ret = IMLangFontLink2_MapFont(font_link2, NULL, 0, 0, NULL);
2657  ok(ret == E_FAIL, "IMLangFontLink2_MapFont: expected E_FAIL, got %08x\n", ret);
2658  ret = IMLangFontLink2_MapFont(font_link2, NULL, codepages, ch, &new_font);
2659  ok(ret == E_FAIL, "IMLangFontLink2_MapFont: expected E_FAIL, got %08x\n", ret);
2660  ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, 0, NULL);
2661  ok(ret == E_INVALIDARG, "IMLangFontLink2_MapFont: expected E_INVALIDARG, got %08x\n", ret);
2662  ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, ch, NULL);
2663  ok(ret == E_INVALIDARG, "IMLangFontLink2_MapFont: expected E_INVALIDARG, got %08x\n", ret);
2664 
2665  ret = IMLangFontLink2_MapFont(font_link2, hdc, 0, ch, &new_font);
2666  todo_wine
2667  ok(ret == S_OK || broken(ret == E_FAIL), /* got E_FAIL on winxp and win2k */
2668  "IMLangFontLink2_MapFont: expected S_OK || E_FAIL, got %08x\n", ret);
2669  ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, NULL);
2670  ok(ret == S_OK, "IMLangFontLink2_MapFont: expected S_OK, got %08x\n", ret);
2671  ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &new_font);
2672  ok(ret == S_OK && new_font != NULL, "IMLangFontLink2_MapFont: expected S_OK/!NULL, got %08x/%p\n", ret, new_font);
2673  last_font = new_font;
2674  ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &new_font);
2675  ok(ret == S_OK && new_font == last_font, "IMLangFontLink2_MapFont: expected S_OK/%p, got %08x/%p\n", last_font, ret, new_font);
2676 
2677  ret = IMLangFontLink2_ReleaseFont(font_link2, NULL);
2678  ok(ret == E_FAIL, "IMLangFontLink2_ReleaseFont: expected E_FAIL, got %08x\n", ret);
2679  ret = IMLangFontLink2_ReleaseFont(font_link2, new_font);
2680  ok(ret == S_OK, "IMLangFontLink2_ReleaseFont: expected S_OK, got %08x\n", ret);
2681  ret = IMLangFontLink2_ResetFontMapping(font_link2);
2682  ok(ret == S_OK, "IMLangFontLink2_ResetFontMapping: expected S_OK, got %08x\n", ret);
2683 
2684  /* Show that the font cache is global */
2685  ret = IMLangFontLink_MapFont(font_link, hdc, codepages, old_font, &font1);
2686  ok(ret == S_OK, "MapFont() failed, hr %#x.\n", ret);
2687  ret = IMLangFontLink2_MapFont(font_link2, hdc, codepages, 0, &font2);
2688  ok(ret == S_OK, "MapFont() failed, hr %#x.\n", ret);
2689  ok(font1 != NULL && font2 != NULL, "expected !NULL/!NULL, got %p/%p\n", font1, font2);
2690  ok(font1 == font2, "expected equal, got not equal\n");
2691 
2692  IMLangFontLink_GetFontCodePages(font_link, hdc, font1, &font_codepages);
2693  ok((codepages & (~font_codepages)) != 0 && (codepages & font_codepages) != 0,
2694  "code pages of font is incorrect\n");
2695 
2696  IMLangFontLink_ResetFontMapping(font_link);
2697  IMLangFontLink2_ResetFontMapping(font_link2);
2698  ReleaseDC(NULL, hdc);
2699 }
2700 
2702 {
2703  IMultiLanguage *iML = NULL;
2704  IMultiLanguage2 *iML2 = NULL;
2705  IMultiLanguage3 *iML3 = NULL;
2706  IMLangFontLink *iMLFL = NULL;
2707  IMLangFontLink2 *iMLFL2 = NULL;
2708  HRESULT ret;
2709 
2710  if (!init_function_ptrs())
2711  return;
2712 
2713  CoInitialize(NULL);
2716 
2719 
2721 
2722  trace("IMultiLanguage\n");
2723  ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2724  &IID_IMultiLanguage, (void **)&iML);
2725  if (ret != S_OK || !iML) return;
2726 
2727  test_GetNumberOfCodePageInfo((IMultiLanguage2 *)iML);
2730  IMultiLanguage_Release(iML);
2731 
2732 
2733  /* IMultiLanguage2 (IE5.0 and above) */
2734  trace("IMultiLanguage2\n");
2735  ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2736  &IID_IMultiLanguage2, (void **)&iML2);
2737  if (ret != S_OK || !iML2) return;
2738 
2739  test_rfc1766(iML2);
2742  test_GetRfc1766Info(iML2);
2744  test_GetCodePageInfo(iML2);
2745 
2746  test_EnumCodePages(iML2, 0);
2747  test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST);
2748  test_EnumCodePages(iML2, MIMECONTF_BROWSER);
2749  test_EnumCodePages(iML2, MIMECONTF_MINIMAL);
2750  test_EnumCodePages(iML2, MIMECONTF_VALID);
2751  /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
2752  /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
2753 
2754  test_EnumScripts(iML2, 0);
2755  test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER);
2756  test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM);
2757 
2758  ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE);
2759  ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08x\n", ret);
2760  ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, CP_UTF8);
2761  ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> CP_UTF8) = %08x\n", ret);
2762 
2765 
2767 
2768  IMultiLanguage2_Release(iML2);
2769 
2770 
2771  /* IMLangFontLink */
2772  ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2773  &IID_IMLangFontLink, (void **)&iMLFL);
2774  if (ret != S_OK || !iMLFL) return;
2775 
2776  IMLangFontLink_Test(iMLFL);
2777 
2778  /* IMLangFontLink2 */
2779  ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2780  &IID_IMLangFontLink2, (void **)&iMLFL2);
2781  if (ret != S_OK || !iMLFL2) return;
2782 
2783  test_GetScriptFontInfo(iMLFL2);
2784  test_GetFontUnicodeRanges(iMLFL2);
2785  test_CodePageToScriptID(iMLFL2);
2786  test_MapFont(iMLFL, iMLFL2);
2787 
2788  IMLangFontLink_Release(iMLFL);
2789  IMLangFontLink2_Release(iMLFL2);
2790 
2791  trace("IMultiLanguage3\n");
2792  ret = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
2793  &IID_IMultiLanguage3, (void **)&iML3);
2794  if (ret == S_OK)
2795  {
2797  IMultiLanguage3_Release(iML3);
2798  }
2799 
2800  CoUninitialize();
2801 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
static LPCPINFOEXA
Definition: mlang.c:45
static void test_DetectOutboundCodePageInIStream(IMultiLanguage3 *ml)
Definition: mlang.c:2455
static const WCHAR fr_enca[]
Definition: mlang.c:152
static const WCHAR fr_engb[]
Definition: mlang.c:154
char strA[12]
Definition: clipboard.c:2028
#define trace(...)
Definition: kmt_test.h:217
static const WCHAR de_en[]
Definition: mlang.c:117
static const WCHAR en_deat[]
Definition: mlang.c:146
#define REFIID
Definition: guiddef.h:113
#define TRUE
Definition: types.h:120
LPCSTR rfc1766
Definition: mlang.c:112
static UCHAR ULONG UCHAR ULONG UCHAR * output
Definition: bcrypt.c:29
static BOOL init_function_ptrs(void)
Definition: mlang.c:544
#define E_NOINTERFACE
Definition: winerror.h:2364
#define FS_BALTIC
Definition: wingdi.h:566
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define FS_VIETNAMESE
Definition: wingdi.h:567
CFF_Charset charset
Definition: cffcmap.c:138
#define SUBLANG_GERMAN
Definition: nls.h:251
#define WideCharToMultiByte
Definition: compat.h:101
BOOL todo_dwFlags
Definition: mlang.c:237
HRESULT hr
Definition: shlfolder.c:183
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos)
Definition: mlang.c:2370
HDC WINAPI GetDC(_In_opt_ HWND)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
LCID broken_lcid
Definition: mlang.c:57
HFONT WINAPI CreateFontIndirectA(_In_ const LOGFONTA *)
REFIID riid
Definition: precomp.h:44
HRESULT hr
Definition: mlang.c:56
#define LANG_NEUTRAL
Definition: nls.h:22
#define FS_CHINESESIMP
Definition: wingdi.h:570
#define CP_ACP
Definition: compat.h:99
#define LOCALE_USER_DEFAULT
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
GLuint GLuint GLsizei count
Definition: gl.h:1545
int other
Definition: msacm.c:1364
static void test_ConvertINetUnicodeToMultiByte(void)
Definition: mlang.c:1766
int en
Definition: doserrmap.h:8
#define FS_CHINESETRAD
Definition: wingdi.h:572
char CHAR
Definition: xmlstorage.h:175
#define SUBLANG_DEFAULT
Definition: nls.h:168
static void test_GetCodePageInfo(IMultiLanguage2 *iML2)
Definition: mlang.c:2530
static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stg, DWORD flag)
Definition: mlang.c:2423
static HDC
Definition: imagelist.c:92
GLintptr offset
Definition: glext.h:5920
static void test_GetNumberOfCodePageInfo(IMultiLanguage2 *iML2)
Definition: mlang.c:1437
static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags)
Definition: mlang.c:2397
BOOL todo
Definition: filedlg.c:313
#define wine_dbgstr_w
Definition: kernel32.h:34
static void test_GetCharsetInfo_other(IMultiLanguage *ml)
Definition: mlang.c:1014
GLdouble n
Definition: glext.h:7729
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER newsize)
Definition: mlang.c:2384
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
FT_UInt sid
Definition: cffcmap.c:139
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
BOOL todo_wszWebCharset
Definition: mlang.c:240
voidpf uLong int origin
Definition: ioapi.h:142
MIMECPINFO cpinfo
Definition: mlang.c:234
GLuint buffer
Definition: glext.h:5915
#define FS_CYRILLIC
Definition: wingdi.h:561
BOOL todo_uiFamilyCodePage
Definition: mlang.c:238
static const WCHAR fr_dech[]
Definition: mlang.c:166
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
#define WC_DEFAULTCHAR
Definition: unicode.h:45
DWORD LCID
Definition: nls.h:13
WORD LANGID
Definition: typedefs.h:79
OLECHAR * BSTR
Definition: compat.h:1934
static void test_GetGlobalFontLinkObject(void)
Definition: mlang.c:2248
static DWORD
Definition: mlang.c:45
static const info_table_entry info_table[]
Definition: mlang.c:169
static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype)
Definition: mlang.c:2416
int32_t INT_PTR
Definition: typedefs.h:62
static ULONG stream_pos
Definition: mlang.c:2328
static const WCHAR autoW[]
Definition: htmlbody.c:590
HRESULT WINAPI GetGlobalFontLinkObject(void **unknown)
Definition: mlang.c:4001
#define SUBLANG_NEUTRAL
Definition: nls.h:167
#define lstrlenW
Definition: compat.h:407
#define E_FAIL
Definition: ddrawi.h:102
#define FS_LATIN2
Definition: wingdi.h:560
int winetest_debug
int32_t INT
Definition: typedefs.h:56
static const WCHAR fr_deat[]
Definition: mlang.c:164
static const WCHAR stringW[]
Definition: engine.c:36
#define SUBLANG_ENGLISH_US
Definition: nls.h:222
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:194
static void scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2)
Definition: mlang.c:1059
struct _test_info info[]
Definition: SetCursorPos.c:19
static const WCHAR fr_de2[]
Definition: mlang.c:162
static void test_LcidToRfc1766(void)
Definition: mlang.c:1487
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static const WCHAR en_enus[]
Definition: mlang.c:142
LPCWSTR localename
Definition: mlang.c:113
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define CP_UTF8
Definition: nls.h:20
static const WCHAR asciiW[]
Definition: mlang.c:397
unsigned int BOOL
Definition: ntddk_ex.h:94
WCHAR strW[12]
Definition: clipboard.c:2029
long LONG
Definition: pedump.c:60
static WCHAR * strstrW(const WCHAR *str, const WCHAR *sub)
Definition: mlang.c:1301
static void cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
Definition: mlang.c:702
static const WCHAR de_dech[]
Definition: mlang.c:134
#define TODO_NAME
Definition: mlang.c:106
static HRESULT WINAPI stream_Revert(IStream *iface)
Definition: mlang.c:2403
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
static const WCHAR de_enca[]
Definition: mlang.c:118
#define ok(value,...)
static const WCHAR en_engb[]
Definition: mlang.c:140
#define LANG_ITALIAN
Definition: nls.h:75
#define LCMAP_LOWERCASE
Definition: winnls.h:181
#define S_FALSE
Definition: winerror.h:2357
static LPCWSTR
Definition: mlang.c:48
#define E_INVALIDARG
Definition: ddrawi.h:101
UINT ciCharset
Definition: wingdi.h:1524
const WCHAR * str
static HRESULT(WINAPI *pConvertINetMultiByteToUnicode)(LPDWORD
smooth NULL
Definition: ftsmooth.c:416
LCID WINAPI GetSystemDefaultLCID(void)
Definition: lang.c:787
static const WCHAR de_de[]
Definition: mlang.c:130
Definition: general.c:220
static const WCHAR fr_enus2[]
Definition: mlang.c:158
const char * LPCSTR
Definition: xmlstorage.h:183
static BOOL(WINAPI *pGetCPInfoExA)(UINT
static const WCHAR fr_enus[]
Definition: mlang.c:156
static INT
Definition: mlang.c:51
static HFONT hfont
#define FS_THAI
Definition: wingdi.h:568
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static const WCHAR lang[]
Definition: wbemdisp.c:287
LPCWSTR broken_name
Definition: mlang.c:114
#define SUBLANG_ENGLISH_CAN
Definition: nls.h:225
#define todo_wine_if(is_todo)
Definition: test.h:155
static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2)
Definition: mlang.c:1452
BOOL WINAPI TranslateCharsetInfo(_Inout_ PDWORD, _Out_ LPCHARSETINFO, _In_ DWORD)
#define FS_HEBREW
Definition: wingdi.h:564
GLsizeiptr size
Definition: glext.h:5919
static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2)
Definition: mlang.c:569
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static const WCHAR de_enus[]
Definition: mlang.c:125
static void test_Rfc1766ToLcid(void)
Definition: mlang.c:1410
int convert
Definition: msacm.c:1362
#define CP_UNICODE
Definition: mlang.c:39
if(!(yy_init))
Definition: macro.lex.yy.c:714
__wchar_t WCHAR
Definition: xmlstorage.h:180
static HRESULT check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to)
Definition: mlang.c:741
static LPSTR
Definition: mlang.c:48
LONG HRESULT
Definition: typedefs.h:77
LANGID lang
Definition: mlang.c:110
static LPINT
Definition: mlang.c:46
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
LCID lcid
Definition: mlang.c:55
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static void test_CodePageToScriptID(IMLangFontLink2 *font_link)
Definition: mlang.c:2143
unsigned long DWORD
Definition: ntddk_ex.h:95
static const struct cpinfo_test_data iml2_cpinfo_data[]
Definition: mlang.c:247
static void test_GetRfc1766Info(IMultiLanguage2 *iML2)
Definition: mlang.c:1539
static ULONG WINAPI stream_AddRef(IStream *iface)
Definition: mlang.c:2336
static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER len, DWORD locktype)
Definition: mlang.c:2409
Definition: id3.c:18
#define OBJ_FONT
Definition: objidl.idl:1414
static DWORD cb
Definition: integrity.c:41
BOOL todo_GetCodePageInfo
Definition: mlang.c:236
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
GLbitfield flags
Definition: glext.h:7161
#define WC_NO_BEST_FIT_CHARS
Definition: unicode.h:46
#define LANG_ENGLISH
Definition: nls.h:52
static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags)
Definition: mlang.c:1068
int ret
static void test_GetScriptFontInfo(IMLangFontLink2 *font_link)
Definition: mlang.c:2105
#define LPDWORD
Definition: nt_native.h:46
static const IStreamVtbl stream_vtbl
Definition: mlang.c:2435
static const WCHAR fr_en[]
Definition: mlang.c:151
#define todo_wine
Definition: test.h:154
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
Definition: parse.h:22
HDC hdc
Definition: main.c:9
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
static void test_MapFont(IMLangFontLink *font_link, IMLangFontLink2 *font_link2)
Definition: mlang.c:2604
static IMultiLanguage2 * mlang
Definition: main.c:36
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
#define LANGIDFROMLCID(l)
Definition: nls.h:18
unsigned char BYTE
Definition: mem.h:68
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:819
#define FS_JISJAPAN
Definition: wingdi.h:569
static HRESULT WINAPI stream_Clone(IStream *iface, IStream **stream)
Definition: mlang.c:2429
const char * wine_dbgstr_wn(const WCHAR *str, int n)
Definition: compat.c:342
static const lcid_table_entry lcid_table[]
Definition: mlang.c:65
GLenum src
Definition: glext.h:6340
static LPWSTR
Definition: mlang.c:46
#define FS_WANSUNG
Definition: wingdi.h:571
static LPCSTR
Definition: mlang.c:46
GLsizei const GLfloat * value
Definition: glext.h:6069
#define LANG_FRENCH
Definition: nls.h:58
static HRESULT WINAPI stream_Read(IStream *iface, void *buf, ULONG len, ULONG *read)
Definition: mlang.c:2348
BOOL todo_wszProportionalFont
Definition: mlang.c:244
#define broken(x)
Definition: _sntprintf.h:21
BOOL todo_wszHeaderCharset
Definition: mlang.c:241
LPCSTR rfc1766
Definition: mlang.c:54
#define LANG_GERMAN
Definition: nls.h:62
static void test_IMultiLanguage2_ConvertStringFromUnicode(IMultiLanguage2 *iML2)
Definition: mlang.c:1593
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3234
struct info_table_tag info_table_entry
BOOL todo_wszFixedWidthFont
Definition: mlang.c:243
static const WCHAR en_dech[]
Definition: mlang.c:148
#define S_OK
Definition: intsafe.h:59
static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *stream, ULARGE_INTEGER len, ULARGE_INTEGER *read, ULARGE_INTEGER *written)
Definition: mlang.c:2390
BOOL WINAPI IsValidCodePage(UINT CodePage)
Definition: nls.c:1468
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
struct lcid_tag_table lcid_table_entry
#define lstrcpyW
Definition: compat.h:406
#define WC_COMPOSITECHECK
Definition: unicode.h:43
BOOL WINAPI DeleteDC(_In_ HDC)
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:1991
#define ARRAY_SIZE(a)
Definition: main.h:24
static void test_IMLangConvertCharset(IMultiLanguage *ml)
Definition: mlang.c:2265
static ULONG WINAPI stream_Release(IStream *iface)
Definition: mlang.c:2342
LPCSTR broken_rfc
Definition: mlang.c:58
static const WCHAR de_engb[]
Definition: mlang.c:120
#define E_NOTIMPL
Definition: ddrawi.h:99
BOOL todo_wszBodyCharset
Definition: mlang.c:242
static void test_JapaneseConversion(void)
Definition: mlang.c:1922
#define min(a, b)
Definition: monoChain.cc:55
void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
Definition: oleaut.c:274
static void test_GetFontUnicodeRanges(IMLangFontLink2 *font_link)
Definition: mlang.c:2185
unsigned int UINT
Definition: ndis.h:50
static const WCHAR fr_de[]
Definition: mlang.c:160
#define FS_ARABIC
Definition: wingdi.h:565
static void test_rfc1766(IMultiLanguage2 *iML2)
Definition: mlang.c:1313
#define MultiByteToWideChar
Definition: compat.h:100
DWORD todo
Definition: mlang.c:111
static const WCHAR en_de[]
Definition: mlang.c:144
static HRESULT WINAPI stream_Write(IStream *iface, const void *buf, ULONG len, ULONG *written)
Definition: mlang.c:2364
#define skip(...)
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
static const LCID english
Definition: wbemdisp.c:32
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1897
#define TCI_SRCCODEPAGE
Definition: wingdi.h:961
#define FS_LATIN1
Definition: wingdi.h:559
POINT cp
Definition: magnifier.c:61
#define ok_w2(format, szString1, szString2)
Definition: mlang.c:559
LCID lcid
Definition: mlang.c:109
static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2)
Definition: mlang.c:1350
static int processed(const type_t *type)
Definition: typegen.c:2236
unsigned int ULONG
Definition: retypes.h:1
static void test_IsCodePageInstallable(IMultiLanguage2 *ml2)
Definition: mlang.c:2228
CHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:55
#define MAKELANGID(p, s)
Definition: nls.h:15
static const WCHAR de_deat[]
Definition: mlang.c:132
#define FS_GREEK
Definition: wingdi.h:562
static const WCHAR de_enus2[]
Definition: mlang.c:127
#define GetProcAddress(x, y)
Definition: compat.h:410
static char * dest
Definition: rtl.c:135
#define SUBLANG_GERMAN_SWISS
Definition: nls.h:252
#define FS_TURKISH
Definition: wingdi.h:563
static const WCHAR en_enca[]
Definition: mlang.c:138
CardRegion * from
Definition: spigame.cpp:19
static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj)
Definition: mlang.c:2330
static const char stream_data[]
Definition: mlang.c:2327
#define memset(x, y, z)
Definition: compat.h:39
START_TEST(mlang)
Definition: mlang.c:2701
static const WCHAR de_engb2[]
Definition: mlang.c:122
#define HeapFree(x, y, z)
Definition: compat.h:394
HGDIOBJ WINAPI GetCurrentObject(_In_ HDC, _In_ UINT)
Definition: dc.c:439
static void IMLangFontLink_Test(IMLangFontLink *iMLFL)
Definition: mlang.c:1164
LCID WINAPI GetThreadLocale(void)
Definition: lang.c:1449
#define SUBLANG_ENGLISH_UK
Definition: nls.h:223
BOOL expected
Definition: store.c:2063
BOOL todo_wszDescription
Definition: mlang.c:239
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define SUCCEEDED(hr)
Definition: intsafe.h:57
INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen)
Definition: lang.c:2047
static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags)
Definition: mlang.c:783
LONGLONG QuadPart
Definition: typedefs.h:112
static const WCHAR en_en[]
Definition: mlang.c:137
#define PRIMARYLANGID(l)
Definition: nls.h:16
#define SUBLANG_GERMAN_AUSTRIAN
Definition: nls.h:253