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