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