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