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