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