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