comdlg32: Fix the Hungarian translation.
[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,2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "ole2.h"
35 #include "mlang.h"
36
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(mlang);
41
42 #include "initguid.h"
43
44 #define CP_UNICODE 1200
45
46 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
47
48 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj);
49 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum);
50
51 static DWORD MLANG_tls_index; /* to store various per thead data */
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     { "US-ASCII",
377       20127, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT | MIMECONTF_EXPORT |
378              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID |
379              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
380       "us-ascii", "us-ascii", "us-ascii" },
381     { "Western European (ISO)",
382       28591, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
383              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
384              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
385              MIMECONTF_MIME_LATEST,
386       "iso-8859-1", "iso-8859-1", "iso-8859-1" },
387     { "Latin 9 (ISO)",
388       28605, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
389              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
390              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
391              MIMECONTF_MIME_LATEST,
392       "iso-8859-15", "iso-8859-15", "iso-8859-15" }
393 };
394 static const MIME_CP_INFO unicode_cp[] =
395 {
396     { "Unicode",
397       CP_UNICODE, MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
398                   MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
399                   MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
400                   MIMECONTF_MIME_LATEST,
401       "unicode", "unicode", "unicode" },
402     { "Unicode (UTF-7)",
403       CP_UTF7, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
404                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
405                MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
406       "utf-7", "utf-7", "utf-7" },
407     { "Unicode (UTF-8)",
408       CP_UTF8, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
409                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
410                MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
411                MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
412       "utf-8", "utf-8", "utf-8" }
413 };
414
415 static const struct mlang_data
416 {
417     const char *description;
418     UINT family_codepage;
419     UINT number_of_cp;
420     const MIME_CP_INFO *mime_cp_info;
421     const char *fixed_font;
422     const char *proportional_font;
423 } mlang_data[] =
424 {
425     { "Arabic",1256,sizeof(arabic_cp)/sizeof(arabic_cp[0]),arabic_cp,
426       "Courier","Arial" }, /* FIXME */
427     { "Baltic",1257,sizeof(baltic_cp)/sizeof(baltic_cp[0]),baltic_cp,
428       "Courier","Arial" }, /* FIXME */
429     { "Chinese Simplified",936,sizeof(chinese_simplified_cp)/sizeof(chinese_simplified_cp[0]),chinese_simplified_cp,
430       "Courier","Arial" }, /* FIXME */
431     { "Chinese Traditional",950,sizeof(chinese_traditional_cp)/sizeof(chinese_traditional_cp[0]),chinese_traditional_cp,
432       "Courier","Arial" }, /* FIXME */
433     { "Central European",1250,sizeof(central_european_cp)/sizeof(central_european_cp[0]),central_european_cp,
434       "Courier","Arial" }, /* FIXME */
435     { "Cyrillic",1251,sizeof(cyrillic_cp)/sizeof(cyrillic_cp[0]),cyrillic_cp,
436       "Courier","Arial" }, /* FIXME */
437     { "Greek",1253,sizeof(greek_cp)/sizeof(greek_cp[0]),greek_cp,
438       "Courier","Arial" }, /* FIXME */
439     { "Hebrew",1255,sizeof(hebrew_cp)/sizeof(hebrew_cp[0]),hebrew_cp,
440       "Courier","Arial" }, /* FIXME */
441     { "Japanese",932,sizeof(japanese_cp)/sizeof(japanese_cp[0]),japanese_cp,
442       "Courier","Arial" }, /* FIXME */
443     { "Korean",949,sizeof(korean_cp)/sizeof(korean_cp[0]),korean_cp,
444       "Courier","Arial" }, /* FIXME */
445     { "Thai",874,sizeof(thai_cp)/sizeof(thai_cp[0]),thai_cp,
446       "Courier","Arial" }, /* FIXME */
447     { "Turkish",1254,sizeof(turkish_cp)/sizeof(turkish_cp[0]),turkish_cp,
448       "Courier","Arial" }, /* FIXME */
449     { "Vietnamese",1258,sizeof(vietnamese_cp)/sizeof(vietnamese_cp[0]),vietnamese_cp,
450       "Courier","Arial" }, /* FIXME */
451     { "Western European",1252,sizeof(western_cp)/sizeof(western_cp[0]),western_cp,
452       "Courier","Arial" }, /* FIXME */
453     { "Unicode",CP_UNICODE,sizeof(unicode_cp)/sizeof(unicode_cp[0]),unicode_cp,
454       "Courier","Arial" } /* FIXME */
455 };
456
457 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info);
458
459 static LONG dll_count;
460
461 /*
462  * Dll lifetime tracking declaration
463  */
464 static void LockModule(void)
465 {
466     InterlockedIncrement(&dll_count);
467 }
468
469 static void UnlockModule(void)
470 {
471     InterlockedDecrement(&dll_count);
472 }
473
474 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
475 {
476     switch(fdwReason) {
477         case DLL_PROCESS_ATTACH:
478             MLANG_tls_index = TlsAlloc();
479             DisableThreadLibraryCalls(hInstDLL);
480             break;
481         case DLL_PROCESS_DETACH:
482             TlsFree(MLANG_tls_index);
483             break;
484     }
485     return TRUE;
486 }
487
488 HRESULT WINAPI ConvertINetMultiByteToUnicode(
489     LPDWORD pdwMode,
490     DWORD dwEncoding,
491     LPCSTR pSrcStr,
492     LPINT pcSrcSize,
493     LPWSTR pDstStr,
494     LPINT pcDstSize)
495 {
496     INT src_len = -1;
497
498     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
499           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
500
501     if (!pcDstSize)
502         return E_FAIL;
503
504     if (!pcSrcSize)
505         pcSrcSize = &src_len;
506
507     if (!*pcSrcSize)
508     {
509         *pcDstSize = 0;
510         return S_OK;
511     }
512
513     switch (dwEncoding)
514     {
515     case CP_UNICODE:
516         if (*pcSrcSize == -1)
517             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
518         *pcDstSize = min(*pcSrcSize, *pcDstSize);
519         *pcSrcSize *= sizeof(WCHAR);
520         if (pDstStr)
521             memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
522         break;
523
524     default:
525         if (*pcSrcSize == -1)
526             *pcSrcSize = lstrlenA(pSrcStr);
527
528         if (pDstStr)
529             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
530         else
531             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
532         break;
533     }
534     
535     if (!*pcDstSize)
536         return E_FAIL;
537
538     return S_OK;
539 }
540
541 HRESULT WINAPI ConvertINetUnicodeToMultiByte(
542     LPDWORD pdwMode,
543     DWORD dwEncoding,
544     LPCWSTR pSrcStr,
545     LPINT pcSrcSize,
546     LPSTR pDstStr,
547     LPINT pcDstSize)
548 {
549
550     INT src_len = -1;
551
552     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
553           debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
554
555     if (!pcDstSize)
556         return E_FAIL;
557
558     if (!pcSrcSize)
559         pcSrcSize = &src_len;
560
561     if (!*pcSrcSize)
562     {
563         *pcDstSize = 0;
564         return S_OK;
565     }
566
567     switch (dwEncoding)
568     {
569     case CP_UNICODE:
570         if (*pcSrcSize == -1)
571             *pcSrcSize = lstrlenW(pSrcStr);
572         *pcDstSize = min(*pcSrcSize * sizeof(WCHAR), *pcDstSize);
573         if (pDstStr)
574             memmove(pDstStr, pSrcStr, *pcDstSize);
575         break;
576
577     default:
578         if (*pcSrcSize == -1)
579             *pcSrcSize = lstrlenW(pSrcStr);
580
581         if (pDstStr)
582             *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
583         else
584             *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0, NULL, NULL);
585         break;
586     }
587
588
589     if (!*pcDstSize)
590         return E_FAIL;
591
592     return S_OK;
593 }
594
595 HRESULT WINAPI ConvertINetString(
596     LPDWORD pdwMode,
597     DWORD dwSrcEncoding,
598     DWORD dwDstEncoding,
599     LPCSTR pSrcStr,
600     LPINT pcSrcSize,
601     LPSTR pDstStr,
602     LPINT pcDstSize
603 )
604 {
605     TRACE("%p %d %d %s %p %p %p\n", pdwMode, dwSrcEncoding, dwDstEncoding,
606           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
607
608     if (dwSrcEncoding == CP_UNICODE)
609     {
610         INT cSrcSizeW;
611         if (pcSrcSize && *pcSrcSize != -1)
612         {
613             cSrcSizeW = *pcSrcSize / sizeof(WCHAR);
614             pcSrcSize = &cSrcSizeW;
615         }
616         return ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, (LPCWSTR)pSrcStr, pcSrcSize, pDstStr, pcDstSize);
617     }
618     else if (dwDstEncoding == CP_UNICODE)
619     {
620         HRESULT hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, (LPWSTR)pDstStr, pcDstSize);
621         *pcDstSize *= sizeof(WCHAR);
622         return hr;
623     }
624     else
625     {
626         INT cDstSizeW;
627         LPWSTR pDstStrW;
628         HRESULT hr;
629
630         TRACE("convert %s from %d to %d\n", debugstr_a(pSrcStr), dwSrcEncoding, dwDstEncoding);
631
632         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, NULL, &cDstSizeW);
633         if (hr != S_OK)
634             return hr;
635
636         pDstStrW = HeapAlloc(GetProcessHeap(), 0, cDstSizeW * sizeof(WCHAR));
637         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, pDstStrW, &cDstSizeW);
638         if (hr == S_OK)
639             hr = ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, pDstStrW, &cDstSizeW, pDstStr, pcDstSize);
640
641         HeapFree(GetProcessHeap(), 0, pDstStrW);
642         return hr;
643     }
644 }
645
646 static HRESULT GetFamilyCodePage(
647     UINT uiCodePage,
648     UINT* puiFamilyCodePage)
649 {
650     UINT i, n;
651
652     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
653
654     if (!puiFamilyCodePage) return S_FALSE;
655
656     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
657     {
658         for (n = 0; n < mlang_data[i].number_of_cp; n++)
659         {
660             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
661             {
662                 *puiFamilyCodePage = mlang_data[i].family_codepage;
663                 return S_OK;
664             }
665         }
666     }
667
668     return S_FALSE;
669 }
670
671 HRESULT WINAPI IsConvertINetStringAvailable(
672     DWORD dwSrcEncoding,
673     DWORD dwDstEncoding)
674 {
675     UINT src_family, dst_family;
676
677     TRACE("%d %d\n", dwSrcEncoding, dwDstEncoding);
678
679     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
680         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
681         return S_FALSE;
682
683     if (src_family == dst_family) return S_OK;
684
685     /* we can convert any codepage to/from unicode */
686     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
687
688     return S_FALSE;
689 }
690
691 static inline INT lcid_to_rfc1766A( LCID lcid, LPSTR rfc1766, INT len )
692 {
693     INT n = GetLocaleInfoA( lcid, LOCALE_SISO639LANGNAME, rfc1766, len );
694     if (n)
695     {
696         rfc1766[n - 1] = '-';
697         n += GetLocaleInfoA( lcid, LOCALE_SISO3166CTRYNAME, rfc1766 + n, len - n );
698         LCMapStringA( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, rfc1766, n, rfc1766, len );
699         return n;
700     }
701     return 0;
702 }
703
704 static inline INT lcid_to_rfc1766W( LCID lcid, LPWSTR rfc1766, INT len )
705 {
706     INT n = GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME, rfc1766, len );
707     INT save = n;
708     if (n)
709     {
710         rfc1766[n - 1] = '-';
711         n += GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME, rfc1766 + n, len - n );
712         if (n == save)
713             rfc1766[n - 1] = '\0';
714         LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, rfc1766, n, rfc1766, len );
715         return n;
716     }
717     return 0;
718 }
719
720 HRESULT WINAPI LcidToRfc1766A(
721     LCID lcid,
722     LPSTR pszRfc1766,
723     INT nChar)
724 {
725     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
726
727     if (lcid_to_rfc1766A( lcid, pszRfc1766, nChar ))
728         return S_OK;
729
730     return S_FALSE;
731 }
732
733 HRESULT WINAPI LcidToRfc1766W(
734     LCID lcid,
735     LPWSTR pszRfc1766,
736     INT nChar)
737 {
738     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
739
740     if (lcid_to_rfc1766W( lcid, pszRfc1766, nChar ))
741         return S_OK;
742
743     return S_FALSE;
744 }
745
746 static HRESULT lcid_from_rfc1766(IEnumRfc1766 *iface, LCID *lcid, LPCWSTR rfc1766)
747 {
748     RFC1766INFO info;
749     ULONG num;
750
751     while (IEnumRfc1766_Next(iface, 1, &info, &num) == S_OK)
752     {
753         if (!strcmpW(info.wszRfc1766, rfc1766))
754         {
755             *lcid = info.lcid;
756             return S_OK;
757         }
758         if (strlenW(rfc1766) == 2 && !memcmp(info.wszRfc1766, rfc1766, 2 * sizeof(WCHAR)))
759         {
760             *lcid = PRIMARYLANGID(info.lcid);
761             return S_OK;
762         }
763     }
764
765     return E_FAIL;
766 }
767
768 HRESULT WINAPI Rfc1766ToLcidW(LCID *pLocale, LPCWSTR pszRfc1766)
769 {
770     IEnumRfc1766 *enumrfc1766;
771     HRESULT hr;
772
773     TRACE("(%p, %s)\n", pLocale, debugstr_w(pszRfc1766));
774
775     if (!pLocale || !pszRfc1766)
776         return E_INVALIDARG;
777
778     *pLocale = 0;
779
780     hr = EnumRfc1766_create(0, &enumrfc1766);
781     if (FAILED(hr))
782         return hr;
783
784     hr = lcid_from_rfc1766(enumrfc1766, pLocale, pszRfc1766);
785     IEnumRfc1766_Release(enumrfc1766);
786
787     return hr;
788 }
789
790 HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A)
791 {
792     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
793
794     MultiByteToWideChar(CP_ACP, 0, rfc1766A, -1, rfc1766W, MAX_RFC1766_NAME);
795     rfc1766W[MAX_RFC1766_NAME] = 0;
796
797     return Rfc1766ToLcidW(lcid, rfc1766W);
798 }
799
800 /******************************************************************************
801  * MLANG ClassFactory
802  */
803 typedef struct {
804     IClassFactory ITF_IClassFactory;
805
806     LONG ref;
807     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
808 } IClassFactoryImpl;
809
810 struct object_creation_info
811 {
812     const CLSID *clsid;
813     LPCSTR szClassName;
814     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
815 };
816
817 static const struct object_creation_info object_creation[] =
818 {
819     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
820 };
821
822 static HRESULT WINAPI
823 MLANGCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
824 {
825     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
826
827     TRACE("%s\n", debugstr_guid(riid) );
828
829     if (IsEqualGUID(riid, &IID_IUnknown)
830         || IsEqualGUID(riid, &IID_IClassFactory))
831     {
832         IClassFactory_AddRef(iface);
833         *ppobj = This;
834         return S_OK;
835     }
836
837     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
838     return E_NOINTERFACE;
839 }
840
841 static ULONG WINAPI MLANGCF_AddRef(LPCLASSFACTORY iface)
842 {
843     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
844     return InterlockedIncrement(&This->ref);
845 }
846
847 static ULONG WINAPI MLANGCF_Release(LPCLASSFACTORY iface)
848 {
849     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
850
851     ULONG ref = InterlockedDecrement(&This->ref);
852
853     if (ref == 0)
854     {
855         TRACE("Destroying %p\n", This);
856         HeapFree(GetProcessHeap(), 0, This);
857     }
858
859     return ref;
860 }
861
862 static HRESULT WINAPI MLANGCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
863                                           REFIID riid, LPVOID *ppobj)
864 {
865     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
866     HRESULT hres;
867     LPUNKNOWN punk;
868     
869     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
870
871     *ppobj = NULL;
872     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
873     if (SUCCEEDED(hres)) {
874         hres = IUnknown_QueryInterface(punk, riid, ppobj);
875         IUnknown_Release(punk);
876     }
877     TRACE("returning (%p) -> %x\n", *ppobj, hres);
878     return hres;
879 }
880
881 static HRESULT WINAPI MLANGCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
882 {
883     if (dolock)
884         LockModule();
885     else
886         UnlockModule();
887
888     return S_OK;
889 }
890
891 static const IClassFactoryVtbl MLANGCF_Vtbl =
892 {
893     MLANGCF_QueryInterface,
894     MLANGCF_AddRef,
895     MLANGCF_Release,
896     MLANGCF_CreateInstance,
897     MLANGCF_LockServer
898 };
899
900 /******************************************************************
901  *              DllGetClassObject (MLANG.@)
902  */
903 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
904 {
905     int i;
906     IClassFactoryImpl *factory;
907
908     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
909
910     if ( !IsEqualGUID( &IID_IClassFactory, iid )
911          && ! IsEqualGUID( &IID_IUnknown, iid) )
912         return E_NOINTERFACE;
913
914     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
915     {
916         if (IsEqualGUID(object_creation[i].clsid, rclsid))
917             break;
918     }
919
920     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
921     {
922         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
923         return CLASS_E_CLASSNOTAVAILABLE;
924     }
925
926     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
927
928     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
929     if (factory == NULL) return E_OUTOFMEMORY;
930
931     factory->ITF_IClassFactory.lpVtbl = &MLANGCF_Vtbl;
932     factory->ref = 1;
933
934     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
935
936     *ppv = &(factory->ITF_IClassFactory);
937
938     TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
939
940     return S_OK;
941 }
942
943
944 /******************************************************************************/
945
946 typedef struct tagMLang_impl
947 {
948     const IMLangFontLinkVtbl *vtbl_IMLangFontLink;
949     const IMultiLanguageVtbl *vtbl_IMultiLanguage;
950     const IMultiLanguage3Vtbl *vtbl_IMultiLanguage3;
951     LONG ref;
952     DWORD total_cp, total_scripts;
953 } MLang_impl;
954
955 static ULONG WINAPI MLang_AddRef( MLang_impl* This)
956 {
957     return InterlockedIncrement(&This->ref);
958 }
959
960 static ULONG WINAPI MLang_Release( MLang_impl* This )
961 {
962     ULONG ref = InterlockedDecrement(&This->ref);
963
964     TRACE("%p ref = %d\n", This, ref);
965     if (ref == 0)
966     {
967         TRACE("Destroying %p\n", This);
968         HeapFree(GetProcessHeap(), 0, This);
969         UnlockModule();
970     }
971
972     return ref;
973 }
974
975 static HRESULT WINAPI MLang_QueryInterface(
976         MLang_impl* This,
977         REFIID riid,
978         void** ppvObject)
979 {
980     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
981
982     if (IsEqualGUID(riid, &IID_IUnknown)
983         || IsEqualGUID(riid, &IID_IMLangCodePages)
984         || IsEqualGUID(riid, &IID_IMLangFontLink))
985     {
986         MLang_AddRef(This);
987         TRACE("Returning IID_IMLangFontLink %p ref = %d\n", This, This->ref);
988         *ppvObject = &(This->vtbl_IMLangFontLink);
989         return S_OK;
990     }
991
992     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
993     {
994         MLang_AddRef(This);
995         TRACE("Returning IID_IMultiLanguage %p ref = %d\n", This, This->ref);
996         *ppvObject = &(This->vtbl_IMultiLanguage);
997         return S_OK;
998     }
999
1000     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
1001     {
1002         MLang_AddRef(This);
1003         *ppvObject = &(This->vtbl_IMultiLanguage3);
1004         TRACE("Returning IID_IMultiLanguage2 %p ref = %d\n", This, This->ref);
1005         return S_OK;
1006     }
1007
1008     if (IsEqualGUID(riid, &IID_IMultiLanguage3) )
1009     {
1010         MLang_AddRef(This);
1011         *ppvObject = &(This->vtbl_IMultiLanguage3);
1012         TRACE("Returning IID_IMultiLanguage3 %p ref = %d\n", This, This->ref);
1013         return S_OK;
1014     }
1015
1016     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1017     return E_NOINTERFACE;
1018 }
1019
1020 /******************************************************************************/
1021
1022 typedef struct tagEnumCodePage_impl
1023 {
1024     const IEnumCodePageVtbl *vtbl_IEnumCodePage;
1025     LONG ref;
1026     MIMECPINFO *cpinfo;
1027     DWORD total, pos;
1028 } EnumCodePage_impl;
1029
1030 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1031         IEnumCodePage* iface,
1032         REFIID riid,
1033         void** ppvObject)
1034 {
1035     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1036
1037     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1038
1039     if (IsEqualGUID(riid, &IID_IUnknown)
1040         || IsEqualGUID(riid, &IID_IEnumCodePage))
1041     {
1042         IEnumCodePage_AddRef(iface);
1043         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1044         *ppvObject = &(This->vtbl_IEnumCodePage);
1045         return S_OK;
1046     }
1047
1048     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1049     return E_NOINTERFACE;
1050 }
1051
1052 static ULONG WINAPI fnIEnumCodePage_AddRef(
1053         IEnumCodePage* iface)
1054 {
1055     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1056     return InterlockedIncrement(&This->ref);
1057 }
1058
1059 static ULONG WINAPI fnIEnumCodePage_Release(
1060         IEnumCodePage* iface)
1061 {
1062     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1063     ULONG ref = InterlockedDecrement(&This->ref);
1064
1065     TRACE("%p ref = %d\n", This, ref);
1066     if (ref == 0)
1067     {
1068         TRACE("Destroying %p\n", This);
1069         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1070         HeapFree(GetProcessHeap(), 0, This);
1071     }
1072
1073     return ref;
1074 }
1075
1076 static HRESULT WINAPI fnIEnumCodePage_Clone(
1077         IEnumCodePage* iface,
1078         IEnumCodePage** ppEnum)
1079 {
1080     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1081     FIXME("%p %p\n", This, ppEnum);
1082     return E_NOTIMPL;
1083 }
1084
1085 static  HRESULT WINAPI fnIEnumCodePage_Next(
1086         IEnumCodePage* iface,
1087         ULONG celt,
1088         PMIMECPINFO rgelt,
1089         ULONG* pceltFetched)
1090 {
1091     ULONG i;
1092
1093     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1094     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1095
1096     if (!pceltFetched) return S_FALSE;
1097     *pceltFetched = 0;
1098
1099     if (!rgelt) return S_FALSE;
1100
1101     if (This->pos + celt > This->total)
1102         celt = This->total - This->pos;
1103
1104     if (!celt) return S_FALSE;
1105
1106     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1107     *pceltFetched = celt;
1108     This->pos += celt;
1109
1110     for (i = 0; i < celt; i++)
1111     {
1112         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1113               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1114               rgelt[i].uiFamilyCodePage,
1115               wine_dbgstr_w(rgelt[i].wszDescription),
1116               wine_dbgstr_w(rgelt[i].wszWebCharset),
1117               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1118               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1119               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1120               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1121               rgelt[i].bGDICharset);
1122     }
1123     return S_OK;
1124 }
1125
1126 static HRESULT WINAPI fnIEnumCodePage_Reset(
1127         IEnumCodePage* iface)
1128 {
1129     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1130     TRACE("%p\n", This);
1131
1132     This->pos = 0;
1133     return S_OK;
1134 }
1135
1136 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1137         IEnumCodePage* iface,
1138         ULONG celt)
1139 {
1140     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1141     TRACE("%p %u\n", This, celt);
1142
1143     if (celt >= This->total) return S_FALSE;
1144
1145     This->pos += celt;
1146     return S_OK;
1147 }
1148
1149 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1150 {
1151     fnIEnumCodePage_QueryInterface,
1152     fnIEnumCodePage_AddRef,
1153     fnIEnumCodePage_Release,
1154     fnIEnumCodePage_Clone,
1155     fnIEnumCodePage_Next,
1156     fnIEnumCodePage_Reset,
1157     fnIEnumCodePage_Skip
1158 };
1159
1160 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1161                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1162 {
1163     EnumCodePage_impl *ecp;
1164     MIMECPINFO *cpinfo;
1165     UINT i, n;
1166
1167     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1168
1169     if (!grfFlags) /* enumerate internal data base of encodings */
1170         grfFlags = MIMECONTF_MIME_LATEST;
1171
1172     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1173     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
1174     ecp->ref = 1;
1175     ecp->pos = 0;
1176     ecp->total = 0;
1177     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1178     {
1179         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1180         {
1181             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1182                 ecp->total++;
1183         }
1184     }
1185
1186     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1187                             sizeof(MIMECPINFO) * ecp->total);
1188     cpinfo = ecp->cpinfo;
1189
1190     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1191     {
1192         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1193         {
1194             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1195                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1196         }
1197     }
1198
1199     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1200
1201     *ppEnumCodePage = (IEnumCodePage*) ecp;
1202
1203     return S_OK;
1204 }
1205
1206 /******************************************************************************/
1207
1208 typedef struct tagEnumScript_impl
1209 {
1210     const IEnumScriptVtbl *vtbl_IEnumScript;
1211     LONG ref;
1212     SCRIPTINFO *script_info;
1213     DWORD total, pos;
1214 } EnumScript_impl;
1215
1216 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1217         IEnumScript* iface,
1218         REFIID riid,
1219         void** ppvObject)
1220 {
1221     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1222
1223     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1224
1225     if (IsEqualGUID(riid, &IID_IUnknown)
1226         || IsEqualGUID(riid, &IID_IEnumScript))
1227     {
1228         IEnumScript_AddRef(iface);
1229         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1230         *ppvObject = &(This->vtbl_IEnumScript);
1231         return S_OK;
1232     }
1233
1234     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1235     return E_NOINTERFACE;
1236 }
1237
1238 static ULONG WINAPI fnIEnumScript_AddRef(
1239         IEnumScript* iface)
1240 {
1241     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1242     return InterlockedIncrement(&This->ref);
1243 }
1244
1245 static ULONG WINAPI fnIEnumScript_Release(
1246         IEnumScript* iface)
1247 {
1248     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1249     ULONG ref = InterlockedDecrement(&This->ref);
1250
1251     TRACE("%p ref = %d\n", This, ref);
1252     if (ref == 0)
1253     {
1254         TRACE("Destroying %p\n", This);
1255         HeapFree(GetProcessHeap(), 0, This->script_info);
1256         HeapFree(GetProcessHeap(), 0, This);
1257     }
1258
1259     return ref;
1260 }
1261
1262 static HRESULT WINAPI fnIEnumScript_Clone(
1263         IEnumScript* iface,
1264         IEnumScript** ppEnum)
1265 {
1266     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1267     FIXME("%p %p: stub!\n", This, ppEnum);
1268     return E_NOTIMPL;
1269 }
1270
1271 static  HRESULT WINAPI fnIEnumScript_Next(
1272         IEnumScript* iface,
1273         ULONG celt,
1274         PSCRIPTINFO rgelt,
1275         ULONG* pceltFetched)
1276 {
1277     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1278     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1279
1280     if (!pceltFetched || !rgelt) return E_FAIL;
1281
1282     *pceltFetched = 0;
1283
1284     if (This->pos + celt > This->total)
1285         celt = This->total - This->pos;
1286
1287     if (!celt) return S_FALSE;
1288
1289     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1290     *pceltFetched = celt;
1291     This->pos += celt;
1292
1293     return S_OK;
1294 }
1295
1296 static HRESULT WINAPI fnIEnumScript_Reset(
1297         IEnumScript* iface)
1298 {
1299     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1300     TRACE("%p\n", This);
1301
1302     This->pos = 0;
1303     return S_OK;
1304 }
1305
1306 static  HRESULT WINAPI fnIEnumScript_Skip(
1307         IEnumScript* iface,
1308         ULONG celt)
1309 {
1310     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1311     TRACE("%p %u\n", This, celt);
1312
1313     if (celt >= This->total) return S_FALSE;
1314
1315     This->pos += celt;
1316     return S_OK;
1317 }
1318
1319 static const IEnumScriptVtbl IEnumScript_vtbl =
1320 {
1321     fnIEnumScript_QueryInterface,
1322     fnIEnumScript_AddRef,
1323     fnIEnumScript_Release,
1324     fnIEnumScript_Clone,
1325     fnIEnumScript_Next,
1326     fnIEnumScript_Reset,
1327     fnIEnumScript_Skip
1328 };
1329
1330 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1331                      LANGID LangId, IEnumScript** ppEnumScript )
1332 {
1333     EnumScript_impl *es;
1334     UINT i;
1335
1336     TRACE("%p, %08x, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1337
1338     if (!dwFlags) /* enumerate all available scripts */
1339         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1340
1341     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1342     es->vtbl_IEnumScript = &IEnumScript_vtbl;
1343     es->ref = 1;
1344     es->pos = 0;
1345     /* do not enumerate unicode flavours */
1346     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1347     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1348
1349     for (i = 0; i < es->total; i++)
1350     {
1351         es->script_info[i].ScriptId = i;
1352         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1353         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1354             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1355         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1356             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1357         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1358             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1359     }
1360
1361     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1362
1363     *ppEnumScript = (IEnumScript *)es;
1364
1365     return S_OK;
1366 }
1367
1368 /******************************************************************************/
1369
1370 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1371         IMLangFontLink* iface,
1372         REFIID riid,
1373         void** ppvObject)
1374 {
1375     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1376     return MLang_QueryInterface( This, riid, ppvObject );
1377 }
1378
1379 static ULONG WINAPI fnIMLangFontLink_AddRef(
1380         IMLangFontLink* iface)
1381 {
1382     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1383     return MLang_AddRef( This );
1384 }
1385
1386 static ULONG WINAPI fnIMLangFontLink_Release(
1387         IMLangFontLink* iface)
1388 {
1389     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1390     return MLang_Release( This );
1391 }
1392
1393 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1394         IMLangFontLink* iface,
1395         WCHAR chSrc,
1396         DWORD* pdwCodePages)
1397 {
1398     FIXME("\n");
1399     return E_NOTIMPL;
1400 }
1401
1402 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1403         IMLangFontLink* iface,
1404         const WCHAR* pszSrc,
1405         long cchSrc,
1406         DWORD dwPriorityCodePages,
1407         DWORD* pdwCodePages,
1408         long* pcchCodePages)
1409 {
1410     FIXME("(pszSrc=%s, cchSrc=%ld, dwPriorityCodePages=%d) stub\n", debugstr_w(pszSrc), cchSrc, dwPriorityCodePages);
1411     *pdwCodePages = 0;
1412     *pcchCodePages = 1;
1413     return S_OK;
1414 }
1415
1416 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1417         IMLangFontLink* iface,
1418         UINT uCodePage,
1419         DWORD* pdwCodePages)
1420 {
1421     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1422     CHARSETINFO cs;
1423     BOOL rc; 
1424
1425     TRACE("(%p) Seeking %u\n",This, uCodePage);
1426     memset(&cs, 0, sizeof(cs));
1427
1428     rc = TranslateCharsetInfo((DWORD*)uCodePage, &cs, TCI_SRCCODEPAGE);
1429
1430     if (rc)
1431     {
1432         *pdwCodePages = cs.fs.fsCsb[0];
1433         TRACE("resulting CodePages 0x%x\n",*pdwCodePages);
1434     }
1435     else
1436         TRACE("CodePage Not Found\n");
1437
1438     return S_OK;
1439 }
1440
1441 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1442         IMLangFontLink* iface,
1443         DWORD dwCodePages,
1444         UINT uDefaultCodePage,
1445         UINT* puCodePage)
1446 {
1447     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1448     DWORD mask = 0x00000000;
1449     UINT i;
1450     CHARSETINFO cs;
1451     BOOL rc; 
1452
1453     TRACE("(%p) scanning  0x%x  default page %u\n",This, dwCodePages,
1454             uDefaultCodePage);
1455
1456     *puCodePage = 0x00000000;
1457
1458     rc = TranslateCharsetInfo((DWORD*)uDefaultCodePage, &cs, TCI_SRCCODEPAGE);
1459   
1460     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
1461     {
1462         TRACE("Found Default Codepage\n");
1463         *puCodePage = uDefaultCodePage;
1464         return S_OK;
1465     }
1466
1467     
1468     for (i = 0; i < 32; i++)
1469     {
1470
1471         mask = 1 << i;
1472         if (dwCodePages & mask)
1473         {
1474             DWORD Csb[2];
1475             Csb[0] = mask;
1476             Csb[1] = 0x0;
1477             rc = TranslateCharsetInfo((DWORD*)Csb, &cs, TCI_SRCFONTSIG);
1478             if (!rc)
1479                 continue;
1480
1481             TRACE("Falling back to least significant found CodePage %u\n",
1482                     cs.ciACP);
1483             *puCodePage = cs.ciACP;
1484             return S_OK;
1485         }
1486     }
1487
1488     TRACE("no codepage found\n");
1489     return E_FAIL;
1490 }
1491
1492 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
1493         IMLangFontLink* iface,
1494         HDC hDC,
1495         HFONT hFont,
1496         DWORD* pdwCodePages)
1497 {
1498     HFONT old_font;
1499     FONTSIGNATURE fontsig;
1500     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1501
1502     TRACE("(%p)\n",This);
1503
1504     old_font = SelectObject(hDC,hFont);
1505     GetTextCharsetInfo(hDC,&fontsig, 0);
1506     SelectObject(hDC,old_font);
1507
1508     *pdwCodePages = fontsig.fsCsb[0];
1509     TRACE("CodePages is 0x%x\n",fontsig.fsCsb[0]);
1510
1511     return S_OK;
1512 }
1513
1514 static HRESULT WINAPI fnIMLangFontLink_MapFont(
1515         IMLangFontLink* iface,
1516         HDC hDC,
1517         DWORD dwCodePages,
1518         HFONT hSrcFont,
1519         HFONT* phDestFont)
1520 {
1521     FIXME("\n");
1522     return E_NOTIMPL;
1523 }
1524
1525 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
1526         IMLangFontLink* iface,
1527         HFONT hFont)
1528 {
1529     FIXME("\n");
1530     return E_NOTIMPL;
1531 }
1532
1533 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
1534         IMLangFontLink* iface)
1535 {
1536     FIXME("\n");
1537     return E_NOTIMPL;
1538 }
1539
1540
1541 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
1542 {
1543     fnIMLangFontLink_QueryInterface,
1544     fnIMLangFontLink_AddRef,
1545     fnIMLangFontLink_Release,
1546     fnIMLangFontLink_GetCharCodePages,
1547     fnIMLangFontLink_GetStrCodePages,
1548     fnIMLangFontLink_CodePageToCodePages,
1549     fnIMLangFontLink_CodePagesToCodePage,
1550     fnIMLangFontLink_GetFontCodePages,
1551     fnIMLangFontLink_MapFont,
1552     fnIMLangFontLink_ReleaseFont,
1553     fnIMLangFontLink_ResetFontMapping,
1554 };
1555
1556 /******************************************************************************/
1557
1558 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
1559     IMultiLanguage* iface,
1560     REFIID riid,
1561     void** ppvObject)
1562 {
1563     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1564     return MLang_QueryInterface( This, riid, ppvObject );
1565 }
1566
1567 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
1568 {
1569     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1570     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
1571 }
1572
1573 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
1574 {
1575     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1576     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
1577 }
1578
1579 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
1580     IMultiLanguage* iface,
1581     UINT* pcCodePage)
1582 {
1583     FIXME("\n");
1584     return E_NOTIMPL;
1585 }
1586
1587 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
1588     IMultiLanguage* iface,
1589     UINT uiCodePage,
1590     PMIMECPINFO pCodePageInfo)
1591 {
1592     UINT i, n;
1593
1594     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1595     TRACE("%p, %u, %p\n", This, uiCodePage, 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 fnIMultiLanguage_GetFamilyCodePage(
1613     IMultiLanguage* iface,
1614     UINT uiCodePage,
1615     UINT* puiFamilyCodePage)
1616 {
1617     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1618 }
1619
1620 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
1621     IMultiLanguage* iface,
1622     DWORD grfFlags,
1623     IEnumCodePage** ppEnumCodePage)
1624 {
1625     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1626     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
1627
1628     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
1629 }
1630
1631 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
1632     IMultiLanguage* iface,
1633     BSTR Charset,
1634     PMIMECSETINFO pCharsetInfo)
1635 {
1636     FIXME("\n");
1637     return E_NOTIMPL;
1638 }
1639
1640 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
1641     IMultiLanguage* iface,
1642     DWORD dwSrcEncoding,
1643     DWORD dwDstEncoding)
1644 {
1645     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
1646 }
1647
1648 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
1649     IMultiLanguage* iface,
1650     DWORD* pdwMode,
1651     DWORD dwSrcEncoding,
1652     DWORD dwDstEncoding,
1653     BYTE* pSrcStr,
1654     UINT* pcSrcSize,
1655     BYTE* pDstStr,
1656     UINT* pcDstSize)
1657 {
1658     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
1659         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
1660 }
1661
1662 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
1663     IMultiLanguage* iface,
1664     DWORD* pdwMode,
1665     DWORD dwEncoding,
1666     CHAR* pSrcStr,
1667     UINT* pcSrcSize,
1668     WCHAR* pDstStr,
1669     UINT* pcDstSize)
1670 {
1671     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
1672         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1673 }
1674
1675 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
1676     IMultiLanguage* iface,
1677     DWORD* pdwMode,
1678     DWORD dwEncoding,
1679     WCHAR* pSrcStr,
1680     UINT* pcSrcSize,
1681     CHAR* pDstStr,
1682     UINT* pcDstSize)
1683 {
1684     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
1685         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1686 }
1687
1688 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
1689     IMultiLanguage* iface)
1690 {
1691     FIXME("\n");
1692     return E_NOTIMPL;
1693 }
1694
1695 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
1696     IMultiLanguage* iface,
1697     LCID lcid,
1698     BSTR* pbstrRfc1766)
1699 {
1700     WCHAR buf[MAX_RFC1766_NAME];
1701
1702     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
1703
1704     if (lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
1705     {
1706         *pbstrRfc1766 = SysAllocString( buf );
1707         return S_OK;
1708     }
1709     return E_FAIL;
1710 }
1711
1712 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
1713     IMultiLanguage* iface,
1714     LCID* pLocale,
1715     BSTR bstrRfc1766)
1716 {
1717     HRESULT hr;
1718     IEnumRfc1766 *rfc1766;
1719
1720     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
1721
1722     if (!pLocale || !bstrRfc1766)
1723         return E_INVALIDARG;
1724
1725     hr = IMultiLanguage_EnumRfc1766(iface, &rfc1766);
1726     if (FAILED(hr))
1727         return hr;
1728
1729     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
1730
1731     IEnumRfc1766_Release(rfc1766);
1732     return hr;
1733 }
1734
1735 /******************************************************************************/
1736
1737 typedef struct tagEnumRfc1766_impl
1738 {
1739     const IEnumRfc1766Vtbl *vtbl_IEnumRfc1766;
1740     LONG ref;
1741     RFC1766INFO *info;
1742     DWORD total, pos;
1743 } EnumRfc1766_impl;
1744
1745 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
1746         IEnumRfc1766 *iface,
1747         REFIID riid,
1748         void** ppvObject)
1749 {
1750     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1751
1752     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1753
1754     if (IsEqualGUID(riid, &IID_IUnknown)
1755         || IsEqualGUID(riid, &IID_IEnumRfc1766))
1756     {
1757         IEnumRfc1766_AddRef(iface);
1758         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
1759         *ppvObject = &(This->vtbl_IEnumRfc1766);
1760         return S_OK;
1761     }
1762
1763     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
1764     return E_NOINTERFACE;
1765 }
1766
1767 static ULONG WINAPI fnIEnumRfc1766_AddRef(
1768         IEnumRfc1766 *iface)
1769 {
1770     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1771     return InterlockedIncrement(&This->ref);
1772 }
1773
1774 static ULONG WINAPI fnIEnumRfc1766_Release(
1775         IEnumRfc1766 *iface)
1776 {
1777     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1778     ULONG ref = InterlockedDecrement(&This->ref);
1779
1780     TRACE("%p ref = %d\n", This, ref);
1781     if (ref == 0)
1782     {
1783         TRACE("Destroying %p\n", This);
1784         HeapFree(GetProcessHeap(), 0, This->info);
1785         HeapFree(GetProcessHeap(), 0, This);
1786     }
1787     return ref;
1788 }
1789
1790 static HRESULT WINAPI fnIEnumRfc1766_Clone(
1791         IEnumRfc1766 *iface,
1792         IEnumRfc1766 **ppEnum)
1793 {
1794     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1795     FIXME("%p %p\n", This, ppEnum);
1796     return E_NOTIMPL;
1797 }
1798
1799 static  HRESULT WINAPI fnIEnumRfc1766_Next(
1800         IEnumRfc1766 *iface,
1801         ULONG celt,
1802         PRFC1766INFO rgelt,
1803         ULONG *pceltFetched)
1804 {
1805     ULONG i;
1806
1807     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1808     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1809
1810     if (!pceltFetched) return S_FALSE;
1811     *pceltFetched = 0;
1812
1813     if (!rgelt) return S_FALSE;
1814
1815     if (This->pos + celt > This->total)
1816         celt = This->total - This->pos;
1817
1818     if (!celt) return S_FALSE;
1819
1820     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
1821     *pceltFetched = celt;
1822     This->pos += celt;
1823
1824     for (i = 0; i < celt; i++)
1825     {
1826         TRACE("#%u: %08x %s %s\n",
1827               i, rgelt[i].lcid,
1828               wine_dbgstr_w(rgelt[i].wszRfc1766),
1829               wine_dbgstr_w(rgelt[i].wszLocaleName));
1830     }
1831     return S_OK;
1832 }
1833
1834 static HRESULT WINAPI fnIEnumRfc1766_Reset(
1835         IEnumRfc1766 *iface)
1836 {
1837     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1838     TRACE("%p\n", This);
1839
1840     This->pos = 0;
1841     return S_OK;
1842 }
1843
1844 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
1845         IEnumRfc1766 *iface,
1846         ULONG celt)
1847 {
1848     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1849     TRACE("%p %u\n", This, celt);
1850
1851     if (celt >= This->total) return S_FALSE;
1852
1853     This->pos += celt;
1854     return S_OK;
1855 }
1856
1857 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
1858 {
1859     fnIEnumRfc1766_QueryInterface,
1860     fnIEnumRfc1766_AddRef,
1861     fnIEnumRfc1766_Release,
1862     fnIEnumRfc1766_Clone,
1863     fnIEnumRfc1766_Next,
1864     fnIEnumRfc1766_Reset,
1865     fnIEnumRfc1766_Skip
1866 };
1867
1868 struct enum_locales_data
1869 {
1870     RFC1766INFO *info;
1871     DWORD total, allocated;
1872 };
1873
1874 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
1875 {
1876     WCHAR *end;
1877     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
1878     RFC1766INFO *info;
1879
1880     TRACE("%s\n", debugstr_w(locale));
1881
1882     if (data->total >= data->allocated)
1883     {
1884         data->allocated += 32;
1885         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
1886         if (!data->info) return FALSE;
1887     }
1888
1889     info = &data->info[data->total];
1890
1891     info->lcid = strtolW(locale, &end, 16);
1892     if (*end) /* invalid number */
1893         return FALSE;
1894
1895     info->wszRfc1766[0] = 0;
1896     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
1897
1898     info->wszLocaleName[0] = 0;
1899     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
1900     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
1901     
1902     data->total++;
1903
1904     return TRUE;
1905 }
1906
1907 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
1908 {
1909     EnumRfc1766_impl *rfc;
1910     struct enum_locales_data data;
1911
1912     TRACE("%04x, %p\n", LangId, ppEnum);
1913
1914     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
1915     rfc->vtbl_IEnumRfc1766 = &IEnumRfc1766_vtbl;
1916     rfc->ref = 1;
1917     rfc->pos = 0;
1918     rfc->total = 0;
1919
1920     data.total = 0;
1921     data.allocated = 32;
1922     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
1923     if (!data.info)
1924     {
1925         HeapFree(GetProcessHeap(), 0, rfc);
1926         return S_FALSE;
1927     }
1928
1929     TlsSetValue(MLANG_tls_index, &data);
1930     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
1931     TlsSetValue(MLANG_tls_index, NULL);
1932
1933     TRACE("enumerated %d rfc1766 structures\n", data.total);
1934
1935     if (!data.total)
1936     {
1937         HeapFree(GetProcessHeap(), 0, data.info);
1938         HeapFree(GetProcessHeap(), 0, rfc);
1939         return FALSE;
1940     }
1941
1942     rfc->info = data.info;
1943     rfc->total = data.total;
1944
1945     *ppEnum = (IEnumRfc1766 *)rfc;
1946     return S_OK;
1947 }
1948
1949 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
1950     IMultiLanguage *iface,
1951     IEnumRfc1766 **ppEnumRfc1766)
1952 {
1953     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1954     TRACE("%p %p\n", This, ppEnumRfc1766);
1955
1956     return EnumRfc1766_create(0, ppEnumRfc1766);
1957 }
1958
1959 /******************************************************************************/
1960
1961 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
1962     IMultiLanguage* iface,
1963     LCID Locale,
1964     PRFC1766INFO pRfc1766Info)
1965 {
1966     FIXME("\n");
1967     return E_NOTIMPL;
1968 }
1969
1970 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
1971     IMultiLanguage* iface,
1972     UINT uiSrcCodePage,
1973     UINT uiDstCodePage,
1974     DWORD dwProperty,
1975     IMLangConvertCharset** ppMLangConvertCharset)
1976 {
1977     FIXME("\n");
1978     return E_NOTIMPL;
1979 }
1980
1981 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
1982 {
1983     fnIMultiLanguage_QueryInterface,
1984     fnIMultiLanguage_AddRef,
1985     fnIMultiLanguage_Release,
1986     fnIMultiLanguage_GetNumberOfCodePageInfo,
1987     fnIMultiLanguage_GetCodePageInfo,
1988     fnIMultiLanguage_GetFamilyCodePage,
1989     fnIMultiLanguage_EnumCodePages,
1990     fnIMultiLanguage_GetCharsetInfo,
1991     fnIMultiLanguage_IsConvertible,
1992     fnIMultiLanguage_ConvertString,
1993     fnIMultiLanguage_ConvertStringToUnicode,
1994     fnIMultiLanguage_ConvertStringFromUnicode,
1995     fnIMultiLanguage_ConvertStringReset,
1996     fnIMultiLanguage_GetRfc1766FromLcid,
1997     fnIMultiLanguage_GetLcidFromRfc1766,
1998     fnIMultiLanguage_EnumRfc1766,
1999     fnIMultiLanguage_GetRfc1766Info,
2000     fnIMultiLanguage_CreateConvertCharset,
2001 };
2002
2003
2004 /******************************************************************************/
2005
2006 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
2007     IMultiLanguage3* iface,
2008     REFIID riid,
2009     void** ppvObject)
2010 {
2011     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2012     return MLang_QueryInterface( This, riid, ppvObject );
2013 }
2014
2015 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
2016 {
2017     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2018     return MLang_AddRef( This );
2019 }
2020
2021 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
2022 {
2023     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2024     return MLang_Release( This );
2025 }
2026
2027 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
2028     IMultiLanguage3* iface,
2029     UINT* pcCodePage)
2030 {
2031     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2032     TRACE("%p, %p\n", This, pcCodePage);
2033
2034     if (!pcCodePage) return S_FALSE;
2035
2036     *pcCodePage = This->total_cp;
2037     return S_OK;
2038 }
2039
2040 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2041 {
2042     CHARSETINFO csi;
2043
2044     if (TranslateCharsetInfo((DWORD *)ml_data->family_codepage, &csi, TCI_SRCCODEPAGE))
2045         mime_cp_info->bGDICharset = csi.ciCharset;
2046     else
2047         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2048
2049     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2050     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2051     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2052     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2053                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
2054     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2055                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
2056     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2057                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
2058     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2059                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
2060
2061     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2062         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
2063     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2064         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
2065
2066     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2067           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2068           mime_cp_info->uiFamilyCodePage,
2069           wine_dbgstr_w(mime_cp_info->wszDescription),
2070           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2071           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2072           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2073           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2074           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2075           mime_cp_info->bGDICharset);
2076 }
2077
2078 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
2079     IMultiLanguage3* iface,
2080     UINT uiCodePage,
2081     LANGID LangId,
2082     PMIMECPINFO pCodePageInfo)
2083 {
2084     UINT i, n;
2085
2086     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2087     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2088
2089     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2090     {
2091         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2092         {
2093             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2094             {
2095                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2096                 return S_OK;
2097             }
2098         }
2099     }
2100
2101     return S_FALSE;
2102 }
2103
2104 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
2105     IMultiLanguage3* iface,
2106     UINT uiCodePage,
2107     UINT* puiFamilyCodePage)
2108 {
2109     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2110 }
2111
2112 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
2113     IMultiLanguage3* iface,
2114     DWORD grfFlags,
2115     LANGID LangId,
2116     IEnumCodePage** ppEnumCodePage)
2117 {
2118     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2119     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2120
2121     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2122 }
2123
2124 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
2125     IMultiLanguage3* iface,
2126     BSTR Charset,
2127     PMIMECSETINFO pCharsetInfo)
2128 {
2129     UINT i, n;
2130
2131     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2132     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2133
2134     if (!pCharsetInfo) return E_FAIL;
2135
2136     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2137     {
2138         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2139         {
2140             WCHAR csetW[MAX_MIMECSET_NAME];
2141
2142             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2143             if (!lstrcmpiW(Charset, csetW))
2144             {
2145                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2146                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2147                 strcpyW(pCharsetInfo->wszCharset, csetW);
2148                 return S_OK;
2149             }
2150         }
2151     }
2152
2153     /* FIXME:
2154      * Since we do not support charsets like iso-2022-jp and do not have
2155      * them in our database as a primary (web_charset) encoding this loop
2156      * does an attempt to 'approximate' charset name by header_charset.
2157      */
2158     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2159     {
2160         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2161         {
2162             WCHAR csetW[MAX_MIMECSET_NAME];
2163
2164             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2165             if (!lstrcmpiW(Charset, csetW))
2166             {
2167                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2168                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2169                 strcpyW(pCharsetInfo->wszCharset, csetW);
2170                 return S_OK;
2171             }
2172         }
2173     }
2174
2175     return E_FAIL;
2176 }
2177
2178 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2179     IMultiLanguage3* iface,
2180     DWORD dwSrcEncoding,
2181     DWORD dwDstEncoding)
2182 {
2183     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2184 }
2185
2186 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2187     IMultiLanguage3* iface,
2188     DWORD* pdwMode,
2189     DWORD dwSrcEncoding,
2190     DWORD dwDstEncoding,
2191     BYTE* pSrcStr,
2192     UINT* pcSrcSize,
2193     BYTE* pDstStr,
2194     UINT* pcDstSize)
2195 {
2196     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2197         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2198 }
2199
2200 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2201     IMultiLanguage3* iface,
2202     DWORD* pdwMode,
2203     DWORD dwEncoding,
2204     CHAR* pSrcStr,
2205     UINT* pcSrcSize,
2206     WCHAR* pDstStr,
2207     UINT* pcDstSize)
2208 {
2209     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2210         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2211 }
2212
2213 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2214     IMultiLanguage3* iface,
2215     DWORD* pdwMode,
2216     DWORD dwEncoding,
2217     WCHAR* pSrcStr,
2218     UINT* pcSrcSize,
2219     CHAR* pDstStr,
2220     UINT* pcDstSize)
2221 {
2222     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2223         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2224 }
2225
2226 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2227     IMultiLanguage3* iface)
2228 {
2229     FIXME("\n");
2230     return E_NOTIMPL;
2231 }
2232
2233 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2234     IMultiLanguage3* iface,
2235     LCID lcid,
2236     BSTR* pbstrRfc1766)
2237 {
2238     WCHAR buf[MAX_RFC1766_NAME];
2239
2240     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2241
2242     if (lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2243     {
2244         *pbstrRfc1766 = SysAllocString( buf );
2245         return S_OK;
2246     }
2247     return E_FAIL;
2248 }
2249
2250 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2251     IMultiLanguage3* iface,
2252     LCID* pLocale,
2253     BSTR bstrRfc1766)
2254 {
2255     HRESULT hr;
2256     IEnumRfc1766 *rfc1766;
2257
2258     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2259
2260     if (!pLocale || !bstrRfc1766)
2261         return E_INVALIDARG;
2262
2263     hr = IMultiLanguage2_EnumRfc1766(iface, 0, &rfc1766);
2264     if (FAILED(hr))
2265         return hr;
2266
2267     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2268
2269     IEnumRfc1766_Release(rfc1766);
2270     return hr;
2271 }
2272
2273 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2274     IMultiLanguage3* iface,
2275     LANGID LangId,
2276     IEnumRfc1766** ppEnumRfc1766)
2277 {
2278     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2279     TRACE("%p %p\n", This, ppEnumRfc1766);
2280
2281     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2282 }
2283
2284 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2285     IMultiLanguage3* iface,
2286     LCID Locale,
2287     LANGID LangId,
2288     PRFC1766INFO pRfc1766Info)
2289 {
2290     FIXME("\n");
2291     return E_NOTIMPL;
2292 }
2293
2294 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2295     IMultiLanguage3* iface,
2296     UINT uiSrcCodePage,
2297     UINT uiDstCodePage,
2298     DWORD dwProperty,
2299     IMLangConvertCharset** ppMLangConvertCharset)
2300 {
2301     FIXME("\n");
2302     return E_NOTIMPL;
2303 }
2304
2305 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2306     IMultiLanguage3* iface,
2307     DWORD* pdwMode,
2308     DWORD dwFlag,
2309     WCHAR* lpFallBack,
2310     DWORD dwSrcEncoding,
2311     DWORD dwDstEncoding,
2312     IStream* pstmIn,
2313     IStream* pstmOut)
2314 {
2315     FIXME("\n");
2316     return E_NOTIMPL;
2317 }
2318
2319 /*
2320  * TODO: handle dwFlag and lpFallBack
2321 */
2322 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
2323     IMultiLanguage3* iface,
2324     DWORD* pdwMode,
2325     DWORD dwEncoding,
2326     CHAR* pSrcStr,
2327     UINT* pcSrcSize,
2328     WCHAR* pDstStr,
2329     UINT* pcDstSize,
2330     DWORD dwFlag,
2331     WCHAR* lpFallBack)
2332 {
2333     FIXME("\n");
2334     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2335         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2336 }
2337
2338 /*****************************************************************************
2339  * MultiLanguage2::ConvertStringToUnicodeEx
2340  *
2341  * Translates the multibyte string from the specified code page to Unicode.
2342  *
2343  * PARAMS
2344  *   see ConvertStringToUnicode
2345  *   dwFlag 
2346  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
2347  *              instead unconvertible characters.
2348  *
2349  * RETURNS
2350  *   S_OK     Success.
2351  *   S_FALSE  The conversion is not supported.
2352  *   E_FAIL   Some error has occurred.
2353  *
2354  * TODO: handle dwFlag and lpFallBack
2355 */
2356 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
2357     IMultiLanguage3* This,
2358     DWORD* pdwMode,
2359     DWORD dwEncoding,
2360     WCHAR* pSrcStr,
2361     UINT* pcSrcSize,
2362     CHAR* pDstStr,
2363     UINT* pcDstSize,
2364     DWORD dwFlag,
2365     WCHAR* lpFallBack)
2366 {
2367     FIXME("\n");
2368     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2369         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2370 }
2371
2372 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
2373     IMultiLanguage3* iface,
2374     DWORD dwFlag,
2375     DWORD dwPrefWinCodePage,
2376     IStream* pstmIn,
2377     DetectEncodingInfo* lpEncoding,
2378     INT* pnScores)
2379 {
2380     FIXME("\n");
2381     return E_NOTIMPL;
2382 }
2383
2384 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
2385     IMultiLanguage3* iface,
2386     DWORD dwFlag,
2387     DWORD dwPrefWinCodePage,
2388     CHAR* pSrcStr,
2389     INT* pcSrcSize,
2390     DetectEncodingInfo* lpEncoding,
2391     INT* pnScores)
2392 {
2393     FIXME("\n");
2394     return E_NOTIMPL;
2395 }
2396
2397 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
2398     IMultiLanguage3* iface,
2399     UINT uiCodePage,
2400     HWND hwnd)
2401 {
2402     FIXME("%u, %p\n", uiCodePage, hwnd);
2403     return E_NOTIMPL;
2404 }
2405
2406 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
2407     IMultiLanguage3* iface,
2408     UINT uiCodePage,
2409     LCID lcid,
2410     LPWSTR lpWideCharStr,
2411     int cchWideChar)
2412 {
2413     FIXME("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
2414     return E_NOTIMPL;
2415 }
2416
2417 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
2418     IMultiLanguage3* iface,
2419     UINT uiCodePage)
2420 {
2421     FIXME("%u\n", uiCodePage);
2422     return E_NOTIMPL;
2423 }
2424
2425 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
2426     IMultiLanguage3* iface,
2427     MIMECONTF dwSource)
2428 {
2429     FIXME("0x%08x\n", dwSource);
2430     return S_OK;
2431 }
2432
2433 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
2434     IMultiLanguage3* iface,
2435     UINT* pnScripts)
2436 {
2437     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2438     TRACE("%p %p\n", This, pnScripts);
2439
2440     if (!pnScripts) return S_FALSE;
2441
2442     *pnScripts = This->total_scripts;
2443     return S_OK;
2444 }
2445
2446 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
2447     IMultiLanguage3* iface,
2448     DWORD dwFlags,
2449     LANGID LangId,
2450     IEnumScript** ppEnumScript)
2451 {
2452     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2453     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
2454
2455     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
2456 }
2457
2458 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
2459     IMultiLanguage3* iface,
2460     UINT uiCodePage,
2461     HWND hwnd,
2462     DWORD dwfIODControl)
2463 {
2464     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2465     FIXME("%p %u %p %08x: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
2466
2467     return S_FALSE;
2468 }
2469
2470 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
2471     IMultiLanguage3 *iface,
2472     DWORD dwFlags,
2473     LPCWSTR lpWideCharStr,
2474     UINT cchWideChar,
2475     UINT *puiPreferredCodePages,
2476     UINT nPreferredCodePages,
2477     UINT *puiDetectedCodePages,
2478     UINT *pnDetectedCodePages,
2479     WCHAR *lpSpecialChar)
2480 {
2481     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2482     FIXME("(%p)->(%08x %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
2483           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
2484           pnDetectedCodePages, lpSpecialChar);
2485     return E_NOTIMPL;
2486 }
2487
2488 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
2489     IMultiLanguage3 *iface,
2490     DWORD dwFlags,
2491     IStream *pStrIn,
2492     UINT *puiPreferredCodePages,
2493     UINT nPreferredCodePages,
2494     UINT *puiDetectedCodePages,
2495     UINT *pnDetectedCodePages,
2496     WCHAR *lpSpecialChar)
2497 {
2498     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2499     FIXME("(%p)->(%08x %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
2500           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
2501           pnDetectedCodePages, lpSpecialChar);
2502     return E_NOTIMPL;
2503 }
2504
2505 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
2506 {
2507     fnIMultiLanguage2_QueryInterface,
2508     fnIMultiLanguage2_AddRef,
2509     fnIMultiLanguage2_Release,
2510     fnIMultiLanguage2_GetNumberOfCodePageInfo,
2511     fnIMultiLanguage2_GetCodePageInfo,
2512     fnIMultiLanguage2_GetFamilyCodePage,
2513     fnIMultiLanguage2_EnumCodePages,
2514     fnIMultiLanguage2_GetCharsetInfo,
2515     fnIMultiLanguage2_IsConvertible,
2516     fnIMultiLanguage2_ConvertString,
2517     fnIMultiLanguage2_ConvertStringToUnicode,
2518     fnIMultiLanguage2_ConvertStringFromUnicode,
2519     fnIMultiLanguage2_ConvertStringReset,
2520     fnIMultiLanguage2_GetRfc1766FromLcid,
2521     fnIMultiLanguage2_GetLcidFromRfc1766,
2522     fnIMultiLanguage2_EnumRfc1766,
2523     fnIMultiLanguage2_GetRfc1766Info,
2524     fnIMultiLanguage2_CreateConvertCharset,
2525     fnIMultiLanguage2_ConvertStringInIStream,
2526     fnIMultiLanguage2_ConvertStringToUnicodeEx,
2527     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
2528     fnIMultiLanguage2_DetectCodepageInIStream,
2529     fnIMultiLanguage2_DetectInputCodepage,
2530     fnIMultiLanguage2_ValidateCodePage,
2531     fnIMultiLanguage2_GetCodePageDescription,
2532     fnIMultiLanguage2_IsCodePageInstallable,
2533     fnIMultiLanguage2_SetMimeDBSource,
2534     fnIMultiLanguage2_GetNumberOfScripts,
2535     fnIMultiLanguage2_EnumScripts,
2536     fnIMultiLanguage2_ValidateCodePageEx,
2537     fnIMultiLanguage3_DetectOutboundCodePage,
2538     fnIMultiLanguage3_DetectOutboundCodePageInIStream
2539 };
2540
2541 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
2542 {
2543     MLang_impl *mlang;
2544     UINT i;
2545
2546     TRACE("Creating MultiLanguage object\n");
2547
2548     if( pUnkOuter )
2549         return CLASS_E_NOAGGREGATION;
2550
2551     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
2552     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
2553     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
2554     mlang->vtbl_IMultiLanguage3 = &IMultiLanguage3_vtbl;
2555
2556     mlang->total_cp = 0;
2557     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2558         mlang->total_cp += mlang_data[i].number_of_cp;
2559
2560     /* do not enumerate unicode flavours */
2561     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
2562
2563     mlang->ref = 1;
2564     *ppObj = (LPVOID) mlang;
2565     TRACE("returning %p\n", mlang);
2566
2567     LockModule();
2568
2569     return S_OK;
2570 }
2571
2572 /******************************************************************************/
2573
2574 HRESULT WINAPI DllCanUnloadNow(void)
2575 {
2576     return dll_count == 0 ? S_OK : S_FALSE;
2577 }
2578
2579 HRESULT WINAPI GetGlobalFontLinkObject(void)
2580 {
2581     FIXME("\n");
2582     return S_FALSE;
2583 }