Test passing NULL source to WideCharToMultiByte.
[wine] / dlls / mlang / mlang.c
1 /*
2  *    MLANG Class Factory
3  *
4  * Copyright 2002 Lionel Ulmer
5  * Copyright 2003,2004 Mike McCormack
6  * Copyright 2004 Dmitry Timoshkov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winreg.h"
35 #include "ole2.h"
36 #include "mlang.h"
37
38 #include "uuids.h"
39
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(mlang);
44
45 #include "initguid.h"
46
47 #define CP_UNICODE 1200
48
49 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
50
51 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj);
52
53 /* FIXME:
54  * Under what circumstances HKEY_CLASSES_ROOT\MIME\Database\Codepage and
55  * HKEY_CLASSES_ROOT\MIME\Database\Charset are used?
56  */
57
58 typedef struct
59 {
60     const char *description;
61     UINT cp;
62     DWORD flags;
63     const char *web_charset;
64     const char *header_charset;
65     const char *body_charset;
66 } MIME_CP_INFO;
67
68 /* These data are based on the codepage info in libs/unicode/cpmap.pl */
69 /* FIXME: Add 28604 (Celtic), 28606 (Balkan) */
70
71 static const MIME_CP_INFO arabic_cp[] =
72 {
73     { "Arabic (864)",
74       864, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
75            MIMECONTF_MIME_LATEST,
76       "ibm864", "ibm864", "ibm864" },
77     { "Arabic (1006)",
78       1006, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
79             MIMECONTF_MIME_LATEST,
80       "ibm1006", "ibm1006", "ibm1006" },
81     { "Arabic (Windows)",
82       1256, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
83             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
84             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
85       "windows-1256", "windows-1256", "windows-1256" },
86     { "Arabic (ISO)",
87       28596, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
88              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
89              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
90              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
91       "iso-8859-6", "iso-8859-6", "iso-8859-6" }
92 };
93 static const MIME_CP_INFO baltic_cp[] =
94 {
95     { "Baltic (DOS)",
96       775, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
97            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
98       "ibm775", "ibm775", "ibm775" },
99     { "Baltic (Windows)",
100       1257, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
101             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
102             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
103             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
104       "windows-1257", "windows-1257", "windows-1257" },
105     { "Baltic (ISO)",
106       28594, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
107              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
108              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
109              MIMECONTF_MIME_LATEST,
110       "iso-8859-4", "iso-8859-4", "iso-8859-4" },
111     { "Estonian (ISO)",
112       28603, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
113              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
114       "iso-8859-13", "iso-8859-13", "iso-8859-13" }
115 };
116 static const MIME_CP_INFO chinese_simplified_cp[] =
117 {
118     { "Chinese Simplified (GB2312)",
119       936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
120            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
121            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
122            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
123       "gb2312", "gb2312", "gb2312" }
124 };
125 static const MIME_CP_INFO chinese_traditional_cp[] =
126 {
127     { "Chinese Traditional (Big5)",
128       950, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
129            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
130            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
131            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
132       "big5", "big5", "big5" }
133 };
134 static const MIME_CP_INFO central_european_cp[] =
135 {
136     { "Central European (DOS)",
137       852, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
138            MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
139            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
140       "ibm852", "ibm852", "ibm852" },
141     { "Central European (Windows)",
142       1250, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
143             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
144             MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
145             MIMECONTF_MIME_LATEST,
146       "windows-1250", "windows-1250", "windows-1250" },
147     { "Central European (Mac)",
148       10029, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
149              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
150       "x-mac-ce", "x-mac-ce", "x-mac-ce" },
151     { "Central European (ISO)",
152       28592, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
153              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
154              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
155              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
156       "iso-8859-2", "iso-8859-2", "iso-8859-2" }
157 };
158 static const MIME_CP_INFO cyrillic_cp[] =
159 {
160     { "OEM Cyrillic",
161       855, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
162            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
163       "ibm855", "ibm855", "ibm855" },
164     { "Cyrillic (DOS)",
165       866, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
166            MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
167            MIMECONTF_MIME_LATEST,
168       "cp866", "cp866", "cp866" },
169 #if 0 /* Windows has 20866 as an official code page for KOI8-R */
170     { "Cyrillic (KOI8-R)",
171       878, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
172            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
173       "koi8-r", "koi8-r", "koi8-r" },
174 #endif
175     { "Cyrillic (Windows)",
176       1251, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
177             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
178             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
179       "windows-1251", "windows-1251", "windows-1251" },
180     { "Cyrillic (Mac)",
181       10007, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
182              MIMECONTF_MIME_LATEST,
183       "x-mac-cyrillic", "x-mac-cyrillic", "x-mac-cyrillic" },
184     { "Cyrillic (KOI8-R)",
185       20866, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
186              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
187              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
188              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
189       "koi8-r", "koi8-r", "koi8-r" },
190     { "Cyrillic (KOI8-U)",
191       21866, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
192              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
193              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
194              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
195       "koi8-u", "koi8-u", "koi8-u" },
196     { "Cyrillic (ISO)",
197       28595, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
198              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
199              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
200              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
201       "iso-8859-5", "iso-8859-5", "iso-8859-5" }
202 };
203 static const MIME_CP_INFO greek_cp[] =
204 {
205     { "Greek (DOS)",
206       737, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
207            MIMECONTF_MIME_LATEST,
208       "ibm737", "ibm737", "ibm737" },
209     { "Greek, Modern (DOS)",
210       869, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
211            MIMECONTF_MIME_LATEST,
212       "ibm869", "ibm869", "ibm869" },
213     { "IBM EBCDIC (Greek Modern)",
214       875, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
215            MIMECONTF_MIME_LATEST,
216       "cp875", "cp875", "cp875" },
217     { "Greek (Windows)",
218       1253, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
219             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
220             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
221       "windows-1253", "windows-1253", "windows-1253" },
222     { "Greek (Mac)",
223       10006, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
224              MIMECONTF_MIME_LATEST,
225       "x-mac-greek", "x-mac-greek", "x-mac-greek" },
226     { "Greek (ISO)",
227       28597, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
228              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
229              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
230              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
231       "iso-8859-7", "iso-8859-7", "iso-8859-7" }
232 };
233 static const MIME_CP_INFO hebrew_cp[] =
234 {
235     { "Hebrew (424)",
236       424, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
237            MIMECONTF_MIME_LATEST,
238       "ibm424", "ibm424", "ibm424" },
239     { "Hebrew (856)",
240       856, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
241            MIMECONTF_MIME_LATEST,
242       "cp856", "cp856", "cp856" },
243     { "Hebrew (DOS)",
244       862, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
245            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
246            MIMECONTF_MIME_LATEST,
247       "dos-862", "dos-862", "dos-862" },
248     { "Hebrew (Windows)",
249       1255, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
250             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
251             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
252       "windows-1255", "windows-1255", "windows-1255" },
253     { "Hebrew (ISO-Visual)",
254       28598, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
255              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
256              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
257       "iso-8859-8", "iso-8859-8", "iso-8859-8" }
258 };
259 static const MIME_CP_INFO japanese_cp[] =
260 {
261     { "Japanese (Shift-JIS)",
262       932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
263            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
264            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
265            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
266       "shift_jis", "iso-2022-jp", "iso-2022-jp" },
267     { "Japanese (JIS 0208-1990 and 0212-1990)",
268       20932, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
269              MIMECONTF_MIME_LATEST,
270       "euc-jp", "euc-jp", "euc-jp" }
271 };
272 static const MIME_CP_INFO korean_cp[] =
273 {
274     { "Korean",
275       949, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
276            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
277            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
278            MIMECONTF_MIME_LATEST,
279       "ks_c_5601-1987", "ks_c_5601-1987", "ks_c_5601-1987" }
280 };
281 static const MIME_CP_INFO thai_cp[] =
282 {
283     { "Thai (Windows)",
284       874, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_MIME_LATEST,
285       "ibm-thai", "ibm-thai", "ibm-thai" }
286 };
287 static const MIME_CP_INFO turkish_cp[] =
288 {
289     { "Turkish (DOS)",
290       857, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
291            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
292       "ibm857", "ibm857", "ibm857" },
293     { "IBM EBCDIC (Turkish Latin-5)",
294       1026, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
295             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
296       "ibm1026", "ibm1026", "ibm1026" },
297     { "Turkish (Windows)",
298       1254, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
299             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
300             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
301             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
302       "windows-1254", "windows-1254", "windows-1254" },
303     { "Turkish (Mac)",
304       10081, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
305              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
306       "x-mac-turkish", "x-mac-turkish", "x-mac-turkish" },
307     { "Latin 3 (ISO)",
308       28593, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
309              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
310              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
311       "iso-8859-3", "iso-8859-3", "iso-8859-3" },
312     { "Turkish (ISO)",
313       28599, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
314              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
315              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
316              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
317       "iso-8859-9", "iso-8859-9", "iso-8859-9" }
318 };
319 static const MIME_CP_INFO vietnamese_cp[] =
320 {
321     { "Vietnamese (Windows)",
322       1258, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
323             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
324             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
325             MIMECONTF_MIME_LATEST,
326       "windows-1258", "windows-1258", "windows-1258" }
327 };
328 static const MIME_CP_INFO western_cp[] =
329 {
330     { "IBM EBCDIC (US-Canada)",
331       37, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
332           MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
333       "ibm037", "ibm037", "ibm037" },
334     { "OEM United States",
335       437, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
336            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
337       "ibm437", "ibm437", "ibm437" },
338     { "IBM EBCDIC (International)",
339       500, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
340            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
341       "ibm500", "ibm500", "ibm500" },
342     { "Western European (DOS)",
343       850, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
344            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
345       "ibm850", "ibm850", "ibm850" },
346     { "Portuguese (DOS)",
347       860, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
348            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
349       "ibm860", "ibm860", "ibm860" },
350     { "Icelandic (DOS)",
351       861, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
352            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
353       "ibm861", "ibm861", "ibm861" },
354     { "French Canadian (DOS)",
355       863, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
356            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
357       "ibm863", "ibm863", "ibm863" },
358     { "Nordic (DOS)",
359       865, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
360            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
361       "ibm865", "ibm865", "ibm865" },
362     { "Western European (Windows)",
363       1252, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
364             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
365             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
366             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
367       "windows-1252", "windows-1252", "iso-8859-1" },
368     { "Western European (Mac)",
369       10000, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
370              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
371       "macintosh", "macintosh", "macintosh" },
372     { "Icelandic (Mac)",
373       10079, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
374              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
375       "x-mac-icelandic", "x-mac-icelandic", "x-mac-icelandic" },
376     { "Western European (ISO)",
377       28591, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
378              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
379              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
380              MIMECONTF_MIME_LATEST,
381       "iso-8859-1", "iso-8859-1", "iso-8859-1" },
382     { "Latin 9 (ISO)",
383       28605, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
384              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
385              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
386              MIMECONTF_MIME_LATEST,
387       "iso-8859-15", "iso-8859-15", "iso-8859-15" }
388 };
389 static const MIME_CP_INFO unicode_cp[] =
390 {
391     { "Unicode",
392       CP_UNICODE, MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
393                   MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
394                   MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
395                   MIMECONTF_MIME_LATEST,
396       "unicode", "unicode", "unicode" },
397     { "Unicode (UTF-7)",
398       CP_UTF7, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
399                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
400                MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
401       "utf-7", "utf-7", "utf-7" },
402     { "Unicode (UTF-8)",
403       CP_UTF8, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
404                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
405                MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
406                MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
407       "utf-8", "utf-8", "utf-8" }
408 };
409
410 static const struct mlang_data
411 {
412     const char *description;
413     UINT family_codepage;
414     UINT number_of_cp;
415     const MIME_CP_INFO *mime_cp_info;
416     const char *fixed_font;
417     const char *proportional_font;
418 } mlang_data[] =
419 {
420     { "Arabic",1256,sizeof(arabic_cp)/sizeof(arabic_cp[0]),arabic_cp,
421       "Courier","Arial" }, /* FIXME */
422     { "Baltic",1257,sizeof(baltic_cp)/sizeof(baltic_cp[0]),baltic_cp,
423       "Courier","Arial" }, /* FIXME */
424     { "Chinese Simplified",936,sizeof(chinese_simplified_cp)/sizeof(chinese_simplified_cp[0]),chinese_simplified_cp,
425       "Courier","Arial" }, /* FIXME */
426     { "Chinese Traditional",950,sizeof(chinese_traditional_cp)/sizeof(chinese_traditional_cp[0]),chinese_traditional_cp,
427       "Courier","Arial" }, /* FIXME */
428     { "Central European",1250,sizeof(central_european_cp)/sizeof(central_european_cp[0]),central_european_cp,
429       "Courier","Arial" }, /* FIXME */
430     { "Cyrillic",1251,sizeof(cyrillic_cp)/sizeof(cyrillic_cp[0]),cyrillic_cp,
431       "Courier","Arial" }, /* FIXME */
432     { "Greek",1253,sizeof(greek_cp)/sizeof(greek_cp[0]),greek_cp,
433       "Courier","Arial" }, /* FIXME */
434     { "Hebrew",1255,sizeof(hebrew_cp)/sizeof(hebrew_cp[0]),hebrew_cp,
435       "Courier","Arial" }, /* FIXME */
436     { "Japanese",932,sizeof(japanese_cp)/sizeof(japanese_cp[0]),japanese_cp,
437       "Courier","Arial" }, /* FIXME */
438     { "Korean",949,sizeof(korean_cp)/sizeof(korean_cp[0]),korean_cp,
439       "Courier","Arial" }, /* FIXME */
440     { "Thai",874,sizeof(thai_cp)/sizeof(thai_cp[0]),thai_cp,
441       "Courier","Arial" }, /* FIXME */
442     { "Turkish",1254,sizeof(turkish_cp)/sizeof(turkish_cp[0]),turkish_cp,
443       "Courier","Arial" }, /* FIXME */
444     { "Vietnamese",1258,sizeof(vietnamese_cp)/sizeof(vietnamese_cp[0]),vietnamese_cp,
445       "Courier","Arial" }, /* FIXME */
446     { "Western European",1252,sizeof(western_cp)/sizeof(western_cp[0]),western_cp,
447       "Courier","Arial" }, /* FIXME */
448     { "Unicode",CP_UNICODE,sizeof(unicode_cp)/sizeof(unicode_cp[0]),unicode_cp,
449       "Courier","Arial" } /* FIXME */
450 };
451
452 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info);
453
454 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
455 {
456     switch(fdwReason) {
457         case DLL_PROCESS_ATTACH:
458             DisableThreadLibraryCalls(hInstDLL);
459             break;
460         case DLL_PROCESS_DETACH:
461             break;
462     }
463     return TRUE;
464 }
465
466 HRESULT WINAPI ConvertINetMultiByteToUnicode(
467     LPDWORD pdwMode,
468     DWORD dwEncoding,
469     LPCSTR pSrcStr,
470     LPINT pcSrcSize,
471     LPWSTR pDstStr,
472     LPINT pcDstSize)
473 {
474     INT src_len = -1;
475
476     TRACE("%p %ld %s %p %p %p\n", pdwMode, dwEncoding,
477           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
478
479     if (!pcDstSize)
480         return E_FAIL;
481
482     if (!pcSrcSize)
483         pcSrcSize = &src_len;
484
485     if (!*pcSrcSize)
486     {
487         *pcDstSize = 0;
488         return S_OK;
489     }
490
491     switch (dwEncoding)
492     {
493     case CP_UNICODE:
494         if (*pcSrcSize == -1)
495             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
496         *pcDstSize = min(*pcSrcSize, *pcDstSize);
497         *pcSrcSize *= sizeof(WCHAR);
498         if (pDstStr)
499             memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
500         break;
501
502     default:
503         if (*pcSrcSize == -1)
504             *pcSrcSize = lstrlenA(pSrcStr);
505
506         if (pDstStr)
507             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
508         else
509             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
510         break;
511     }
512     
513     if (!*pcDstSize)
514         return E_FAIL;
515
516     return S_OK;
517 }
518
519 HRESULT WINAPI ConvertINetUnicodeToMultiByte(
520     LPDWORD pdwMode,
521     DWORD dwEncoding,
522     LPCWSTR pSrcStr,
523     LPINT pcSrcSize,
524     LPSTR pDstStr,
525     LPINT pcDstSize)
526 {
527
528     INT src_len = -1;
529
530     TRACE("%p %ld %s %p %p %p\n", pdwMode, dwEncoding,
531           debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
532
533     if (!pcDstSize)
534         return E_FAIL;
535
536     if (!pcSrcSize)
537         pcSrcSize = &src_len;
538
539     if (!*pcSrcSize)
540     {
541         *pcDstSize = 0;
542         return S_OK;
543     }
544
545     switch (dwEncoding)
546     {
547     case CP_UNICODE:
548         if (*pcSrcSize == -1)
549             *pcSrcSize = lstrlenW(pSrcStr);
550         *pcDstSize = min(*pcSrcSize * sizeof(WCHAR), *pcDstSize);
551         if (pDstStr)
552             memmove(pDstStr, pSrcStr, *pcDstSize);
553         break;
554
555     default:
556         if (*pcSrcSize == -1)
557             *pcSrcSize = lstrlenW(pSrcStr);
558
559         if (pDstStr)
560             *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
561         else
562             *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0, NULL, NULL);
563         break;
564     }
565
566
567     if (!*pcDstSize)
568         return E_FAIL;
569
570     return S_OK;
571 }
572
573 HRESULT WINAPI ConvertINetString(
574     LPDWORD pdwMode,
575     DWORD dwSrcEncoding,
576     DWORD dwDstEncoding,
577     LPCSTR pSrcStr,
578     LPINT pcSrcSize,
579     LPSTR pDstStr,
580     LPINT pcDstSize
581 )
582 {
583     FIXME("%p %ld %ld %s %p %p %p: stub!\n", pdwMode, dwSrcEncoding, dwDstEncoding,
584           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
585     return E_NOTIMPL;
586 }
587
588 static HRESULT GetFamilyCodePage(
589     UINT uiCodePage,
590     UINT* puiFamilyCodePage)
591 {
592     UINT i, n;
593
594     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
595
596     if (!puiFamilyCodePage) return S_FALSE;
597
598     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
599     {
600         for (n = 0; n < mlang_data[i].number_of_cp; n++)
601         {
602             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
603             {
604                 *puiFamilyCodePage = mlang_data[i].family_codepage;
605                 return S_OK;
606             }
607         }
608     }
609
610     return S_FALSE;
611 }
612
613 HRESULT WINAPI IsConvertINetStringAvailable(
614     DWORD dwSrcEncoding,
615     DWORD dwDstEncoding)
616 {
617     UINT src_family, dst_family;
618
619     TRACE("%ld %ld\n", dwSrcEncoding, dwDstEncoding);
620
621     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
622         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
623         return S_FALSE;
624
625     if (src_family == dst_family) return S_OK;
626
627     /* we can convert any codepage to/from unicode */
628     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
629
630     return S_FALSE;
631 }
632
633 HRESULT WINAPI LcidToRfc1766A(
634     LCID Locale,
635     LPSTR pszRfc1766,
636     INT nChar)
637 {
638     FIXME("%ld %s %u\n", Locale, pszRfc1766, nChar);
639     return S_FALSE;
640 }
641
642 HRESULT WINAPI LcidToRfc1766W(
643     LCID Locale,
644     LPWSTR pszRfc1766,
645     INT nChar)
646 {
647     FIXME("%ld %p %u\n", Locale, pszRfc1766, nChar);
648     return S_FALSE;
649 }
650
651 /******************************************************************************
652  * MLANG ClassFactory
653  */
654 typedef struct {
655     IClassFactory ITF_IClassFactory;
656
657     LONG ref;
658     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
659 } IClassFactoryImpl;
660
661 struct object_creation_info
662 {
663     const CLSID *clsid;
664     LPCSTR szClassName;
665     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
666 };
667
668 static const struct object_creation_info object_creation[] =
669 {
670     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
671 };
672
673 static HRESULT WINAPI
674 MLANGCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
675 {
676     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
677
678     TRACE("%s\n", debugstr_guid(riid) );
679
680     if (IsEqualGUID(riid, &IID_IUnknown)
681         || IsEqualGUID(riid, &IID_IClassFactory))
682     {
683         IClassFactory_AddRef(iface);
684         *ppobj = This;
685         return S_OK;
686     }
687
688     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
689     return E_NOINTERFACE;
690 }
691
692 static ULONG WINAPI MLANGCF_AddRef(LPCLASSFACTORY iface)
693 {
694     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
695     return InterlockedIncrement(&This->ref);
696 }
697
698 static ULONG WINAPI MLANGCF_Release(LPCLASSFACTORY iface)
699 {
700     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
701
702     ULONG ref = InterlockedDecrement(&This->ref);
703
704     if (ref == 0)
705     {
706         TRACE("Destroying %p\n", This);
707         HeapFree(GetProcessHeap(), 0, This);
708     }
709
710     return ref;
711 }
712
713 static HRESULT WINAPI MLANGCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
714                                           REFIID riid, LPVOID *ppobj)
715 {
716     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
717     HRESULT hres;
718     LPUNKNOWN punk;
719     
720     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
721
722     *ppobj = NULL;
723     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
724     if (SUCCEEDED(hres)) {
725         hres = IUnknown_QueryInterface(punk, riid, ppobj);
726         IUnknown_Release(punk);
727     }
728     TRACE("returning (%p) -> %lx\n", *ppobj, hres);
729     return hres;
730 }
731
732 static HRESULT WINAPI MLANGCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
733 {
734     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
735     FIXME("(%p)->(%d),stub!\n",This,dolock);
736     return S_OK;
737 }
738
739 static const IClassFactoryVtbl MLANGCF_Vtbl =
740 {
741     MLANGCF_QueryInterface,
742     MLANGCF_AddRef,
743     MLANGCF_Release,
744     MLANGCF_CreateInstance,
745     MLANGCF_LockServer
746 };
747
748 /******************************************************************
749  *              DllGetClassObject (MLANG.@)
750  */
751 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
752 {
753     int i;
754     IClassFactoryImpl *factory;
755
756     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
757
758     if ( !IsEqualGUID( &IID_IClassFactory, iid )
759          && ! IsEqualGUID( &IID_IUnknown, iid) )
760         return E_NOINTERFACE;
761
762     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
763     {
764         if (IsEqualGUID(object_creation[i].clsid, rclsid))
765             break;
766     }
767
768     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
769     {
770         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
771         return CLASS_E_CLASSNOTAVAILABLE;
772     }
773
774     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
775
776     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
777     if (factory == NULL) return E_OUTOFMEMORY;
778
779     factory->ITF_IClassFactory.lpVtbl = &MLANGCF_Vtbl;
780     factory->ref = 1;
781
782     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
783
784     *ppv = &(factory->ITF_IClassFactory);
785
786     TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
787
788     return S_OK;
789 }
790
791
792 /******************************************************************************/
793
794 typedef struct tagMLang_impl
795 {
796     const IMLangFontLinkVtbl *vtbl_IMLangFontLink;
797     const IMultiLanguageVtbl *vtbl_IMultiLanguage;
798     const IMultiLanguage2Vtbl *vtbl_IMultiLanguage2;
799     LONG ref;
800     DWORD total_cp, total_scripts;
801 } MLang_impl;
802
803 static ULONG WINAPI MLang_AddRef( MLang_impl* This)
804 {
805     return InterlockedIncrement(&This->ref);
806 }
807
808 static ULONG WINAPI MLang_Release( MLang_impl* This )
809 {
810     ULONG ref = InterlockedDecrement(&This->ref);
811
812     TRACE("%p ref = %ld\n", This, ref);
813     if (ref == 0)
814     {
815         TRACE("Destroying %p\n", This);
816         HeapFree(GetProcessHeap(), 0, This);
817     }
818
819     return ref;
820 }
821
822 static HRESULT WINAPI MLang_QueryInterface(
823         MLang_impl* This,
824         REFIID riid,
825         void** ppvObject)
826 {
827     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
828
829     if (IsEqualGUID(riid, &IID_IUnknown)
830         || IsEqualGUID(riid, &IID_IMLangCodePages)
831         || IsEqualGUID(riid, &IID_IMLangFontLink))
832     {
833         MLang_AddRef(This);
834         TRACE("Returning IID_IMLangFontLink %p ref = %ld\n", This, This->ref);
835         *ppvObject = &(This->vtbl_IMLangFontLink);
836         return S_OK;
837     }
838
839     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
840     {
841         MLang_AddRef(This);
842         TRACE("Returning IID_IMultiLanguage %p ref = %ld\n", This, This->ref);
843         *ppvObject = &(This->vtbl_IMultiLanguage);
844         return S_OK;
845     }
846
847     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
848     {
849         MLang_AddRef(This);
850         *ppvObject = &(This->vtbl_IMultiLanguage2);
851         TRACE("Returning IID_IMultiLanguage2 %p ref = %ld\n", This, This->ref);
852         return S_OK;
853     }
854
855     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
856     return E_NOINTERFACE;
857 }
858
859 /******************************************************************************/
860
861 typedef struct tagEnumCodePage_impl
862 {
863     const IEnumCodePageVtbl *vtbl_IEnumCodePage;
864     LONG ref;
865     MIMECPINFO *cpinfo;
866     DWORD total, pos;
867 } EnumCodePage_impl;
868
869 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
870         IEnumCodePage* iface,
871         REFIID riid,
872         void** ppvObject)
873 {
874     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
875
876     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
877
878     if (IsEqualGUID(riid, &IID_IUnknown)
879         || IsEqualGUID(riid, &IID_IEnumCodePage))
880     {
881         IEnumCodePage_AddRef(iface);
882         TRACE("Returning IID_IEnumCodePage %p ref = %ld\n", This, This->ref);
883         *ppvObject = &(This->vtbl_IEnumCodePage);
884         return S_OK;
885     }
886
887     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
888     return E_NOINTERFACE;
889 }
890
891 static ULONG WINAPI fnIEnumCodePage_AddRef(
892         IEnumCodePage* iface)
893 {
894     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
895     return InterlockedIncrement(&This->ref);
896 }
897
898 static ULONG WINAPI fnIEnumCodePage_Release(
899         IEnumCodePage* iface)
900 {
901     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
902     ULONG ref = InterlockedDecrement(&This->ref);
903
904     TRACE("%p ref = %ld\n", This, ref);
905     if (ref == 0)
906     {
907         TRACE("Destroying %p\n", This);
908         HeapFree(GetProcessHeap(), 0, This->cpinfo);
909         HeapFree(GetProcessHeap(), 0, This);
910     }
911
912     return ref;
913 }
914
915 static HRESULT WINAPI fnIEnumCodePage_Clone(
916         IEnumCodePage* iface,
917         IEnumCodePage** ppEnum)
918 {
919     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
920     FIXME("%p %p\n", This, ppEnum);
921     return E_NOTIMPL;
922 }
923
924 static  HRESULT WINAPI fnIEnumCodePage_Next(
925         IEnumCodePage* iface,
926         ULONG celt,
927         PMIMECPINFO rgelt,
928         ULONG* pceltFetched)
929 {
930     ULONG i;
931
932     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
933     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
934
935     if (!pceltFetched) return S_FALSE;
936     *pceltFetched = 0;
937
938     if (!rgelt) return S_FALSE;
939
940     if (This->pos + celt > This->total)
941         celt = This->total - This->pos;
942
943     if (!celt) return S_FALSE;
944
945     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
946     *pceltFetched = celt;
947     This->pos += celt;
948
949     for (i = 0; i < celt; i++)
950     {
951         TRACE("#%lu: %08lx %u %u %s %s %s %s %s %s %d\n",
952               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
953               rgelt[i].uiFamilyCodePage,
954               wine_dbgstr_w(rgelt[i].wszDescription),
955               wine_dbgstr_w(rgelt[i].wszWebCharset),
956               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
957               wine_dbgstr_w(rgelt[i].wszBodyCharset),
958               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
959               wine_dbgstr_w(rgelt[i].wszProportionalFont),
960               rgelt[i].bGDICharset);
961     }
962     return S_OK;
963 }
964
965 static HRESULT WINAPI fnIEnumCodePage_Reset(
966         IEnumCodePage* iface)
967 {
968     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
969     TRACE("%p\n", This);
970
971     This->pos = 0;
972     return S_OK;
973 }
974
975 static  HRESULT WINAPI fnIEnumCodePage_Skip(
976         IEnumCodePage* iface,
977         ULONG celt)
978 {
979     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
980     TRACE("%p %lu\n", This, celt);
981
982     if (celt >= This->total) return S_FALSE;
983
984     This->pos = celt;  /* FIXME: should be += ?? */
985     return S_OK;
986 }
987
988 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
989 {
990     fnIEnumCodePage_QueryInterface,
991     fnIEnumCodePage_AddRef,
992     fnIEnumCodePage_Release,
993     fnIEnumCodePage_Clone,
994     fnIEnumCodePage_Next,
995     fnIEnumCodePage_Reset,
996     fnIEnumCodePage_Skip
997 };
998
999 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1000                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1001 {
1002     EnumCodePage_impl *ecp;
1003     MIMECPINFO *cpinfo;
1004     UINT i, n;
1005
1006     TRACE("%p, %08lx, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1007
1008     if (!grfFlags) /* enumerate internal data base of encodings */
1009         grfFlags = MIMECONTF_MIME_LATEST;
1010
1011     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1012     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
1013     ecp->ref = 1;
1014     ecp->pos = 0;
1015     ecp->total = 0;
1016     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1017     {
1018         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1019         {
1020             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1021                 ecp->total++;
1022         }
1023     }
1024
1025     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1026                             sizeof(MIMECPINFO) * ecp->total);
1027     cpinfo = ecp->cpinfo;
1028
1029     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1030     {
1031         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1032         {
1033             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1034                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1035         }
1036     }
1037
1038     TRACE("enumerated %ld codepages with flags %08lx\n", ecp->total, grfFlags);
1039
1040     *ppEnumCodePage = (IEnumCodePage*) ecp;
1041
1042     return S_OK;
1043 }
1044
1045 /******************************************************************************/
1046
1047 typedef struct tagEnumScript_impl
1048 {
1049     const IEnumScriptVtbl *vtbl_IEnumScript;
1050     LONG ref;
1051     SCRIPTINFO *script_info;
1052     DWORD total, pos;
1053 } EnumScript_impl;
1054
1055 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1056         IEnumScript* iface,
1057         REFIID riid,
1058         void** ppvObject)
1059 {
1060     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1061
1062     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1063
1064     if (IsEqualGUID(riid, &IID_IUnknown)
1065         || IsEqualGUID(riid, &IID_IEnumScript))
1066     {
1067         IEnumScript_AddRef(iface);
1068         TRACE("Returning IID_IEnumScript %p ref = %ld\n", This, This->ref);
1069         *ppvObject = &(This->vtbl_IEnumScript);
1070         return S_OK;
1071     }
1072
1073     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1074     return E_NOINTERFACE;
1075 }
1076
1077 static ULONG WINAPI fnIEnumScript_AddRef(
1078         IEnumScript* iface)
1079 {
1080     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1081     return InterlockedIncrement(&This->ref);
1082 }
1083
1084 static ULONG WINAPI fnIEnumScript_Release(
1085         IEnumScript* iface)
1086 {
1087     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1088     ULONG ref = InterlockedDecrement(&This->ref);
1089
1090     TRACE("%p ref = %ld\n", This, ref);
1091     if (ref == 0)
1092     {
1093         TRACE("Destroying %p\n", This);
1094         HeapFree(GetProcessHeap(), 0, This);
1095     }
1096
1097     return ref;
1098 }
1099
1100 static HRESULT WINAPI fnIEnumScript_Clone(
1101         IEnumScript* iface,
1102         IEnumScript** ppEnum)
1103 {
1104     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1105     FIXME("%p %p: stub!\n", This, ppEnum);
1106     return E_NOTIMPL;
1107 }
1108
1109 static  HRESULT WINAPI fnIEnumScript_Next(
1110         IEnumScript* iface,
1111         ULONG celt,
1112         PSCRIPTINFO rgelt,
1113         ULONG* pceltFetched)
1114 {
1115     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1116     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
1117
1118     if (!pceltFetched || !rgelt) return E_FAIL;
1119
1120     *pceltFetched = 0;
1121
1122     if (This->pos + celt > This->total)
1123         celt = This->total - This->pos;
1124
1125     if (!celt) return S_FALSE;
1126
1127     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1128     *pceltFetched = celt;
1129     This->pos += celt;
1130
1131     return S_OK;
1132 }
1133
1134 static HRESULT WINAPI fnIEnumScript_Reset(
1135         IEnumScript* iface)
1136 {
1137     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1138     TRACE("%p\n", This);
1139
1140     This->pos = 0;
1141     return S_OK;
1142 }
1143
1144 static  HRESULT WINAPI fnIEnumScript_Skip(
1145         IEnumScript* iface,
1146         ULONG celt)
1147 {
1148     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1149     TRACE("%p %lu\n", This, celt);
1150
1151     if (celt >= This->total) return S_FALSE;
1152
1153     This->pos = celt;  /* FIXME: should be += ?? */
1154     return S_OK;
1155 }
1156
1157 static const IEnumScriptVtbl IEnumScript_vtbl =
1158 {
1159     fnIEnumScript_QueryInterface,
1160     fnIEnumScript_AddRef,
1161     fnIEnumScript_Release,
1162     fnIEnumScript_Clone,
1163     fnIEnumScript_Next,
1164     fnIEnumScript_Reset,
1165     fnIEnumScript_Skip
1166 };
1167
1168 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1169                      LANGID LangId, IEnumScript** ppEnumScript )
1170 {
1171     EnumScript_impl *es;
1172     UINT i;
1173
1174     TRACE("%p, %08lx, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1175
1176     if (!dwFlags) /* enumerate all available scripts */
1177         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1178
1179     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1180     es->vtbl_IEnumScript = &IEnumScript_vtbl;
1181     es->ref = 1;
1182     es->pos = 0;
1183     /* do not enumerate unicode flavours */
1184     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1185     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1186
1187     for (i = 0; i < es->total; i++)
1188     {
1189         es->script_info[i].ScriptId = i;
1190         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1191         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1192             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1193         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1194             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1195         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1196             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1197     }
1198
1199     TRACE("enumerated %ld scripts with flags %08lx\n", es->total, dwFlags);
1200
1201     *ppEnumScript = (IEnumScript *)es;
1202
1203     return S_OK;
1204 }
1205
1206 /******************************************************************************/
1207
1208 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1209         IMLangFontLink* iface,
1210         REFIID riid,
1211         void** ppvObject)
1212 {
1213     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1214     return MLang_QueryInterface( This, riid, ppvObject );
1215 }
1216
1217 static ULONG WINAPI fnIMLangFontLink_AddRef(
1218         IMLangFontLink* iface)
1219 {
1220     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1221     return MLang_AddRef( This );
1222 }
1223
1224 static ULONG WINAPI fnIMLangFontLink_Release(
1225         IMLangFontLink* iface)
1226 {
1227     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1228     return MLang_Release( This );
1229 }
1230
1231 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1232         IMLangFontLink* iface,
1233         WCHAR chSrc,
1234         DWORD* pdwCodePages)
1235 {
1236     FIXME("\n");
1237     return E_NOTIMPL;
1238 }
1239
1240 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1241         IMLangFontLink* iface,
1242         const WCHAR* pszSrc,
1243         long cchSrc,
1244         DWORD dwPriorityCodePages,
1245         DWORD* pdwCodePages,
1246         long* pcchCodePages)
1247 {
1248     FIXME("\n");
1249     return E_NOTIMPL;
1250 }
1251
1252 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1253         IMLangFontLink* iface,
1254         UINT uCodePage,
1255         DWORD* pdwCodePages)
1256 {
1257     FIXME("\n");
1258     return E_NOTIMPL;
1259 }
1260
1261 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1262         IMLangFontLink* iface,
1263         DWORD dwCodePages,
1264         UINT uDefaultCodePage,
1265         UINT* puCodePage)
1266 {
1267     FIXME("\n");
1268     return E_NOTIMPL;
1269 }
1270
1271 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
1272         IMLangFontLink* iface,
1273         HDC hDC,
1274         HFONT hFont,
1275         DWORD* pdwCodePages)
1276 {
1277     FIXME("\n");
1278     return E_NOTIMPL;
1279 }
1280
1281 static HRESULT WINAPI fnIMLangFontLink_MapFont(
1282         IMLangFontLink* iface,
1283         HDC hDC,
1284         DWORD dwCodePages,
1285         HFONT hSrcFont,
1286         HFONT* phDestFont)
1287 {
1288     FIXME("\n");
1289     return E_NOTIMPL;
1290 }
1291
1292 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
1293         IMLangFontLink* iface,
1294         HFONT hFont)
1295 {
1296     FIXME("\n");
1297     return E_NOTIMPL;
1298 }
1299
1300 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
1301         IMLangFontLink* iface)
1302 {
1303     FIXME("\n");
1304     return E_NOTIMPL;
1305 }
1306
1307
1308 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
1309 {
1310     fnIMLangFontLink_QueryInterface,
1311     fnIMLangFontLink_AddRef,
1312     fnIMLangFontLink_Release,
1313     fnIMLangFontLink_GetCharCodePages,
1314     fnIMLangFontLink_GetStrCodePages,
1315     fnIMLangFontLink_CodePageToCodePages,
1316     fnIMLangFontLink_CodePagesToCodePage,
1317     fnIMLangFontLink_GetFontCodePages,
1318     fnIMLangFontLink_MapFont,
1319     fnIMLangFontLink_ReleaseFont,
1320     fnIMLangFontLink_ResetFontMapping,
1321 };
1322
1323 /******************************************************************************/
1324
1325 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
1326     IMultiLanguage* iface,
1327     REFIID riid,
1328     void** ppvObject)
1329 {
1330     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1331     return MLang_QueryInterface( This, riid, ppvObject );
1332 }
1333
1334 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
1335 {
1336     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1337     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
1338 }
1339
1340 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
1341 {
1342     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1343     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
1344 }
1345
1346 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
1347     IMultiLanguage* iface,
1348     UINT* pcCodePage)
1349 {
1350     FIXME("\n");
1351     return E_NOTIMPL;
1352 }
1353
1354 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
1355     IMultiLanguage* iface,
1356     UINT uiCodePage,
1357     PMIMECPINFO pCodePageInfo)
1358 {
1359     FIXME("\n");
1360     return E_NOTIMPL;
1361 }
1362
1363 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
1364     IMultiLanguage* iface,
1365     UINT uiCodePage,
1366     UINT* puiFamilyCodePage)
1367 {
1368     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1369 }
1370
1371 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
1372     IMultiLanguage* iface,
1373     DWORD grfFlags,
1374     IEnumCodePage** ppEnumCodePage)
1375 {
1376     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1377     TRACE("%p %08lx %p\n", This, grfFlags, ppEnumCodePage);
1378
1379     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
1380 }
1381
1382 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
1383     IMultiLanguage* iface,
1384     BSTR Charset,
1385     PMIMECSETINFO pCharsetInfo)
1386 {
1387     FIXME("\n");
1388     return E_NOTIMPL;
1389 }
1390
1391 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
1392     IMultiLanguage* iface,
1393     DWORD dwSrcEncoding,
1394     DWORD dwDstEncoding)
1395 {
1396     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
1397 }
1398
1399 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
1400     IMultiLanguage* iface,
1401     DWORD* pdwMode,
1402     DWORD dwSrcEncoding,
1403     DWORD dwDstEncoding,
1404     BYTE* pSrcStr,
1405     UINT* pcSrcSize,
1406     BYTE* pDstStr,
1407     UINT* pcDstSize)
1408 {
1409     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
1410                              pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1411 }
1412
1413 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
1414     IMultiLanguage* iface,
1415     DWORD* pdwMode,
1416     DWORD dwEncoding,
1417     CHAR* pSrcStr,
1418     UINT* pcSrcSize,
1419     WCHAR* pDstStr,
1420     UINT* pcDstSize)
1421 {
1422     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
1423                                          pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1424 }
1425
1426 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
1427     IMultiLanguage* iface,
1428     DWORD* pdwMode,
1429     DWORD dwEncoding,
1430     WCHAR* pSrcStr,
1431     UINT* pcSrcSize,
1432     CHAR* pDstStr,
1433     UINT* pcDstSize)
1434 {
1435     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
1436                                          pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1437 }
1438
1439 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
1440     IMultiLanguage* iface)
1441 {
1442     FIXME("\n");
1443     return E_NOTIMPL;
1444 }
1445
1446 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
1447     IMultiLanguage* iface,
1448     LCID Locale,
1449     BSTR* pbstrRfc1766)
1450 {
1451     FIXME("\n");
1452     return E_NOTIMPL;
1453 }
1454
1455 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
1456     IMultiLanguage* iface,
1457     LCID* pLocale,
1458     BSTR bstrRfc1766)
1459 {
1460     FIXME("\n");
1461     return E_NOTIMPL;
1462 }
1463
1464 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
1465     IMultiLanguage* iface,
1466     IEnumRfc1766** ppEnumRfc1766)
1467 {
1468     FIXME("\n");
1469     return E_NOTIMPL;
1470 }
1471
1472 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
1473     IMultiLanguage* iface,
1474     LCID Locale,
1475     PRFC1766INFO pRfc1766Info)
1476 {
1477     FIXME("\n");
1478     return E_NOTIMPL;
1479 }
1480
1481 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
1482     IMultiLanguage* iface,
1483     UINT uiSrcCodePage,
1484     UINT uiDstCodePage,
1485     DWORD dwProperty,
1486     IMLangConvertCharset** ppMLangConvertCharset)
1487 {
1488     FIXME("\n");
1489     return E_NOTIMPL;
1490 }
1491
1492 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
1493 {
1494     fnIMultiLanguage_QueryInterface,
1495     fnIMultiLanguage_AddRef,
1496     fnIMultiLanguage_Release,
1497     fnIMultiLanguage_GetNumberOfCodePageInfo,
1498     fnIMultiLanguage_GetCodePageInfo,
1499     fnIMultiLanguage_GetFamilyCodePage,
1500     fnIMultiLanguage_EnumCodePages,
1501     fnIMultiLanguage_GetCharsetInfo,
1502     fnIMultiLanguage_IsConvertible,
1503     fnIMultiLanguage_ConvertString,
1504     fnIMultiLanguage_ConvertStringToUnicode,
1505     fnIMultiLanguage_ConvertStringFromUnicode,
1506     fnIMultiLanguage_ConvertStringReset,
1507     fnIMultiLanguage_GetRfc1766FromLcid,
1508     fnIMultiLanguage_GetLcidFromRfc1766,
1509     fnIMultiLanguage_EnumRfc1766,
1510     fnIMultiLanguage_GetRfc1766Info,
1511     fnIMultiLanguage_CreateConvertCharset,
1512 };
1513
1514
1515 /******************************************************************************/
1516
1517 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
1518     IMultiLanguage2* iface,
1519     REFIID riid,
1520     void** ppvObject)
1521 {
1522     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1523     return MLang_QueryInterface( This, riid, ppvObject );
1524 }
1525
1526 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage2* iface )
1527 {
1528     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1529     return MLang_AddRef( This );
1530 }
1531
1532 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage2* iface )
1533 {
1534     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1535     return MLang_Release( This );
1536 }
1537
1538 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
1539     IMultiLanguage2* iface,
1540     UINT* pcCodePage)
1541 {
1542     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1543     TRACE("%p, %p\n", This, pcCodePage);
1544
1545     if (!pcCodePage) return S_FALSE;
1546
1547     *pcCodePage = This->total_cp;
1548     return S_OK;
1549 }
1550
1551 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
1552 {
1553     CHARSETINFO csi;
1554
1555     if (TranslateCharsetInfo((DWORD *)ml_data->family_codepage, &csi, TCI_SRCCODEPAGE))
1556         mime_cp_info->bGDICharset = csi.ciCharset;
1557     else
1558         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
1559
1560     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
1561     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
1562     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
1563     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
1564                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
1565     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
1566                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
1567     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
1568                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
1569     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
1570                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
1571
1572     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
1573         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
1574     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
1575         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
1576
1577     TRACE("%08lx %u %u %s %s %s %s %s %s %d\n",
1578           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
1579           mime_cp_info->uiFamilyCodePage,
1580           wine_dbgstr_w(mime_cp_info->wszDescription),
1581           wine_dbgstr_w(mime_cp_info->wszWebCharset),
1582           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
1583           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
1584           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
1585           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
1586           mime_cp_info->bGDICharset);
1587 }
1588
1589 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
1590     IMultiLanguage2* iface,
1591     UINT uiCodePage,
1592     LANGID LangId,
1593     PMIMECPINFO pCodePageInfo)
1594 {
1595     UINT i, n;
1596
1597     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1598     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
1599
1600     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1601     {
1602         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1603         {
1604             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1605             {
1606                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
1607                 return S_OK;
1608             }
1609         }
1610     }
1611
1612     return S_FALSE;
1613 }
1614
1615 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
1616     IMultiLanguage2* iface,
1617     UINT uiCodePage,
1618     UINT* puiFamilyCodePage)
1619 {
1620     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1621 }
1622
1623 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
1624     IMultiLanguage2* iface,
1625     DWORD grfFlags,
1626     LANGID LangId,
1627     IEnumCodePage** ppEnumCodePage)
1628 {
1629     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1630     TRACE("%p %08lx %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
1631
1632     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
1633 }
1634
1635 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
1636     IMultiLanguage2* iface,
1637     BSTR Charset,
1638     PMIMECSETINFO pCharsetInfo)
1639 {
1640     UINT i, n;
1641
1642     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1643     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
1644
1645     if (!pCharsetInfo) return E_FAIL;
1646
1647     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1648     {
1649         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1650         {
1651             WCHAR csetW[MAX_MIMECSET_NAME];
1652
1653             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
1654             if (!lstrcmpiW(Charset, csetW))
1655             {
1656                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
1657                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
1658                 strcpyW(pCharsetInfo->wszCharset, csetW);
1659                 return S_OK;
1660             }
1661         }
1662     }
1663
1664     /* FIXME:
1665      * Since we do not support charsets like iso-2022-jp and do not have
1666      * them in our database as a primary (web_charset) encoding this loop
1667      * does an attempt to 'approximate' charset name by header_charset.
1668      */
1669     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1670     {
1671         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1672         {
1673             WCHAR csetW[MAX_MIMECSET_NAME];
1674
1675             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
1676             if (!lstrcmpiW(Charset, csetW))
1677             {
1678                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
1679                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
1680                 strcpyW(pCharsetInfo->wszCharset, csetW);
1681                 return S_OK;
1682             }
1683         }
1684     }
1685
1686     return E_FAIL;
1687 }
1688
1689 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
1690     IMultiLanguage2* iface,
1691     DWORD dwSrcEncoding,
1692     DWORD dwDstEncoding)
1693 {
1694     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
1695 }
1696
1697 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
1698     IMultiLanguage2* iface,
1699     DWORD* pdwMode,
1700     DWORD dwSrcEncoding,
1701     DWORD dwDstEncoding,
1702     BYTE* pSrcStr,
1703     UINT* pcSrcSize,
1704     BYTE* pDstStr,
1705     UINT* pcDstSize)
1706 {
1707     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
1708                              pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1709 }
1710
1711 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
1712     IMultiLanguage2* iface,
1713     DWORD* pdwMode,
1714     DWORD dwEncoding,
1715     CHAR* pSrcStr,
1716     UINT* pcSrcSize,
1717     WCHAR* pDstStr,
1718     UINT* pcDstSize)
1719 {
1720     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
1721                                          pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1722 }
1723
1724 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
1725     IMultiLanguage2* iface,
1726     DWORD* pdwMode,
1727     DWORD dwEncoding,
1728     WCHAR* pSrcStr,
1729     UINT* pcSrcSize,
1730     CHAR* pDstStr,
1731     UINT* pcDstSize)
1732 {
1733     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
1734                                          pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1735 }
1736
1737 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
1738     IMultiLanguage2* iface)
1739 {
1740     FIXME("\n");
1741     return E_NOTIMPL;
1742 }
1743
1744 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
1745     IMultiLanguage2* iface,
1746     LCID Locale,
1747     BSTR* pbstrRfc1766)
1748 {
1749     FIXME("\n");
1750     return E_NOTIMPL;
1751 }
1752
1753 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
1754     IMultiLanguage2* iface,
1755     LCID* pLocale,
1756     BSTR bstrRfc1766)
1757 {
1758     FIXME("\n");
1759     return E_NOTIMPL;
1760 }
1761
1762 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
1763     IMultiLanguage2* iface,
1764     LANGID LangId,
1765     IEnumRfc1766** ppEnumRfc1766)
1766 {
1767     FIXME("\n");
1768     return E_NOTIMPL;
1769 }
1770
1771 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
1772     IMultiLanguage2* iface,
1773     LCID Locale,
1774     LANGID LangId,
1775     PRFC1766INFO pRfc1766Info)
1776 {
1777     FIXME("\n");
1778     return E_NOTIMPL;
1779 }
1780
1781 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
1782     IMultiLanguage2* iface,
1783     UINT uiSrcCodePage,
1784     UINT uiDstCodePage,
1785     DWORD dwProperty,
1786     IMLangConvertCharset** ppMLangConvertCharset)
1787 {
1788     FIXME("\n");
1789     return E_NOTIMPL;
1790 }
1791
1792 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
1793     IMultiLanguage2* iface,
1794     DWORD* pdwMode,
1795     DWORD dwFlag,
1796     WCHAR* lpFallBack,
1797     DWORD dwSrcEncoding,
1798     DWORD dwDstEncoding,
1799     IStream* pstmIn,
1800     IStream* pstmOut)
1801 {
1802     FIXME("\n");
1803     return E_NOTIMPL;
1804 }
1805
1806 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
1807     IMultiLanguage2* iface,
1808     DWORD* pdwMode,
1809     DWORD dwEncoding,
1810     CHAR* pSrcStr,
1811     UINT* pcSrcSize,
1812     WCHAR* pDstStr,
1813     UINT* pcDstSize,
1814     DWORD dwFlag,
1815     WCHAR* lpFallBack)
1816 {
1817     FIXME("\n");
1818     return E_NOTIMPL;
1819 }
1820
1821 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
1822     IMultiLanguage2* This,
1823     DWORD* pdwMode,
1824     DWORD dwEncoding,
1825     WCHAR* pSrcStr,
1826     UINT* pcSrcSize,
1827     CHAR* pDstStr,
1828     UINT* pcDstSize,
1829     DWORD dwFlag,
1830     WCHAR* lpFallBack)
1831 {
1832     FIXME("\n");
1833     return E_NOTIMPL;
1834 }
1835
1836 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
1837     IMultiLanguage2* iface,
1838     DWORD dwFlag,
1839     DWORD dwPrefWinCodePage,
1840     IStream* pstmIn,
1841     DetectEncodingInfo* lpEncoding,
1842     INT* pnScores)
1843 {
1844     FIXME("\n");
1845     return E_NOTIMPL;
1846 }
1847
1848 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
1849     IMultiLanguage2* iface,
1850     DWORD dwFlag,
1851     DWORD dwPrefWinCodePage,
1852     CHAR* pSrcStr,
1853     INT* pcSrcSize,
1854     DetectEncodingInfo* lpEncoding,
1855     INT* pnScores)
1856 {
1857     FIXME("\n");
1858     return E_NOTIMPL;
1859 }
1860
1861 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
1862     IMultiLanguage2* iface,
1863     UINT uiCodePage,
1864     HWND hwnd)
1865 {
1866     FIXME("\n");
1867     return E_NOTIMPL;
1868 }
1869
1870 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
1871     IMultiLanguage2* iface,
1872     UINT uiCodePage,
1873     LCID lcid,
1874     LPWSTR lpWideCharStr,
1875     int cchWideChar)
1876 {
1877     FIXME("\n");
1878     return E_NOTIMPL;
1879 }
1880
1881 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
1882     IMultiLanguage2* iface,
1883     UINT uiCodePage)
1884 {
1885     FIXME("\n");
1886     return E_NOTIMPL;
1887 }
1888
1889 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
1890     IMultiLanguage2* iface,
1891     MIMECONTF dwSource)
1892 {
1893     FIXME("\n");
1894     return E_NOTIMPL;
1895 }
1896
1897 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
1898     IMultiLanguage2* iface,
1899     UINT* pnScripts)
1900 {
1901     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1902     TRACE("%p %p\n", This, pnScripts);
1903
1904     if (!pnScripts) return S_FALSE;
1905
1906     *pnScripts = This->total_scripts;
1907     return S_OK;
1908 }
1909
1910 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
1911     IMultiLanguage2* iface,
1912     DWORD dwFlags,
1913     LANGID LangId,
1914     IEnumScript** ppEnumScript)
1915 {
1916     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1917     TRACE("%p %08lx %04x %p\n", This, dwFlags, LangId, ppEnumScript);
1918
1919     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
1920 }
1921
1922 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
1923     IMultiLanguage2* iface,
1924     UINT uiCodePage,
1925     HWND hwnd,
1926     DWORD dwfIODControl)
1927 {
1928     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1929     FIXME("%p %u %p %08lx: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
1930
1931     return S_FALSE;
1932 }
1933
1934 static const IMultiLanguage2Vtbl IMultiLanguage2_vtbl =
1935 {
1936     fnIMultiLanguage2_QueryInterface,
1937     fnIMultiLanguage2_AddRef,
1938     fnIMultiLanguage2_Release,
1939     fnIMultiLanguage2_GetNumberOfCodePageInfo,
1940     fnIMultiLanguage2_GetCodePageInfo,
1941     fnIMultiLanguage2_GetFamilyCodePage,
1942     fnIMultiLanguage2_EnumCodePages,
1943     fnIMultiLanguage2_GetCharsetInfo,
1944     fnIMultiLanguage2_IsConvertible,
1945     fnIMultiLanguage2_ConvertString,
1946     fnIMultiLanguage2_ConvertStringToUnicode,
1947     fnIMultiLanguage2_ConvertStringFromUnicode,
1948     fnIMultiLanguage2_ConvertStringReset,
1949     fnIMultiLanguage2_GetRfc1766FromLcid,
1950     fnIMultiLanguage2_GetLcidFromRfc1766,
1951     fnIMultiLanguage2_EnumRfc1766,
1952     fnIMultiLanguage2_GetRfc1766Info,
1953     fnIMultiLanguage2_CreateConvertCharset,
1954     fnIMultiLanguage2_ConvertStringInIStream,
1955     fnIMultiLanguage2_ConvertStringToUnicodeEx,
1956     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
1957     fnIMultiLanguage2_DetectCodepageInIStream,
1958     fnIMultiLanguage2_DetectInputCodepage,
1959     fnIMultiLanguage2_ValidateCodePage,
1960     fnIMultiLanguage2_GetCodePageDescription,
1961     fnIMultiLanguage2_IsCodePageInstallable,
1962     fnIMultiLanguage2_SetMimeDBSource,
1963     fnIMultiLanguage2_GetNumberOfScripts,
1964     fnIMultiLanguage2_EnumScripts,
1965     fnIMultiLanguage2_ValidateCodePageEx,
1966 };
1967
1968 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
1969 {
1970     MLang_impl *mlang;
1971     UINT i;
1972
1973     TRACE("Creating MultiLanguage object\n");
1974
1975     if( pUnkOuter )
1976         return CLASS_E_NOAGGREGATION;
1977
1978     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
1979     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
1980     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
1981     mlang->vtbl_IMultiLanguage2 = &IMultiLanguage2_vtbl;
1982
1983     mlang->total_cp = 0;
1984     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1985         mlang->total_cp += mlang_data[i].number_of_cp;
1986
1987     /* do not enumerate unicode flavours */
1988     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1989
1990     mlang->ref = 1;
1991     *ppObj = (LPVOID) mlang;
1992     TRACE("returning %p\n", mlang);
1993     return S_OK;
1994 }
1995
1996 /******************************************************************************/
1997
1998 HRESULT WINAPI DllCanUnloadNow(void)
1999 {
2000     FIXME("\n");
2001     return S_FALSE;
2002 }
2003
2004 HRESULT WINAPI GetGlobalFontLinkObject(void)
2005 {
2006     FIXME("\n");
2007     return S_FALSE;
2008 }