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