mlang/tests: Add tests for LcidToRfc1766.
[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  * Copyright 2009 Detlef Riekenberg
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "ole2.h"
36 #include "mlang.h"
37
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(mlang);
42
43 #include "initguid.h"
44
45 #define CP_UNICODE 1200
46
47 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj);
48 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum);
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 (Auto-Select)",
261       50932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
262              MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
263              MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
264       "_autodetect", "_autodetect", "_autodetect" },
265     { "Japanese (EUC)",
266       51932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
267              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
268              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
269              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
270       "euc-jp", "euc-jp", "euc-jp" },
271     { "Japanese (JIS)",
272       50220, MIMECONTF_IMPORT | MIMECONTF_MAILNEWS | MIMECONTF_EXPORT |
273              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
274              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST |
275              MIMECONTF_MIME_IE4,
276       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
277     { "Japanese (JIS 0208-1990 and 0212-1990)",
278       20932, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
279              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
280       "EUC-JP","EUC-JP","EUC-JP"},
281     { "Japanese (JIS-Allow 1 byte Kana)",
282       50221, MIMECONTF_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_SAVABLE_BROWSER |
283              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
284              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
285       "csISO2022JP","iso-2022-jp","iso-2022-jp"},
286     { "Japanese (JIS-Allow 1 byte Kana - SO/SI)",
287       50222, MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_VALID |
288              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
289       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
290     { "Japanese (Mac)",
291       10001, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
292              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
293       "x-mac-japanese","x-mac-japanese","x-mac-japanese"},
294     { "Japanese (Shift-JIS)",
295       932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
296            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
297            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
298            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
299       "shift_jis", "iso-2022-jp", "iso-2022-jp" }
300 };
301 static const MIME_CP_INFO korean_cp[] =
302 {
303     { "Korean",
304       949, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
305            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
306            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
307            MIMECONTF_MIME_LATEST,
308       "ks_c_5601-1987", "ks_c_5601-1987", "ks_c_5601-1987" }
309 };
310 static const MIME_CP_INFO thai_cp[] =
311 {
312     { "Thai (Windows)",
313       874, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_MIME_LATEST,
314       "ibm-thai", "ibm-thai", "ibm-thai" }
315 };
316 static const MIME_CP_INFO turkish_cp[] =
317 {
318     { "Turkish (DOS)",
319       857, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
320            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
321       "ibm857", "ibm857", "ibm857" },
322     { "IBM EBCDIC (Turkish Latin-5)",
323       1026, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
324             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
325       "ibm1026", "ibm1026", "ibm1026" },
326     { "Turkish (Windows)",
327       1254, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
328             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
329             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
330             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
331       "windows-1254", "windows-1254", "windows-1254" },
332     { "Turkish (Mac)",
333       10081, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
334              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
335       "x-mac-turkish", "x-mac-turkish", "x-mac-turkish" },
336     { "Latin 3 (ISO)",
337       28593, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
338              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
339              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
340       "iso-8859-3", "iso-8859-3", "iso-8859-3" },
341     { "Turkish (ISO)",
342       28599, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
343              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
344              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
345              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
346       "iso-8859-9", "iso-8859-9", "iso-8859-9" }
347 };
348 static const MIME_CP_INFO vietnamese_cp[] =
349 {
350     { "Vietnamese (Windows)",
351       1258, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
352             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
353             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
354             MIMECONTF_MIME_LATEST,
355       "windows-1258", "windows-1258", "windows-1258" }
356 };
357 static const MIME_CP_INFO western_cp[] =
358 {
359     { "IBM EBCDIC (US-Canada)",
360       37, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
361           MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
362       "ibm037", "ibm037", "ibm037" },
363     { "OEM United States",
364       437, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
365            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
366       "ibm437", "ibm437", "ibm437" },
367     { "IBM EBCDIC (International)",
368       500, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
369            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
370       "ibm500", "ibm500", "ibm500" },
371     { "Western European (DOS)",
372       850, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
373            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
374       "ibm850", "ibm850", "ibm850" },
375     { "Portuguese (DOS)",
376       860, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
377            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
378       "ibm860", "ibm860", "ibm860" },
379     { "Icelandic (DOS)",
380       861, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
381            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
382       "ibm861", "ibm861", "ibm861" },
383     { "French Canadian (DOS)",
384       863, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
385            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
386       "ibm863", "ibm863", "ibm863" },
387     { "Nordic (DOS)",
388       865, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
389            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
390       "ibm865", "ibm865", "ibm865" },
391     { "Western European (Windows)",
392       1252, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
393             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
394             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
395             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
396       "windows-1252", "windows-1252", "iso-8859-1" },
397     { "Western European (Mac)",
398       10000, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
399              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
400       "macintosh", "macintosh", "macintosh" },
401     { "Icelandic (Mac)",
402       10079, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
403              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
404       "x-mac-icelandic", "x-mac-icelandic", "x-mac-icelandic" },
405     { "US-ASCII",
406       20127, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT | MIMECONTF_EXPORT |
407              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID |
408              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
409       "us-ascii", "us-ascii", "us-ascii" },
410     { "Western European (ISO)",
411       28591, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
412              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
413              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
414              MIMECONTF_MIME_LATEST,
415       "iso-8859-1", "iso-8859-1", "iso-8859-1" },
416     { "Latin 9 (ISO)",
417       28605, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
418              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
419              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
420              MIMECONTF_MIME_LATEST,
421       "iso-8859-15", "iso-8859-15", "iso-8859-15" }
422 };
423 static const MIME_CP_INFO unicode_cp[] =
424 {
425     { "Unicode",
426       CP_UNICODE, MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
427                   MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
428                   MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
429                   MIMECONTF_MIME_LATEST,
430       "unicode", "unicode", "unicode" },
431     { "Unicode (UTF-7)",
432       CP_UTF7, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
433                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
434                MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
435       "utf-7", "utf-7", "utf-7" },
436     { "Unicode (UTF-8)",
437       CP_UTF8, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
438                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
439                MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
440                MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
441       "utf-8", "utf-8", "utf-8" }
442 };
443
444 static const struct mlang_data
445 {
446     const char *description;
447     UINT family_codepage;
448     UINT number_of_cp;
449     const MIME_CP_INFO *mime_cp_info;
450     const char *fixed_font;
451     const char *proportional_font;
452     SCRIPT_ID sid;
453 } mlang_data[] =
454 {
455     { "Arabic",1256,sizeof(arabic_cp)/sizeof(arabic_cp[0]),arabic_cp,
456       "Courier","Arial", sidArabic }, /* FIXME */
457     { "Baltic",1257,sizeof(baltic_cp)/sizeof(baltic_cp[0]),baltic_cp,
458       "Courier","Arial" }, /* FIXME */
459     { "Chinese Simplified",936,sizeof(chinese_simplified_cp)/sizeof(chinese_simplified_cp[0]),chinese_simplified_cp,
460       "Courier","Arial" }, /* FIXME */
461     { "Chinese Traditional",950,sizeof(chinese_traditional_cp)/sizeof(chinese_traditional_cp[0]),chinese_traditional_cp,
462       "Courier","Arial" }, /* FIXME */
463     { "Central European",1250,sizeof(central_european_cp)/sizeof(central_european_cp[0]),central_european_cp,
464       "Courier","Arial" }, /* FIXME */
465     { "Cyrillic",1251,sizeof(cyrillic_cp)/sizeof(cyrillic_cp[0]),cyrillic_cp,
466       "Courier","Arial", sidCyrillic }, /* FIXME */
467     { "Greek",1253,sizeof(greek_cp)/sizeof(greek_cp[0]),greek_cp,
468       "Courier","Arial", sidGreek }, /* FIXME */
469     { "Hebrew",1255,sizeof(hebrew_cp)/sizeof(hebrew_cp[0]),hebrew_cp,
470       "Courier","Arial", sidHebrew }, /* FIXME */
471     { "Japanese",932,sizeof(japanese_cp)/sizeof(japanese_cp[0]),japanese_cp,
472       "MS Gothic","MS PGothic" },
473     { "Korean",949,sizeof(korean_cp)/sizeof(korean_cp[0]),korean_cp,
474       "Courier","Arial" }, /* FIXME */
475     { "Thai",874,sizeof(thai_cp)/sizeof(thai_cp[0]),thai_cp,
476       "Courier","Arial", sidThai }, /* FIXME */
477     { "Turkish",1254,sizeof(turkish_cp)/sizeof(turkish_cp[0]),turkish_cp,
478       "Courier","Arial" }, /* FIXME */
479     { "Vietnamese",1258,sizeof(vietnamese_cp)/sizeof(vietnamese_cp[0]),vietnamese_cp,
480       "Courier","Arial" }, /* FIXME */
481     { "Western European",1252,sizeof(western_cp)/sizeof(western_cp[0]),western_cp,
482       "Courier","Arial", sidLatin }, /* FIXME */
483     { "Unicode",CP_UNICODE,sizeof(unicode_cp)/sizeof(unicode_cp[0]),unicode_cp,
484       "Courier","Arial" } /* FIXME */
485 };
486
487 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info);
488
489 static LONG dll_count;
490
491 /*
492  * Japanese Detection and Converstion Functions
493  */
494
495 #define HANKATA(A)  ((A >= 161) && (A <= 223))
496 #define ISEUC(A)    ((A >= 161) && (A <= 254))
497 #define NOTEUC(A,B) (((A >= 129) && (A <= 159)) && ((B >= 64) && (B <= 160)))
498 #define SJIS1(A)    (((A >= 129) && (A <= 159)) || ((A >= 224) && (A <= 239)))
499 #define SJIS2(A)    ((A >= 64) && (A <= 252))
500 #define ISMARU(A)   ((A >= 202) && (A <= 206))
501 #define ISNIGORI(A) (((A >= 182) && (A <= 196)) || ((A >= 202) && (A <= 206)))
502
503 static UINT DetectJapaneseCode(LPCSTR input, DWORD count)
504 {
505     UINT code = 0;
506     DWORD i = 0;
507     unsigned char c1,c2;
508
509     while ((code == 0 || code == 51932) && i < count)
510     {
511         c1 = input[i];
512         if (c1 == 0x1b /* ESC */)
513         {
514             i++;
515             if (i >= count)
516                 return code;
517             c1 = input[i];
518             if (c1 == '$')
519             {
520                 i++;
521                 if (i >= count)
522                     return code;
523                 c1 = input[i];
524                 if (c1 =='B' || c1 == '@')
525                     code = 50220;
526             }
527             if (c1 == 'K')
528                 code = 50220;
529         }
530         else if (c1 >= 129)
531         {
532             i++;
533             if (i >= count)
534                 return code;
535             c2 = input[i];
536             if NOTEUC(c1,c2)
537                 code = 932;
538             else if (ISEUC(c1) && ISEUC(c2))
539                 code = 51932;
540             else if (((c1 == 142)) && HANKATA(c2))
541                 code = 51932;
542         }
543         i++;
544     }
545     return code;
546 }
547
548 static inline void jis2sjis(unsigned char *p1, unsigned char *p2)
549 {
550     unsigned char c1 = *p1;
551     unsigned char c2 = *p2;
552     int row = c1 < 95 ? 112 : 176;
553     int cell = c1 % 2 ? 31 + (c2 > 95) : 126;
554
555     *p1 = ((c1 + 1) >> 1) + row;
556     *p2 = c2 + cell;
557 }
558
559 static inline void sjis2jis(unsigned char *p1, unsigned char *p2)
560 {
561     unsigned char c1 = *p1;
562     unsigned char c2 = *p2;
563     int shift = c2 < 159;
564     int row = c1 < 160 ? 112 : 176;
565     int cell = shift ? (31 + (c2 > 127)): 126;
566
567     *p1 = ((c1 - row) << 1) - shift;
568     *p2 -= cell;
569 }
570
571 static int han2zen(unsigned char *p1, unsigned char *p2)
572 {
573     int maru = FALSE;
574     int nigori = FALSE;
575     static const unsigned char char1[] = {129,129,129,129,129,131,131,131,131,
576         131,131,131,131,131,131,129,131,131,131,131,131,131,131,131,131,131,
577         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
578         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
579         131,129,129 };
580     static const unsigned char char2[] = {66,117,118,65,69,146,64,66,68,70,
581         72,131,133,135,98,91,65,67,69,71,73,74,76,78,80,82,84,86,88,90,92,94,
582         96,99,101,103,105,106,107,108,109,110,113,116,119,122,125,126,128,
583         129,130,132,134,136,137,138,139,140,141,143,147,74,75};
584
585     if (( *p2 == 222) && ((ISNIGORI(*p1) || (*p1 == 179))))
586             nigori = TRUE;
587     else if ((*p2 == 223) && (ISMARU(*p1)))
588             maru = TRUE;
589
590     if (*p1 >= 161 && *p1 <= 223)
591     {
592         unsigned char index = *p1 - 161;
593         *p1 = char1[index];
594         *p2 = char2[index];
595     }
596
597     if (maru || nigori)
598     {
599         if (nigori)
600         {
601             if (((*p2 >= 74) && (*p2 <= 103)) || ((*p2 >= 110) && (*p2 <= 122)))
602                 (*p2)++;
603             else if ((*p1 == 131) && (*p2 == 69))
604                 *p2 = 148;
605         }
606         else if ((maru) && ((*p2 >= 110) && (*p2 <= 122)))
607             *p2+= 2;
608
609         return 1;
610     }
611
612     return 0;
613 }
614
615
616 static UINT ConvertJIS2SJIS(LPCSTR input, DWORD count, LPSTR output)
617 {
618     DWORD i = 0;
619     int j = 0;
620     unsigned char p2,p;
621     int shifted = FALSE;
622
623     while (i < count)
624     {
625         p = input[i];
626         if (p == 0x1b /* ESC */)
627         {
628             i++;
629             if (i >= count)
630                 return 0;
631             p2 = input[i];
632             if (p2 == '$' || p2 =='(')
633                 i++;
634             if (p2 == 'K' || p2 =='$')
635                 shifted = TRUE;
636             else
637                 shifted = FALSE;
638         }
639         else
640         {
641             if (shifted)
642             {
643                 i++;
644                 if (i >= count)
645                     return 0;
646                 p2 = input[i];
647                 jis2sjis(&p,&p2);
648                 output[j++]=p;
649                 output[j++]=p2;
650             }
651             else
652             {
653                 output[j++] = p;
654             }
655         }
656         i++;
657     }
658     return j;
659 }
660
661 static inline int exit_shift(LPSTR out, int c)
662 {
663     if (out)
664     {
665         out[c] = 0x1b;
666         out[c+1] = '(';
667         out[c+2] = 'B';
668     }
669     return 3;
670 }
671
672 static inline int enter_shift(LPSTR out, int c)
673 {
674     if (out)
675     {
676         out[c] = 0x1b;
677         out[c+1] = '$';
678         out[c+2] = 'B';
679     }
680     return 3;
681 }
682
683
684 static UINT ConvertSJIS2JIS(LPCSTR input, DWORD count, LPSTR output)
685 {
686     DWORD i = 0;
687     int j = 0;
688     unsigned char p2,p;
689     int shifted = FALSE;
690
691     while (i < count)
692     {
693         p = input[i] & 0xff;
694         if (p == 10 || p == 13) /* NL and CR */
695         {
696             if (shifted)
697             {
698                 shifted = FALSE;
699                 j += exit_shift(output,j);
700             }
701             if (output)
702                 output[j++] = p;
703             else
704                 j++;
705         }
706         else
707         {
708             if (SJIS1(p))
709             {
710                 i++;
711                 if (i >= count)
712                     return 0;
713                 p2 = input[i] & 0xff;
714                 if (SJIS2(p2))
715                 {
716                     sjis2jis(&p,&p2);
717                     if (!shifted)
718                     {
719                         shifted = TRUE;
720                         j+=enter_shift(output,j);
721                     }
722                 }
723
724                 if (output)
725                 {
726                     output[j++]=p;
727                     output[j++]=p2;
728                 }
729                 else
730                     j+=2;
731             }
732             else
733             {
734                 if (HANKATA(p))
735                 {
736                     if ((i+1) >= count)
737                         return 0;
738                     p2 = input[i+1] & 0xff;
739                     i+=han2zen(&p,&p2);
740                     sjis2jis(&p,&p2);
741                     if (!shifted)
742                     {
743                         shifted = TRUE;
744                         j+=enter_shift(output,j);
745                     }
746                     if (output)
747                     {
748                         output[j++]=p;
749                         output[j++]=p2;
750                     }
751                     else
752                         j+=2;
753                 }
754                 else
755                 {
756                     if (shifted)
757                     {
758                         shifted = FALSE;
759                         j += exit_shift(output,j);
760                     }
761                     if (output)
762                         output[j++]=p;
763                     else
764                         j++;
765                 }
766             }
767         }
768         i++;
769     }
770     if (shifted)
771         j += exit_shift(output,j);
772     return j;
773 }
774
775 static UINT ConvertJISJapaneseToUnicode(LPCSTR input, DWORD count,
776                                         LPWSTR output, DWORD out_count)
777 {
778     CHAR *sjis_string;
779     UINT rc = 0;
780     sjis_string = HeapAlloc(GetProcessHeap(),0,count);
781     rc = ConvertJIS2SJIS(input,count,sjis_string);
782     if (rc)
783     {
784         TRACE("%s\n",debugstr_an(sjis_string,rc));
785         if (output)
786             rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
787         else
788             rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
789     }
790     HeapFree(GetProcessHeap(),0,sjis_string);
791     return rc;
792
793 }
794
795 static UINT ConvertUnknownJapaneseToUnicode(LPCSTR input, DWORD count,
796                                             LPWSTR output, DWORD out_count)
797 {
798     CHAR *sjis_string;
799     UINT rc = 0;
800     int code = DetectJapaneseCode(input,count);
801     TRACE("Japanese code %i\n",code);
802
803     switch (code)
804     {
805     case 0:
806         if (output)
807             rc = MultiByteToWideChar(CP_ACP,0,input,count,output,out_count);
808         else
809             rc = MultiByteToWideChar(CP_ACP,0,input,count,0,0);
810         break;
811
812     case 932:
813         if (output)
814             rc = MultiByteToWideChar(932,0,input,count,output,out_count);
815         else
816             rc = MultiByteToWideChar(932,0,input,count,0,0);
817         break;
818
819     case 51932:
820         if (output)
821             rc = MultiByteToWideChar(20932,0,input,count,output,out_count);
822         else
823             rc = MultiByteToWideChar(20932,0,input,count,0,0);
824         break;
825
826     case 50220:
827         sjis_string = HeapAlloc(GetProcessHeap(),0,count);
828         rc = ConvertJIS2SJIS(input,count,sjis_string);
829         if (rc)
830         {
831             TRACE("%s\n",debugstr_an(sjis_string,rc));
832             if (output)
833                 rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
834             else
835                 rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
836         }
837         HeapFree(GetProcessHeap(),0,sjis_string);
838         break;
839     }
840     return rc;
841 }
842
843 static UINT ConvertJapaneseUnicodeToJIS(LPCWSTR input, DWORD count,
844                                         LPSTR output, DWORD out_count)
845 {
846     CHAR *sjis_string;
847     INT len;
848     UINT rc = 0;
849
850     len = WideCharToMultiByte(932,0,input,count,0,0,NULL,NULL);
851     sjis_string = HeapAlloc(GetProcessHeap(),0,len);
852     WideCharToMultiByte(932,0,input,count,sjis_string,len,NULL,NULL);
853     TRACE("%s\n",debugstr_an(sjis_string,len));
854
855     rc = ConvertSJIS2JIS(sjis_string, len, NULL);
856     if (out_count >= rc)
857     {
858         ConvertSJIS2JIS(sjis_string, len, output);
859     }
860     HeapFree(GetProcessHeap(),0,sjis_string);
861     return rc;
862
863 }
864
865 /*
866  * Dll lifetime tracking declaration
867  */
868 static void LockModule(void)
869 {
870     InterlockedIncrement(&dll_count);
871 }
872
873 static void UnlockModule(void)
874 {
875     InterlockedDecrement(&dll_count);
876 }
877
878 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
879 {
880     switch(fdwReason) {
881         case DLL_PROCESS_ATTACH:
882             MLANG_tls_index = TlsAlloc();
883             DisableThreadLibraryCalls(hInstDLL);
884             break;
885         case DLL_PROCESS_DETACH:
886             TlsFree(MLANG_tls_index);
887             break;
888     }
889     return TRUE;
890 }
891
892 HRESULT WINAPI ConvertINetMultiByteToUnicode(
893     LPDWORD pdwMode,
894     DWORD dwEncoding,
895     LPCSTR pSrcStr,
896     LPINT pcSrcSize,
897     LPWSTR pDstStr,
898     LPINT pcDstSize)
899 {
900     INT src_len = -1;
901
902     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
903           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
904
905     if (!pcDstSize)
906         return E_FAIL;
907
908     if (!pcSrcSize)
909         pcSrcSize = &src_len;
910
911     if (!*pcSrcSize)
912     {
913         *pcDstSize = 0;
914         return S_OK;
915     }
916
917     /* forwarding euc-jp to EUC-JP */
918     if (dwEncoding == 51932)
919         dwEncoding = 20932;
920
921     switch (dwEncoding)
922     {
923     case CP_UNICODE:
924         if (*pcSrcSize == -1)
925             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
926         *pcDstSize = min(*pcSrcSize, *pcDstSize);
927         *pcSrcSize *= sizeof(WCHAR);
928         if (pDstStr)
929             memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
930         break;
931
932     case 50220:
933     case 50221:
934     case 50222:
935         *pcDstSize = ConvertJISJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
936         break;
937     case 50932:
938         *pcDstSize = ConvertUnknownJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
939         break;
940
941     default:
942         if (*pcSrcSize == -1)
943             *pcSrcSize = lstrlenA(pSrcStr);
944
945         if (pDstStr)
946             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
947         else
948             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
949         break;
950     }
951     
952     if (!*pcDstSize)
953         return E_FAIL;
954
955     return S_OK;
956 }
957
958 HRESULT WINAPI ConvertINetUnicodeToMultiByte(
959     LPDWORD pdwMode,
960     DWORD dwEncoding,
961     LPCWSTR pSrcStr,
962     LPINT pcSrcSize,
963     LPSTR pDstStr,
964     LPINT pcDstSize)
965 {
966     INT destsz, size;
967     INT src_len = -1;
968
969     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
970           debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
971
972     if (!pcDstSize)
973         return S_OK;
974
975     if (!pcSrcSize)
976         pcSrcSize = &src_len;
977
978     destsz = (pDstStr) ? *pcDstSize : 0;
979     *pcDstSize = 0;
980
981     if (!pSrcStr || !*pcSrcSize)
982         return S_OK;
983
984     if (*pcSrcSize == -1)
985         *pcSrcSize = lstrlenW(pSrcStr);
986
987     /* forwarding euc-jp to EUC-JP */
988     if (dwEncoding == 51932)
989         dwEncoding = 20932;
990
991     if (dwEncoding == CP_UNICODE)
992     {
993         if (*pcSrcSize == -1)
994             *pcSrcSize = lstrlenW(pSrcStr);
995
996         size = min(*pcSrcSize, destsz) * sizeof(WCHAR);
997         if (pDstStr)
998             memmove(pDstStr, pSrcStr, size);
999
1000         if (size >= destsz)
1001             goto fail;
1002     }
1003     else if (dwEncoding == 50220 || dwEncoding == 50221 || dwEncoding == 50222)
1004     {
1005         size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, NULL, 0);
1006         if (!size)
1007             goto fail;
1008
1009         if (pDstStr)
1010         {
1011             size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, pDstStr,
1012                                                destsz);
1013             if (!size)
1014                 goto fail;
1015         }
1016
1017     }
1018     else
1019     {
1020         size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1021                                    NULL, 0, NULL, NULL);
1022         if (!size)
1023             goto fail;
1024
1025         if (pDstStr)
1026         {
1027             size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1028                                        pDstStr, destsz, NULL, NULL);
1029             if (!size)
1030                 goto fail;
1031         }
1032     }
1033
1034     *pcDstSize = size;
1035     return S_OK;
1036
1037 fail:
1038     *pcSrcSize = 0;
1039     *pcDstSize = 0;
1040     return E_FAIL;
1041 }
1042
1043 HRESULT WINAPI ConvertINetString(
1044     LPDWORD pdwMode,
1045     DWORD dwSrcEncoding,
1046     DWORD dwDstEncoding,
1047     LPCSTR pSrcStr,
1048     LPINT pcSrcSize,
1049     LPSTR pDstStr,
1050     LPINT pcDstSize
1051 )
1052 {
1053     TRACE("%p %d %d %s %p %p %p\n", pdwMode, dwSrcEncoding, dwDstEncoding,
1054           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
1055
1056     if (dwSrcEncoding == CP_UNICODE)
1057     {
1058         INT cSrcSizeW;
1059         if (pcSrcSize && *pcSrcSize != -1)
1060         {
1061             cSrcSizeW = *pcSrcSize / sizeof(WCHAR);
1062             pcSrcSize = &cSrcSizeW;
1063         }
1064         return ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, (LPCWSTR)pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1065     }
1066     else if (dwDstEncoding == CP_UNICODE)
1067     {
1068         HRESULT hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, (LPWSTR)pDstStr, pcDstSize);
1069         *pcDstSize *= sizeof(WCHAR);
1070         return hr;
1071     }
1072     else
1073     {
1074         INT cDstSizeW;
1075         LPWSTR pDstStrW;
1076         HRESULT hr;
1077
1078         TRACE("convert %s from %d to %d\n", debugstr_a(pSrcStr), dwSrcEncoding, dwDstEncoding);
1079
1080         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, NULL, &cDstSizeW);
1081         if (hr != S_OK)
1082             return hr;
1083
1084         pDstStrW = HeapAlloc(GetProcessHeap(), 0, cDstSizeW * sizeof(WCHAR));
1085         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, pDstStrW, &cDstSizeW);
1086         if (hr == S_OK)
1087             hr = ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, pDstStrW, &cDstSizeW, pDstStr, pcDstSize);
1088
1089         HeapFree(GetProcessHeap(), 0, pDstStrW);
1090         return hr;
1091     }
1092 }
1093
1094 static HRESULT GetFamilyCodePage(
1095     UINT uiCodePage,
1096     UINT* puiFamilyCodePage)
1097 {
1098     UINT i, n;
1099
1100     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
1101
1102     if (!puiFamilyCodePage) return S_FALSE;
1103
1104     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1105     {
1106         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1107         {
1108             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1109             {
1110                 *puiFamilyCodePage = mlang_data[i].family_codepage;
1111                 return S_OK;
1112             }
1113         }
1114     }
1115
1116     return S_FALSE;
1117 }
1118
1119 HRESULT WINAPI IsConvertINetStringAvailable(
1120     DWORD dwSrcEncoding,
1121     DWORD dwDstEncoding)
1122 {
1123     UINT src_family, dst_family;
1124
1125     TRACE("%d %d\n", dwSrcEncoding, dwDstEncoding);
1126
1127     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
1128         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
1129         return S_FALSE;
1130
1131     if (src_family == dst_family) return S_OK;
1132
1133     /* we can convert any codepage to/from unicode */
1134     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
1135
1136     return S_FALSE;
1137 }
1138
1139 static inline HRESULT lcid_to_rfc1766A( LCID lcid, LPSTR rfc1766, INT len )
1140 {
1141     CHAR buffer[MAX_RFC1766_NAME];
1142     INT n = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1143     INT i;
1144
1145     if (n)
1146     {
1147         i = PRIMARYLANGID(lcid);
1148         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1149             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1150             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1151
1152             buffer[n - 1] = '-';
1153             i = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1154             if (!i)
1155                 buffer[n - 1] = '\0';
1156         }
1157         else
1158             i = 0;
1159
1160         LCMapStringA( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len );
1161         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1162     }
1163     return E_FAIL;
1164 }
1165
1166 static inline HRESULT lcid_to_rfc1766W( LCID lcid, LPWSTR rfc1766, INT len )
1167 {
1168     WCHAR buffer[MAX_RFC1766_NAME];
1169     INT n = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1170     INT i;
1171
1172     if (n)
1173     {
1174         i = PRIMARYLANGID(lcid);
1175         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1176             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1177             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1178
1179             buffer[n - 1] = '-';
1180             i = GetLocaleInfoW(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1181             if (!i)
1182                 buffer[n - 1] = '\0';
1183         }
1184         else
1185             i = 0;
1186
1187         LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len);
1188         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1189     }
1190     return E_FAIL;
1191 }
1192
1193 HRESULT WINAPI LcidToRfc1766A(
1194     LCID lcid,
1195     LPSTR pszRfc1766,
1196     INT nChar)
1197 {
1198     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1199     if (!pszRfc1766)
1200         return E_INVALIDARG;
1201
1202     return lcid_to_rfc1766A(lcid, pszRfc1766, nChar);
1203 }
1204
1205 HRESULT WINAPI LcidToRfc1766W(
1206     LCID lcid,
1207     LPWSTR pszRfc1766,
1208     INT nChar)
1209 {
1210     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1211     if (!pszRfc1766)
1212         return E_INVALIDARG;
1213
1214     return lcid_to_rfc1766W(lcid, pszRfc1766, nChar);
1215 }
1216
1217 static HRESULT lcid_from_rfc1766(IEnumRfc1766 *iface, LCID *lcid, LPCWSTR rfc1766)
1218 {
1219     RFC1766INFO info;
1220     ULONG num;
1221
1222     while (IEnumRfc1766_Next(iface, 1, &info, &num) == S_OK)
1223     {
1224         if (!strcmpiW(info.wszRfc1766, rfc1766))
1225         {
1226             *lcid = info.lcid;
1227             return S_OK;
1228         }
1229         if (strlenW(rfc1766) == 2 && !memcmp(info.wszRfc1766, rfc1766, 2 * sizeof(WCHAR)))
1230         {
1231             *lcid = PRIMARYLANGID(info.lcid);
1232             return S_OK;
1233         }
1234     }
1235
1236     return E_FAIL;
1237 }
1238
1239 HRESULT WINAPI Rfc1766ToLcidW(LCID *pLocale, LPCWSTR pszRfc1766)
1240 {
1241     IEnumRfc1766 *enumrfc1766;
1242     HRESULT hr;
1243
1244     TRACE("(%p, %s)\n", pLocale, debugstr_w(pszRfc1766));
1245
1246     if (!pLocale || !pszRfc1766)
1247         return E_INVALIDARG;
1248
1249     hr = EnumRfc1766_create(0, &enumrfc1766);
1250     if (FAILED(hr))
1251         return hr;
1252
1253     hr = lcid_from_rfc1766(enumrfc1766, pLocale, pszRfc1766);
1254     IEnumRfc1766_Release(enumrfc1766);
1255
1256     return hr;
1257 }
1258
1259 HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A)
1260 {
1261     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1262
1263     if (!rfc1766A)
1264         return E_INVALIDARG;
1265
1266     MultiByteToWideChar(CP_ACP, 0, rfc1766A, -1, rfc1766W, MAX_RFC1766_NAME);
1267     rfc1766W[MAX_RFC1766_NAME] = 0;
1268
1269     return Rfc1766ToLcidW(lcid, rfc1766W);
1270 }
1271
1272 /******************************************************************************
1273  * MLANG ClassFactory
1274  */
1275 typedef struct {
1276     IClassFactory ITF_IClassFactory;
1277
1278     LONG ref;
1279     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1280 } IClassFactoryImpl;
1281
1282 struct object_creation_info
1283 {
1284     const CLSID *clsid;
1285     LPCSTR szClassName;
1286     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1287 };
1288
1289 static const struct object_creation_info object_creation[] =
1290 {
1291     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
1292 };
1293
1294 static HRESULT WINAPI
1295 MLANGCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
1296 {
1297     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1298
1299     TRACE("%s\n", debugstr_guid(riid) );
1300
1301     if (IsEqualGUID(riid, &IID_IUnknown)
1302         || IsEqualGUID(riid, &IID_IClassFactory))
1303     {
1304         IClassFactory_AddRef(iface);
1305         *ppobj = This;
1306         return S_OK;
1307     }
1308
1309     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
1310     return E_NOINTERFACE;
1311 }
1312
1313 static ULONG WINAPI MLANGCF_AddRef(LPCLASSFACTORY iface)
1314 {
1315     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1316     return InterlockedIncrement(&This->ref);
1317 }
1318
1319 static ULONG WINAPI MLANGCF_Release(LPCLASSFACTORY iface)
1320 {
1321     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1322
1323     ULONG ref = InterlockedDecrement(&This->ref);
1324
1325     if (ref == 0)
1326     {
1327         TRACE("Destroying %p\n", This);
1328         HeapFree(GetProcessHeap(), 0, This);
1329     }
1330
1331     return ref;
1332 }
1333
1334 static HRESULT WINAPI MLANGCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
1335                                           REFIID riid, LPVOID *ppobj)
1336 {
1337     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1338     HRESULT hres;
1339     LPUNKNOWN punk;
1340     
1341     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1342
1343     *ppobj = NULL;
1344     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
1345     if (SUCCEEDED(hres)) {
1346         hres = IUnknown_QueryInterface(punk, riid, ppobj);
1347         IUnknown_Release(punk);
1348     }
1349     TRACE("returning (%p) -> %x\n", *ppobj, hres);
1350     return hres;
1351 }
1352
1353 static HRESULT WINAPI MLANGCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
1354 {
1355     if (dolock)
1356         LockModule();
1357     else
1358         UnlockModule();
1359
1360     return S_OK;
1361 }
1362
1363 static const IClassFactoryVtbl MLANGCF_Vtbl =
1364 {
1365     MLANGCF_QueryInterface,
1366     MLANGCF_AddRef,
1367     MLANGCF_Release,
1368     MLANGCF_CreateInstance,
1369     MLANGCF_LockServer
1370 };
1371
1372 /******************************************************************
1373  *              DllGetClassObject (MLANG.@)
1374  */
1375 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1376 {
1377     unsigned int i;
1378     IClassFactoryImpl *factory;
1379
1380     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1381
1382     if ( !IsEqualGUID( &IID_IClassFactory, iid )
1383          && ! IsEqualGUID( &IID_IUnknown, iid) )
1384         return E_NOINTERFACE;
1385
1386     for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
1387     {
1388         if (IsEqualGUID(object_creation[i].clsid, rclsid))
1389             break;
1390     }
1391
1392     if (i == sizeof(object_creation)/sizeof(object_creation[0]))
1393     {
1394         FIXME("%s: no class found.\n", debugstr_guid(rclsid));
1395         return CLASS_E_CLASSNOTAVAILABLE;
1396     }
1397
1398     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
1399
1400     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
1401     if (factory == NULL) return E_OUTOFMEMORY;
1402
1403     factory->ITF_IClassFactory.lpVtbl = &MLANGCF_Vtbl;
1404     factory->ref = 1;
1405
1406     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
1407
1408     *ppv = &(factory->ITF_IClassFactory);
1409
1410     TRACE("(%p) <- %p\n", ppv, &(factory->ITF_IClassFactory) );
1411
1412     return S_OK;
1413 }
1414
1415
1416 /******************************************************************************/
1417
1418 typedef struct tagMLang_impl
1419 {
1420     const IMLangFontLinkVtbl *vtbl_IMLangFontLink;
1421     const IMultiLanguageVtbl *vtbl_IMultiLanguage;
1422     const IMultiLanguage3Vtbl *vtbl_IMultiLanguage3;
1423     const IMLangFontLink2Vtbl *vtbl_IMLangFontLink2;
1424     const IMLangLineBreakConsoleVtbl *vtbl_IMLangLineBreakConsole;
1425     LONG ref;
1426     DWORD total_cp, total_scripts;
1427 } MLang_impl;
1428
1429 static ULONG MLang_AddRef( MLang_impl* This)
1430 {
1431     return InterlockedIncrement(&This->ref);
1432 }
1433
1434 static ULONG MLang_Release( MLang_impl* This )
1435 {
1436     ULONG ref = InterlockedDecrement(&This->ref);
1437
1438     TRACE("%p ref = %d\n", This, ref);
1439     if (ref == 0)
1440     {
1441         TRACE("Destroying %p\n", This);
1442         HeapFree(GetProcessHeap(), 0, This);
1443         UnlockModule();
1444     }
1445
1446     return ref;
1447 }
1448
1449 static HRESULT MLang_QueryInterface(
1450         MLang_impl* This,
1451         REFIID riid,
1452         void** ppvObject)
1453 {
1454     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1455
1456     if (IsEqualGUID(riid, &IID_IUnknown)
1457         || IsEqualGUID(riid, &IID_IMLangCodePages)
1458         || IsEqualGUID(riid, &IID_IMLangFontLink))
1459     {
1460         MLang_AddRef(This);
1461         TRACE("Returning IID_IMLangFontLink %p ref = %d\n", This, This->ref);
1462         *ppvObject = &(This->vtbl_IMLangFontLink);
1463         return S_OK;
1464     }
1465
1466     if (IsEqualGUID(riid, &IID_IMLangFontLink2))
1467     {
1468         MLang_AddRef(This);
1469         TRACE("Returning IID_IMLangFontLink2 %p ref = %d\n", This, This->ref);
1470         *ppvObject = &(This->vtbl_IMLangFontLink2);
1471         return S_OK;
1472     }
1473
1474     if (IsEqualGUID(riid, &IID_IMultiLanguage) )
1475     {
1476         MLang_AddRef(This);
1477         TRACE("Returning IID_IMultiLanguage %p ref = %d\n", This, This->ref);
1478         *ppvObject = &(This->vtbl_IMultiLanguage);
1479         return S_OK;
1480     }
1481
1482     if (IsEqualGUID(riid, &IID_IMultiLanguage2) )
1483     {
1484         MLang_AddRef(This);
1485         *ppvObject = &(This->vtbl_IMultiLanguage3);
1486         TRACE("Returning IID_IMultiLanguage2 %p ref = %d\n", This, This->ref);
1487         return S_OK;
1488     }
1489
1490     if (IsEqualGUID(riid, &IID_IMultiLanguage3) )
1491     {
1492         MLang_AddRef(This);
1493         *ppvObject = &(This->vtbl_IMultiLanguage3);
1494         TRACE("Returning IID_IMultiLanguage3 %p ref = %d\n", This, This->ref);
1495         return S_OK;
1496     }
1497
1498     if (IsEqualGUID(riid, &IID_IMLangLineBreakConsole))
1499     {
1500         MLang_AddRef(This);
1501         TRACE("Returning IID_IMLangLineBreakConsole %p ref = %d\n", This, This->ref);
1502         *ppvObject = &(This->vtbl_IMLangLineBreakConsole);
1503         return S_OK;
1504     }
1505
1506
1507     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1508     return E_NOINTERFACE;
1509 }
1510
1511 /******************************************************************************/
1512
1513 typedef struct tagEnumCodePage_impl
1514 {
1515     const IEnumCodePageVtbl *vtbl_IEnumCodePage;
1516     LONG ref;
1517     MIMECPINFO *cpinfo;
1518     DWORD total, pos;
1519 } EnumCodePage_impl;
1520
1521 static inline EnumCodePage_impl *impl_from_IEnumCodePage( IEnumCodePage *iface )
1522 {
1523     return CONTAINING_RECORD( iface, EnumCodePage_impl, vtbl_IEnumCodePage );
1524 }
1525
1526 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1527         IEnumCodePage* iface,
1528         REFIID riid,
1529         void** ppvObject)
1530 {
1531     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1532
1533     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1534
1535     if (IsEqualGUID(riid, &IID_IUnknown)
1536         || IsEqualGUID(riid, &IID_IEnumCodePage))
1537     {
1538         IEnumCodePage_AddRef(iface);
1539         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1540         *ppvObject = &(This->vtbl_IEnumCodePage);
1541         return S_OK;
1542     }
1543
1544     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1545     return E_NOINTERFACE;
1546 }
1547
1548 static ULONG WINAPI fnIEnumCodePage_AddRef(
1549         IEnumCodePage* iface)
1550 {
1551     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1552     return InterlockedIncrement(&This->ref);
1553 }
1554
1555 static ULONG WINAPI fnIEnumCodePage_Release(
1556         IEnumCodePage* iface)
1557 {
1558     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1559     ULONG ref = InterlockedDecrement(&This->ref);
1560
1561     TRACE("%p ref = %d\n", This, ref);
1562     if (ref == 0)
1563     {
1564         TRACE("Destroying %p\n", This);
1565         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1566         HeapFree(GetProcessHeap(), 0, This);
1567     }
1568
1569     return ref;
1570 }
1571
1572 static HRESULT WINAPI fnIEnumCodePage_Clone(
1573         IEnumCodePage* iface,
1574         IEnumCodePage** ppEnum)
1575 {
1576     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1577     FIXME("%p %p\n", This, ppEnum);
1578     return E_NOTIMPL;
1579 }
1580
1581 static  HRESULT WINAPI fnIEnumCodePage_Next(
1582         IEnumCodePage* iface,
1583         ULONG celt,
1584         PMIMECPINFO rgelt,
1585         ULONG* pceltFetched)
1586 {
1587     ULONG i;
1588     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1589
1590     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1591
1592     if (!pceltFetched) return S_FALSE;
1593     *pceltFetched = 0;
1594
1595     if (!rgelt) return S_FALSE;
1596
1597     if (This->pos + celt > This->total)
1598         celt = This->total - This->pos;
1599
1600     if (!celt) return S_FALSE;
1601
1602     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1603     *pceltFetched = celt;
1604     This->pos += celt;
1605
1606     for (i = 0; i < celt; i++)
1607     {
1608         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1609               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1610               rgelt[i].uiFamilyCodePage,
1611               wine_dbgstr_w(rgelt[i].wszDescription),
1612               wine_dbgstr_w(rgelt[i].wszWebCharset),
1613               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1614               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1615               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1616               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1617               rgelt[i].bGDICharset);
1618     }
1619     return S_OK;
1620 }
1621
1622 static HRESULT WINAPI fnIEnumCodePage_Reset(
1623         IEnumCodePage* iface)
1624 {
1625     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1626
1627     TRACE("%p\n", This);
1628
1629     This->pos = 0;
1630     return S_OK;
1631 }
1632
1633 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1634         IEnumCodePage* iface,
1635         ULONG celt)
1636 {
1637     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1638
1639     TRACE("%p %u\n", This, celt);
1640
1641     if (celt >= This->total) return S_FALSE;
1642
1643     This->pos += celt;
1644     return S_OK;
1645 }
1646
1647 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1648 {
1649     fnIEnumCodePage_QueryInterface,
1650     fnIEnumCodePage_AddRef,
1651     fnIEnumCodePage_Release,
1652     fnIEnumCodePage_Clone,
1653     fnIEnumCodePage_Next,
1654     fnIEnumCodePage_Reset,
1655     fnIEnumCodePage_Skip
1656 };
1657
1658 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1659                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1660 {
1661     EnumCodePage_impl *ecp;
1662     MIMECPINFO *cpinfo;
1663     UINT i, n;
1664
1665     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1666
1667     if (!grfFlags) /* enumerate internal data base of encodings */
1668         grfFlags = MIMECONTF_MIME_LATEST;
1669
1670     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1671     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
1672     ecp->ref = 1;
1673     ecp->pos = 0;
1674     ecp->total = 0;
1675     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1676     {
1677         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1678         {
1679             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1680                 ecp->total++;
1681         }
1682     }
1683
1684     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1685                             sizeof(MIMECPINFO) * ecp->total);
1686     cpinfo = ecp->cpinfo;
1687
1688     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1689     {
1690         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1691         {
1692             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1693                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1694         }
1695     }
1696
1697     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1698
1699     *ppEnumCodePage = (IEnumCodePage*) ecp;
1700
1701     return S_OK;
1702 }
1703
1704 /******************************************************************************/
1705
1706 typedef struct tagEnumScript_impl
1707 {
1708     const IEnumScriptVtbl *vtbl_IEnumScript;
1709     LONG ref;
1710     SCRIPTINFO *script_info;
1711     DWORD total, pos;
1712 } EnumScript_impl;
1713
1714 static inline EnumScript_impl *impl_from_IEnumScript( IEnumScript *iface )
1715 {
1716     return CONTAINING_RECORD( iface, EnumScript_impl, vtbl_IEnumScript );
1717 }
1718
1719 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1720         IEnumScript* iface,
1721         REFIID riid,
1722         void** ppvObject)
1723 {
1724     EnumScript_impl *This = impl_from_IEnumScript( iface );
1725
1726     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1727
1728     if (IsEqualGUID(riid, &IID_IUnknown)
1729         || IsEqualGUID(riid, &IID_IEnumScript))
1730     {
1731         IEnumScript_AddRef(iface);
1732         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1733         *ppvObject = &(This->vtbl_IEnumScript);
1734         return S_OK;
1735     }
1736
1737     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1738     return E_NOINTERFACE;
1739 }
1740
1741 static ULONG WINAPI fnIEnumScript_AddRef(
1742         IEnumScript* iface)
1743 {
1744     EnumScript_impl *This = impl_from_IEnumScript( iface );
1745     return InterlockedIncrement(&This->ref);
1746 }
1747
1748 static ULONG WINAPI fnIEnumScript_Release(
1749         IEnumScript* iface)
1750 {
1751     EnumScript_impl *This = impl_from_IEnumScript( iface );
1752     ULONG ref = InterlockedDecrement(&This->ref);
1753
1754     TRACE("%p ref = %d\n", This, ref);
1755     if (ref == 0)
1756     {
1757         TRACE("Destroying %p\n", This);
1758         HeapFree(GetProcessHeap(), 0, This->script_info);
1759         HeapFree(GetProcessHeap(), 0, This);
1760     }
1761
1762     return ref;
1763 }
1764
1765 static HRESULT WINAPI fnIEnumScript_Clone(
1766         IEnumScript* iface,
1767         IEnumScript** ppEnum)
1768 {
1769     EnumScript_impl *This = impl_from_IEnumScript( iface );
1770     FIXME("%p %p: stub!\n", This, ppEnum);
1771     return E_NOTIMPL;
1772 }
1773
1774 static  HRESULT WINAPI fnIEnumScript_Next(
1775         IEnumScript* iface,
1776         ULONG celt,
1777         PSCRIPTINFO rgelt,
1778         ULONG* pceltFetched)
1779 {
1780     EnumScript_impl *This = impl_from_IEnumScript( iface );
1781
1782     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1783
1784     if (!pceltFetched || !rgelt) return E_FAIL;
1785
1786     *pceltFetched = 0;
1787
1788     if (This->pos + celt > This->total)
1789         celt = This->total - This->pos;
1790
1791     if (!celt) return S_FALSE;
1792
1793     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1794     *pceltFetched = celt;
1795     This->pos += celt;
1796
1797     return S_OK;
1798 }
1799
1800 static HRESULT WINAPI fnIEnumScript_Reset(
1801         IEnumScript* iface)
1802 {
1803     EnumScript_impl *This = impl_from_IEnumScript( iface );
1804
1805     TRACE("%p\n", This);
1806
1807     This->pos = 0;
1808     return S_OK;
1809 }
1810
1811 static  HRESULT WINAPI fnIEnumScript_Skip(
1812         IEnumScript* iface,
1813         ULONG celt)
1814 {
1815     EnumScript_impl *This = impl_from_IEnumScript( iface );
1816
1817     TRACE("%p %u\n", This, celt);
1818
1819     if (celt >= This->total) return S_FALSE;
1820
1821     This->pos += celt;
1822     return S_OK;
1823 }
1824
1825 static const IEnumScriptVtbl IEnumScript_vtbl =
1826 {
1827     fnIEnumScript_QueryInterface,
1828     fnIEnumScript_AddRef,
1829     fnIEnumScript_Release,
1830     fnIEnumScript_Clone,
1831     fnIEnumScript_Next,
1832     fnIEnumScript_Reset,
1833     fnIEnumScript_Skip
1834 };
1835
1836 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1837                      LANGID LangId, IEnumScript** ppEnumScript )
1838 {
1839     EnumScript_impl *es;
1840     UINT i;
1841
1842     TRACE("%p, %08x, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1843
1844     if (!dwFlags) /* enumerate all available scripts */
1845         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1846
1847     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1848     es->vtbl_IEnumScript = &IEnumScript_vtbl;
1849     es->ref = 1;
1850     es->pos = 0;
1851     /* do not enumerate unicode flavours */
1852     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1853     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1854
1855     for (i = 0; i < es->total; i++)
1856     {
1857         es->script_info[i].ScriptId = i;
1858         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1859         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1860             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1861         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1862             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1863         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1864             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1865     }
1866
1867     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1868
1869     *ppEnumScript = (IEnumScript *)es;
1870
1871     return S_OK;
1872 }
1873
1874 /******************************************************************************/
1875
1876 static inline MLang_impl *impl_from_IMLangFontLink( IMLangFontLink *iface )
1877 {
1878     return CONTAINING_RECORD( iface, MLang_impl, vtbl_IMLangFontLink );
1879 }
1880
1881 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1882         IMLangFontLink* iface,
1883         REFIID riid,
1884         void** ppvObject)
1885 {
1886     MLang_impl *This = impl_from_IMLangFontLink( iface );
1887     return MLang_QueryInterface( This, riid, ppvObject );
1888 }
1889
1890 static ULONG WINAPI fnIMLangFontLink_AddRef(
1891         IMLangFontLink* iface)
1892 {
1893     MLang_impl *This = impl_from_IMLangFontLink( iface );
1894     return MLang_AddRef( This );
1895 }
1896
1897 static ULONG WINAPI fnIMLangFontLink_Release(
1898         IMLangFontLink* iface)
1899 {
1900     MLang_impl *This = impl_from_IMLangFontLink( iface );
1901     return MLang_Release( This );
1902 }
1903
1904 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1905         IMLangFontLink* iface,
1906         WCHAR chSrc,
1907         DWORD* pdwCodePages)
1908 {
1909     int i;
1910     CHAR buf;
1911     BOOL used_dc;
1912     DWORD codePages;
1913
1914     *pdwCodePages = 0;
1915
1916     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1917     {
1918         WideCharToMultiByte(mlang_data[i].family_codepage, WC_NO_BEST_FIT_CHARS,
1919             &chSrc, 1, &buf, 1, NULL, &used_dc);
1920
1921         /* If default char is not used, current codepage include the given symbol */
1922         if (!used_dc)
1923         {
1924             IMLangFontLink_CodePageToCodePages(iface,
1925                 mlang_data[i].family_codepage, &codePages);
1926             *pdwCodePages |= codePages;
1927         }
1928     }
1929     return S_OK;
1930 }
1931
1932 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1933         IMLangFontLink* iface,
1934         const WCHAR* pszSrc,
1935         LONG cchSrc,
1936         DWORD dwPriorityCodePages,
1937         DWORD* pdwCodePages,
1938         LONG* pcchCodePages)
1939 {
1940     LONG i;
1941     DWORD cps = 0;
1942
1943     TRACE("(%p)->%s %d %x %p %p\n", iface, debugstr_wn(pszSrc, cchSrc), cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
1944
1945     if (pdwCodePages) *pdwCodePages = 0;
1946     if (pcchCodePages) *pcchCodePages = 0;
1947
1948     if (!pszSrc || !cchSrc || cchSrc < 0)
1949         return E_INVALIDARG;
1950
1951     for (i = 0; i < cchSrc; i++)
1952     {
1953         DWORD cp;
1954         HRESULT ret;
1955
1956         ret = fnIMLangFontLink_GetCharCodePages(iface, pszSrc[i], &cp);
1957         if (ret != S_OK) return E_FAIL;
1958
1959         if (!cps) cps = cp;
1960         else cps &= cp;
1961
1962         /* FIXME: not tested */
1963         if (dwPriorityCodePages & cps) break;
1964     }
1965
1966     if (pdwCodePages) *pdwCodePages = cps;
1967     if (pcchCodePages) *pcchCodePages = min( i + 1, cchSrc );
1968     return S_OK;
1969 }
1970
1971 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1972         IMLangFontLink* iface,
1973         UINT uCodePage,
1974         DWORD* pdwCodePages)
1975 {
1976     MLang_impl *This = impl_from_IMLangFontLink( iface );
1977     CHARSETINFO cs;
1978     BOOL rc; 
1979
1980     TRACE("(%p) Seeking %u\n",This, uCodePage);
1981
1982     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uCodePage, &cs, TCI_SRCCODEPAGE);
1983
1984     if (rc)
1985     {
1986         *pdwCodePages = cs.fs.fsCsb[0];
1987         TRACE("resulting CodePages 0x%x\n",*pdwCodePages);
1988         return S_OK;
1989     }
1990
1991     TRACE("CodePage Not Found\n");
1992     *pdwCodePages = 0;
1993     return E_FAIL;
1994 }
1995
1996 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1997         IMLangFontLink* iface,
1998         DWORD dwCodePages,
1999         UINT uDefaultCodePage,
2000         UINT* puCodePage)
2001 {
2002     MLang_impl *This = impl_from_IMLangFontLink( iface );
2003     DWORD mask = 0x00000000;
2004     UINT i;
2005     CHARSETINFO cs;
2006     BOOL rc; 
2007
2008     TRACE("(%p) scanning  0x%x  default page %u\n",This, dwCodePages,
2009             uDefaultCodePage);
2010
2011     *puCodePage = 0x00000000;
2012
2013     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)uDefaultCodePage, &cs,
2014                               TCI_SRCCODEPAGE);
2015
2016     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
2017     {
2018         TRACE("Found Default Codepage\n");
2019         *puCodePage = uDefaultCodePage;
2020         return S_OK;
2021     }
2022
2023     
2024     for (i = 0; i < 32; i++)
2025     {
2026
2027         mask = 1 << i;
2028         if (dwCodePages & mask)
2029         {
2030             DWORD Csb[2];
2031             Csb[0] = mask;
2032             Csb[1] = 0x0;
2033             rc = TranslateCharsetInfo(Csb, &cs, TCI_SRCFONTSIG);
2034             if (!rc)
2035                 continue;
2036
2037             TRACE("Falling back to least significant found CodePage %u\n",
2038                     cs.ciACP);
2039             *puCodePage = cs.ciACP;
2040             return S_OK;
2041         }
2042     }
2043
2044     TRACE("no codepage found\n");
2045     return E_FAIL;
2046 }
2047
2048 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
2049         IMLangFontLink* iface,
2050         HDC hDC,
2051         HFONT hFont,
2052         DWORD* pdwCodePages)
2053 {
2054     HFONT old_font;
2055     FONTSIGNATURE fontsig;
2056     MLang_impl *This = impl_from_IMLangFontLink( iface );
2057
2058     TRACE("(%p)\n",This);
2059
2060     old_font = SelectObject(hDC,hFont);
2061     GetTextCharsetInfo(hDC,&fontsig, 0);
2062     SelectObject(hDC,old_font);
2063
2064     *pdwCodePages = fontsig.fsCsb[0];
2065     TRACE("CodePages is 0x%x\n",fontsig.fsCsb[0]);
2066
2067     return S_OK;
2068 }
2069
2070 static HRESULT WINAPI fnIMLangFontLink_MapFont(
2071         IMLangFontLink* iface,
2072         HDC hDC,
2073         DWORD dwCodePages,
2074         HFONT hSrcFont,
2075         HFONT* phDestFont)
2076 {
2077     FIXME("\n");
2078     return E_NOTIMPL;
2079 }
2080
2081 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
2082         IMLangFontLink* iface,
2083         HFONT hFont)
2084 {
2085     FIXME("\n");
2086     return E_NOTIMPL;
2087 }
2088
2089 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
2090         IMLangFontLink* iface)
2091 {
2092     FIXME("\n");
2093     return E_NOTIMPL;
2094 }
2095
2096
2097 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
2098 {
2099     fnIMLangFontLink_QueryInterface,
2100     fnIMLangFontLink_AddRef,
2101     fnIMLangFontLink_Release,
2102     fnIMLangFontLink_GetCharCodePages,
2103     fnIMLangFontLink_GetStrCodePages,
2104     fnIMLangFontLink_CodePageToCodePages,
2105     fnIMLangFontLink_CodePagesToCodePage,
2106     fnIMLangFontLink_GetFontCodePages,
2107     fnIMLangFontLink_MapFont,
2108     fnIMLangFontLink_ReleaseFont,
2109     fnIMLangFontLink_ResetFontMapping,
2110 };
2111
2112 /******************************************************************************/
2113
2114 static inline MLang_impl *impl_from_IMultiLanguage( IMultiLanguage *iface )
2115 {
2116     return CONTAINING_RECORD( iface, MLang_impl, vtbl_IMultiLanguage );
2117 }
2118
2119 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
2120     IMultiLanguage* iface,
2121     REFIID riid,
2122     void** ppvObject)
2123 {
2124     MLang_impl *This = impl_from_IMultiLanguage( iface );
2125     return MLang_QueryInterface( This, riid, ppvObject );
2126 }
2127
2128 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
2129 {
2130     MLang_impl *This = impl_from_IMultiLanguage( iface );
2131     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
2132 }
2133
2134 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
2135 {
2136     MLang_impl *This = impl_from_IMultiLanguage( iface );
2137     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
2138 }
2139
2140 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
2141     IMultiLanguage* iface,
2142     UINT* pcCodePage)
2143 {
2144     FIXME("\n");
2145     return E_NOTIMPL;
2146 }
2147
2148 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
2149     IMultiLanguage* iface,
2150     UINT uiCodePage,
2151     PMIMECPINFO pCodePageInfo)
2152 {
2153     UINT i, n;
2154     MLang_impl *This = impl_from_IMultiLanguage( iface );
2155
2156     TRACE("%p, %u, %p\n", This, uiCodePage, pCodePageInfo);
2157
2158     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2159     {
2160         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2161         {
2162             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2163             {
2164                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2165                 return S_OK;
2166             }
2167         }
2168     }
2169
2170     return S_FALSE;
2171 }
2172
2173 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
2174     IMultiLanguage* iface,
2175     UINT uiCodePage,
2176     UINT* puiFamilyCodePage)
2177 {
2178     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2179 }
2180
2181 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
2182     IMultiLanguage* iface,
2183     DWORD grfFlags,
2184     IEnumCodePage** ppEnumCodePage)
2185 {
2186     MLang_impl *This = impl_from_IMultiLanguage( iface );
2187
2188     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
2189
2190     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
2191 }
2192
2193 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
2194     IMultiLanguage* iface,
2195     BSTR Charset,
2196     PMIMECSETINFO pCharsetInfo)
2197 {
2198     MLang_impl *This = impl_from_IMultiLanguage( iface );
2199     return IMultiLanguage3_GetCharsetInfo((IMultiLanguage3*)&This->vtbl_IMultiLanguage3, Charset, pCharsetInfo);
2200 }
2201
2202 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
2203     IMultiLanguage* iface,
2204     DWORD dwSrcEncoding,
2205     DWORD dwDstEncoding)
2206 {
2207     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2208 }
2209
2210 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
2211     IMultiLanguage* iface,
2212     DWORD* pdwMode,
2213     DWORD dwSrcEncoding,
2214     DWORD dwDstEncoding,
2215     BYTE* pSrcStr,
2216     UINT* pcSrcSize,
2217     BYTE* pDstStr,
2218     UINT* pcDstSize)
2219 {
2220     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2221         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2222 }
2223
2224 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
2225     IMultiLanguage* iface,
2226     DWORD* pdwMode,
2227     DWORD dwEncoding,
2228     CHAR* pSrcStr,
2229     UINT* pcSrcSize,
2230     WCHAR* pDstStr,
2231     UINT* pcDstSize)
2232 {
2233     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2234         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2235 }
2236
2237 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
2238     IMultiLanguage* iface,
2239     DWORD* pdwMode,
2240     DWORD dwEncoding,
2241     WCHAR* pSrcStr,
2242     UINT* pcSrcSize,
2243     CHAR* pDstStr,
2244     UINT* pcDstSize)
2245 {
2246     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2247         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2248 }
2249
2250 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
2251     IMultiLanguage* iface)
2252 {
2253     FIXME("\n");
2254     return E_NOTIMPL;
2255 }
2256
2257 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
2258     IMultiLanguage* iface,
2259     LCID lcid,
2260     BSTR* pbstrRfc1766)
2261 {
2262     WCHAR buf[MAX_RFC1766_NAME];
2263
2264     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2265     if (!pbstrRfc1766)
2266         return E_INVALIDARG;
2267
2268     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2269     {
2270         *pbstrRfc1766 = SysAllocString( buf );
2271         return S_OK;
2272     }
2273     return E_FAIL;
2274 }
2275
2276 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
2277     IMultiLanguage* iface,
2278     LCID* pLocale,
2279     BSTR bstrRfc1766)
2280 {
2281     HRESULT hr;
2282     IEnumRfc1766 *rfc1766;
2283
2284     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2285
2286     if (!pLocale || !bstrRfc1766)
2287         return E_INVALIDARG;
2288
2289     hr = IMultiLanguage_EnumRfc1766(iface, &rfc1766);
2290     if (FAILED(hr))
2291         return hr;
2292
2293     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2294
2295     IEnumRfc1766_Release(rfc1766);
2296     return hr;
2297 }
2298
2299 /******************************************************************************/
2300
2301 typedef struct tagEnumRfc1766_impl
2302 {
2303     const IEnumRfc1766Vtbl *vtbl_IEnumRfc1766;
2304     LONG ref;
2305     RFC1766INFO *info;
2306     DWORD total, pos;
2307 } EnumRfc1766_impl;
2308
2309 static inline EnumRfc1766_impl *impl_from_IEnumRfc1766( IEnumRfc1766 *iface )
2310 {
2311     return CONTAINING_RECORD( iface, EnumRfc1766_impl, vtbl_IEnumRfc1766 );
2312 }
2313
2314 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
2315         IEnumRfc1766 *iface,
2316         REFIID riid,
2317         void** ppvObject)
2318 {
2319     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2320
2321     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
2322
2323     if (IsEqualGUID(riid, &IID_IUnknown)
2324         || IsEqualGUID(riid, &IID_IEnumRfc1766))
2325     {
2326         IEnumRfc1766_AddRef(iface);
2327         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
2328         *ppvObject = &(This->vtbl_IEnumRfc1766);
2329         return S_OK;
2330     }
2331
2332     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
2333     return E_NOINTERFACE;
2334 }
2335
2336 static ULONG WINAPI fnIEnumRfc1766_AddRef(
2337         IEnumRfc1766 *iface)
2338 {
2339     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2340     return InterlockedIncrement(&This->ref);
2341 }
2342
2343 static ULONG WINAPI fnIEnumRfc1766_Release(
2344         IEnumRfc1766 *iface)
2345 {
2346     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2347     ULONG ref = InterlockedDecrement(&This->ref);
2348
2349     TRACE("%p ref = %d\n", This, ref);
2350     if (ref == 0)
2351     {
2352         TRACE("Destroying %p\n", This);
2353         HeapFree(GetProcessHeap(), 0, This->info);
2354         HeapFree(GetProcessHeap(), 0, This);
2355     }
2356     return ref;
2357 }
2358
2359 static HRESULT WINAPI fnIEnumRfc1766_Clone(
2360         IEnumRfc1766 *iface,
2361         IEnumRfc1766 **ppEnum)
2362 {
2363     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2364
2365     FIXME("%p %p\n", This, ppEnum);
2366     return E_NOTIMPL;
2367 }
2368
2369 static  HRESULT WINAPI fnIEnumRfc1766_Next(
2370         IEnumRfc1766 *iface,
2371         ULONG celt,
2372         PRFC1766INFO rgelt,
2373         ULONG *pceltFetched)
2374 {
2375     ULONG i;
2376     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2377
2378     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
2379
2380     if (!pceltFetched) return S_FALSE;
2381     *pceltFetched = 0;
2382
2383     if (!rgelt) return S_FALSE;
2384
2385     if (This->pos + celt > This->total)
2386         celt = This->total - This->pos;
2387
2388     if (!celt) return S_FALSE;
2389
2390     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
2391     *pceltFetched = celt;
2392     This->pos += celt;
2393
2394     for (i = 0; i < celt; i++)
2395     {
2396         TRACE("#%u: %08x %s %s\n",
2397               i, rgelt[i].lcid,
2398               wine_dbgstr_w(rgelt[i].wszRfc1766),
2399               wine_dbgstr_w(rgelt[i].wszLocaleName));
2400     }
2401     return S_OK;
2402 }
2403
2404 static HRESULT WINAPI fnIEnumRfc1766_Reset(
2405         IEnumRfc1766 *iface)
2406 {
2407     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2408
2409     TRACE("%p\n", This);
2410
2411     This->pos = 0;
2412     return S_OK;
2413 }
2414
2415 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
2416         IEnumRfc1766 *iface,
2417         ULONG celt)
2418 {
2419     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2420
2421     TRACE("%p %u\n", This, celt);
2422
2423     if (celt >= This->total) return S_FALSE;
2424
2425     This->pos += celt;
2426     return S_OK;
2427 }
2428
2429 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
2430 {
2431     fnIEnumRfc1766_QueryInterface,
2432     fnIEnumRfc1766_AddRef,
2433     fnIEnumRfc1766_Release,
2434     fnIEnumRfc1766_Clone,
2435     fnIEnumRfc1766_Next,
2436     fnIEnumRfc1766_Reset,
2437     fnIEnumRfc1766_Skip
2438 };
2439
2440 struct enum_locales_data
2441 {
2442     RFC1766INFO *info;
2443     DWORD total, allocated;
2444 };
2445
2446 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
2447 {
2448     WCHAR *end;
2449     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
2450     RFC1766INFO *info;
2451
2452     TRACE("%s\n", debugstr_w(locale));
2453
2454     if (data->total >= data->allocated)
2455     {
2456         data->allocated += 32;
2457         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
2458         if (!data->info) return FALSE;
2459     }
2460
2461     info = &data->info[data->total];
2462
2463     info->lcid = strtolW(locale, &end, 16);
2464     if (*end) /* invalid number */
2465         return FALSE;
2466
2467     info->wszRfc1766[0] = 0;
2468     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
2469
2470     info->wszLocaleName[0] = 0;
2471     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
2472     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
2473     
2474     data->total++;
2475
2476     return TRUE;
2477 }
2478
2479 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
2480 {
2481     EnumRfc1766_impl *rfc;
2482     struct enum_locales_data data;
2483
2484     TRACE("%04x, %p\n", LangId, ppEnum);
2485
2486     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
2487     rfc->vtbl_IEnumRfc1766 = &IEnumRfc1766_vtbl;
2488     rfc->ref = 1;
2489     rfc->pos = 0;
2490     rfc->total = 0;
2491
2492     data.total = 0;
2493     data.allocated = 32;
2494     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
2495     if (!data.info)
2496     {
2497         HeapFree(GetProcessHeap(), 0, rfc);
2498         return S_FALSE;
2499     }
2500
2501     TlsSetValue(MLANG_tls_index, &data);
2502     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
2503     TlsSetValue(MLANG_tls_index, NULL);
2504
2505     TRACE("enumerated %d rfc1766 structures\n", data.total);
2506
2507     if (!data.total)
2508     {
2509         HeapFree(GetProcessHeap(), 0, data.info);
2510         HeapFree(GetProcessHeap(), 0, rfc);
2511         return FALSE;
2512     }
2513
2514     rfc->info = data.info;
2515     rfc->total = data.total;
2516
2517     *ppEnum = (IEnumRfc1766 *)rfc;
2518     return S_OK;
2519 }
2520
2521 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
2522     IMultiLanguage *iface,
2523     IEnumRfc1766 **ppEnumRfc1766)
2524 {
2525     MLang_impl *This = impl_from_IMultiLanguage( iface );
2526
2527     TRACE("%p %p\n", This, ppEnumRfc1766);
2528
2529     return EnumRfc1766_create(0, ppEnumRfc1766);
2530 }
2531
2532 /******************************************************************************/
2533
2534 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
2535     IMultiLanguage* iface,
2536     LCID Locale,
2537     PRFC1766INFO pRfc1766Info)
2538 {
2539     FIXME("\n");
2540     return E_NOTIMPL;
2541 }
2542
2543 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
2544     IMultiLanguage* iface,
2545     UINT uiSrcCodePage,
2546     UINT uiDstCodePage,
2547     DWORD dwProperty,
2548     IMLangConvertCharset** ppMLangConvertCharset)
2549 {
2550     FIXME("\n");
2551     return E_NOTIMPL;
2552 }
2553
2554 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
2555 {
2556     fnIMultiLanguage_QueryInterface,
2557     fnIMultiLanguage_AddRef,
2558     fnIMultiLanguage_Release,
2559     fnIMultiLanguage_GetNumberOfCodePageInfo,
2560     fnIMultiLanguage_GetCodePageInfo,
2561     fnIMultiLanguage_GetFamilyCodePage,
2562     fnIMultiLanguage_EnumCodePages,
2563     fnIMultiLanguage_GetCharsetInfo,
2564     fnIMultiLanguage_IsConvertible,
2565     fnIMultiLanguage_ConvertString,
2566     fnIMultiLanguage_ConvertStringToUnicode,
2567     fnIMultiLanguage_ConvertStringFromUnicode,
2568     fnIMultiLanguage_ConvertStringReset,
2569     fnIMultiLanguage_GetRfc1766FromLcid,
2570     fnIMultiLanguage_GetLcidFromRfc1766,
2571     fnIMultiLanguage_EnumRfc1766,
2572     fnIMultiLanguage_GetRfc1766Info,
2573     fnIMultiLanguage_CreateConvertCharset,
2574 };
2575
2576
2577 /******************************************************************************/
2578
2579 static inline MLang_impl *impl_from_IMultiLanguage3( IMultiLanguage3 *iface )
2580 {
2581     return CONTAINING_RECORD( iface, MLang_impl, vtbl_IMultiLanguage3 );
2582 }
2583
2584 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
2585     IMultiLanguage3* iface,
2586     REFIID riid,
2587     void** ppvObject)
2588 {
2589     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2590     return MLang_QueryInterface( This, riid, ppvObject );
2591 }
2592
2593 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
2594 {
2595     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2596     return MLang_AddRef( This );
2597 }
2598
2599 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
2600 {
2601     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2602     return MLang_Release( This );
2603 }
2604
2605 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
2606     IMultiLanguage3* iface,
2607     UINT* pcCodePage)
2608 {
2609     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2610
2611     TRACE("%p, %p\n", This, pcCodePage);
2612
2613     if (!pcCodePage) return S_FALSE;
2614
2615     *pcCodePage = This->total_cp;
2616     return S_OK;
2617 }
2618
2619 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2620 {
2621     CHARSETINFO csi;
2622
2623     if (TranslateCharsetInfo((DWORD*)(DWORD_PTR)ml_data->family_codepage, &csi,
2624                              TCI_SRCCODEPAGE))
2625         mime_cp_info->bGDICharset = csi.ciCharset;
2626     else
2627         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2628
2629     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2630     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2631     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2632     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2633                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
2634     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2635                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
2636     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2637                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
2638     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2639                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
2640
2641     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2642         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
2643     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2644         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
2645
2646     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2647           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2648           mime_cp_info->uiFamilyCodePage,
2649           wine_dbgstr_w(mime_cp_info->wszDescription),
2650           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2651           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2652           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2653           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2654           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2655           mime_cp_info->bGDICharset);
2656 }
2657
2658 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
2659     IMultiLanguage3* iface,
2660     UINT uiCodePage,
2661     LANGID LangId,
2662     PMIMECPINFO pCodePageInfo)
2663 {
2664     UINT i, n;
2665     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2666
2667     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2668
2669     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2670     {
2671         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2672         {
2673             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2674             {
2675                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2676                 return S_OK;
2677             }
2678         }
2679     }
2680
2681     return S_FALSE;
2682 }
2683
2684 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
2685     IMultiLanguage3* iface,
2686     UINT uiCodePage,
2687     UINT* puiFamilyCodePage)
2688 {
2689     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2690 }
2691
2692 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
2693     IMultiLanguage3* iface,
2694     DWORD grfFlags,
2695     LANGID LangId,
2696     IEnumCodePage** ppEnumCodePage)
2697 {
2698     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2699
2700     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2701
2702     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2703 }
2704
2705 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
2706     IMultiLanguage3* iface,
2707     BSTR Charset,
2708     PMIMECSETINFO pCharsetInfo)
2709 {
2710     UINT i, n;
2711     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2712
2713     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2714
2715     if (!pCharsetInfo) return E_FAIL;
2716
2717     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2718     {
2719         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2720         {
2721             WCHAR csetW[MAX_MIMECSET_NAME];
2722
2723             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2724             if (!lstrcmpiW(Charset, csetW))
2725             {
2726                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2727                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2728                 strcpyW(pCharsetInfo->wszCharset, csetW);
2729                 return S_OK;
2730             }
2731         }
2732     }
2733
2734     /* FIXME:
2735      * Since we do not support charsets like iso-2022-jp and do not have
2736      * them in our database as a primary (web_charset) encoding this loop
2737      * does an attempt to 'approximate' charset name by header_charset.
2738      */
2739     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2740     {
2741         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2742         {
2743             WCHAR csetW[MAX_MIMECSET_NAME];
2744
2745             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2746             if (!lstrcmpiW(Charset, csetW))
2747             {
2748                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2749                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2750                 strcpyW(pCharsetInfo->wszCharset, csetW);
2751                 return S_OK;
2752             }
2753         }
2754     }
2755
2756     return E_FAIL;
2757 }
2758
2759 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2760     IMultiLanguage3* iface,
2761     DWORD dwSrcEncoding,
2762     DWORD dwDstEncoding)
2763 {
2764     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2765 }
2766
2767 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2768     IMultiLanguage3* iface,
2769     DWORD* pdwMode,
2770     DWORD dwSrcEncoding,
2771     DWORD dwDstEncoding,
2772     BYTE* pSrcStr,
2773     UINT* pcSrcSize,
2774     BYTE* pDstStr,
2775     UINT* pcDstSize)
2776 {
2777     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2778         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2779 }
2780
2781 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2782     IMultiLanguage3* iface,
2783     DWORD* pdwMode,
2784     DWORD dwEncoding,
2785     CHAR* pSrcStr,
2786     UINT* pcSrcSize,
2787     WCHAR* pDstStr,
2788     UINT* pcDstSize)
2789 {
2790     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2791         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2792 }
2793
2794 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2795     IMultiLanguage3* iface,
2796     DWORD* pdwMode,
2797     DWORD dwEncoding,
2798     WCHAR* pSrcStr,
2799     UINT* pcSrcSize,
2800     CHAR* pDstStr,
2801     UINT* pcDstSize)
2802 {
2803     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2804         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2805 }
2806
2807 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2808     IMultiLanguage3* iface)
2809 {
2810     FIXME("\n");
2811     return E_NOTIMPL;
2812 }
2813
2814 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2815     IMultiLanguage3* iface,
2816     LCID lcid,
2817     BSTR* pbstrRfc1766)
2818 {
2819     WCHAR buf[MAX_RFC1766_NAME];
2820
2821     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2822     if (!pbstrRfc1766)
2823         return E_INVALIDARG;
2824
2825     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2826     {
2827         *pbstrRfc1766 = SysAllocString( buf );
2828         return S_OK;
2829     }
2830     return E_FAIL;
2831 }
2832
2833 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2834     IMultiLanguage3* iface,
2835     LCID* pLocale,
2836     BSTR bstrRfc1766)
2837 {
2838     HRESULT hr;
2839     IEnumRfc1766 *rfc1766;
2840
2841     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2842
2843     if (!pLocale || !bstrRfc1766)
2844         return E_INVALIDARG;
2845
2846     hr = IMultiLanguage2_EnumRfc1766(iface, 0, &rfc1766);
2847     if (FAILED(hr))
2848         return hr;
2849
2850     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2851
2852     IEnumRfc1766_Release(rfc1766);
2853     return hr;
2854 }
2855
2856 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2857     IMultiLanguage3* iface,
2858     LANGID LangId,
2859     IEnumRfc1766** ppEnumRfc1766)
2860 {
2861     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2862
2863     TRACE("%p %p\n", This, ppEnumRfc1766);
2864
2865     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2866 }
2867
2868 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2869     IMultiLanguage3* iface,
2870     LCID Locale,
2871     LANGID LangId,
2872     PRFC1766INFO pRfc1766Info)
2873 {
2874     FIXME("\n");
2875     return E_NOTIMPL;
2876 }
2877
2878 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2879     IMultiLanguage3* iface,
2880     UINT uiSrcCodePage,
2881     UINT uiDstCodePage,
2882     DWORD dwProperty,
2883     IMLangConvertCharset** ppMLangConvertCharset)
2884 {
2885     FIXME("\n");
2886     return E_NOTIMPL;
2887 }
2888
2889 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2890     IMultiLanguage3* iface,
2891     DWORD* pdwMode,
2892     DWORD dwFlag,
2893     WCHAR* lpFallBack,
2894     DWORD dwSrcEncoding,
2895     DWORD dwDstEncoding,
2896     IStream* pstmIn,
2897     IStream* pstmOut)
2898 {
2899     char *src, *dst = NULL;
2900     INT srclen, dstlen;
2901     STATSTG stat;
2902     HRESULT hr;
2903
2904     TRACE("%p %0x8 %s %u %u %p %p\n",
2905           pdwMode, dwFlag, debugstr_w(lpFallBack), dwSrcEncoding, dwDstEncoding, pstmIn, pstmOut);
2906
2907     FIXME("dwFlag and lpFallBack not handled\n");
2908
2909     hr = IStream_Stat(pstmIn, &stat, STATFLAG_NONAME);
2910     if (FAILED(hr)) return hr;
2911
2912     if (stat.cbSize.QuadPart > MAXLONG) return E_INVALIDARG;
2913     if (!(src = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart))) return E_OUTOFMEMORY;
2914
2915     hr = IStream_Read(pstmIn, src, stat.cbSize.QuadPart, (ULONG *)&srclen);
2916     if (FAILED(hr)) goto exit;
2917
2918     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, NULL, &dstlen);
2919     if (FAILED(hr)) goto exit;
2920
2921     if (!(dst = HeapAlloc(GetProcessHeap(), 0, dstlen)))
2922     {
2923         hr = E_OUTOFMEMORY;
2924         goto exit;
2925     }
2926     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, dst, &dstlen);
2927     if (FAILED(hr)) goto exit;
2928
2929     hr = IStream_Write(pstmOut, dst, dstlen, NULL);
2930
2931 exit:
2932     HeapFree(GetProcessHeap(), 0, src);
2933     HeapFree(GetProcessHeap(), 0, dst);
2934     return hr;
2935 }
2936
2937 /*
2938  * TODO: handle dwFlag and lpFallBack
2939 */
2940 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
2941     IMultiLanguage3* iface,
2942     DWORD* pdwMode,
2943     DWORD dwEncoding,
2944     CHAR* pSrcStr,
2945     UINT* pcSrcSize,
2946     WCHAR* pDstStr,
2947     UINT* pcDstSize,
2948     DWORD dwFlag,
2949     WCHAR* lpFallBack)
2950 {
2951     FIXME("\n");
2952     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2953         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2954 }
2955
2956 /*****************************************************************************
2957  * MultiLanguage2::ConvertStringToUnicodeEx
2958  *
2959  * Translates the multibyte string from the specified code page to Unicode.
2960  *
2961  * PARAMS
2962  *   see ConvertStringToUnicode
2963  *   dwFlag 
2964  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
2965  *              instead unconvertible characters.
2966  *
2967  * RETURNS
2968  *   S_OK     Success.
2969  *   S_FALSE  The conversion is not supported.
2970  *   E_FAIL   Some error has occurred.
2971  *
2972  * TODO: handle dwFlag and lpFallBack
2973 */
2974 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
2975     IMultiLanguage3* This,
2976     DWORD* pdwMode,
2977     DWORD dwEncoding,
2978     WCHAR* pSrcStr,
2979     UINT* pcSrcSize,
2980     CHAR* pDstStr,
2981     UINT* pcDstSize,
2982     DWORD dwFlag,
2983     WCHAR* lpFallBack)
2984 {
2985     FIXME("\n");
2986     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2987         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2988 }
2989
2990 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
2991     IMultiLanguage3* iface,
2992     DWORD dwFlag,
2993     DWORD dwPrefWinCodePage,
2994     IStream* pstmIn,
2995     DetectEncodingInfo* lpEncoding,
2996     INT* pnScores)
2997 {
2998     FIXME("\n");
2999     return E_NOTIMPL;
3000 }
3001
3002 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
3003     IMultiLanguage3* iface,
3004     DWORD dwFlag,
3005     DWORD dwPrefWinCodePage,
3006     CHAR* pSrcStr,
3007     INT* pcSrcSize,
3008     DetectEncodingInfo* lpEncoding,
3009     INT* pnScores)
3010 {
3011     FIXME("\n");
3012     return E_NOTIMPL;
3013 }
3014
3015 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
3016     IMultiLanguage3* iface,
3017     UINT uiCodePage,
3018     HWND hwnd)
3019 {
3020     return IMultiLanguage2_ValidateCodePageEx(iface,uiCodePage,hwnd,0);
3021 }
3022
3023 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
3024     IMultiLanguage3* iface,
3025     UINT uiCodePage,
3026     LCID lcid,
3027     LPWSTR lpWideCharStr,
3028     int cchWideChar)
3029 {
3030     /* Find first instance */
3031     unsigned int i,n;
3032
3033     TRACE ("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
3034     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3035     {
3036         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3037         {
3038             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3039             {
3040                 MultiByteToWideChar(CP_ACP, 0,
3041                                     mlang_data[i].mime_cp_info[n].description,
3042                                     -1, lpWideCharStr, cchWideChar);
3043                 return S_OK;
3044             }
3045         }
3046     }
3047
3048     return S_FALSE;
3049 }
3050
3051 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
3052     IMultiLanguage3* iface,
3053     UINT uiCodePage)
3054 {
3055     FIXME("%u\n", uiCodePage);
3056     return E_NOTIMPL;
3057 }
3058
3059 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
3060     IMultiLanguage3* iface,
3061     MIMECONTF dwSource)
3062 {
3063     FIXME("0x%08x\n", dwSource);
3064     return S_OK;
3065 }
3066
3067 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
3068     IMultiLanguage3* iface,
3069     UINT* pnScripts)
3070 {
3071     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3072
3073     TRACE("%p %p\n", This, pnScripts);
3074
3075     if (!pnScripts) return S_FALSE;
3076
3077     *pnScripts = This->total_scripts;
3078     return S_OK;
3079 }
3080
3081 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
3082     IMultiLanguage3* iface,
3083     DWORD dwFlags,
3084     LANGID LangId,
3085     IEnumScript** ppEnumScript)
3086 {
3087     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3088
3089     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
3090
3091     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
3092 }
3093
3094 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
3095     IMultiLanguage3* iface,
3096     UINT uiCodePage,
3097     HWND hwnd,
3098     DWORD dwfIODControl)
3099 {
3100     int i;
3101     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3102
3103     TRACE("%p %u %p %08x\n", This, uiCodePage, hwnd, dwfIODControl);
3104
3105     /* quick check for kernel32 supported code pages */
3106     if (IsValidCodePage(uiCodePage))
3107         return S_OK;
3108
3109     /* check for mlang supported code pages */
3110     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3111     {
3112         int n;
3113         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3114         {
3115             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3116                 return S_OK;
3117         }
3118     }
3119
3120     if (dwfIODControl != CPIOD_PEEK)
3121         FIXME("Request to install codepage language pack not handled\n");
3122
3123     return S_FALSE;
3124 }
3125
3126 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
3127     IMultiLanguage3 *iface,
3128     DWORD dwFlags,
3129     LPCWSTR lpWideCharStr,
3130     UINT cchWideChar,
3131     UINT *puiPreferredCodePages,
3132     UINT nPreferredCodePages,
3133     UINT *puiDetectedCodePages,
3134     UINT *pnDetectedCodePages,
3135     WCHAR *lpSpecialChar)
3136 {
3137     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3138
3139     FIXME("(%p)->(%08x %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
3140           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3141           pnDetectedCodePages, lpSpecialChar);
3142     return E_NOTIMPL;
3143 }
3144
3145 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
3146     IMultiLanguage3 *iface,
3147     DWORD dwFlags,
3148     IStream *pStrIn,
3149     UINT *puiPreferredCodePages,
3150     UINT nPreferredCodePages,
3151     UINT *puiDetectedCodePages,
3152     UINT *pnDetectedCodePages,
3153     WCHAR *lpSpecialChar)
3154 {
3155     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3156
3157     FIXME("(%p)->(%08x %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
3158           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3159           pnDetectedCodePages, lpSpecialChar);
3160     return E_NOTIMPL;
3161 }
3162
3163 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
3164 {
3165     fnIMultiLanguage2_QueryInterface,
3166     fnIMultiLanguage2_AddRef,
3167     fnIMultiLanguage2_Release,
3168     fnIMultiLanguage2_GetNumberOfCodePageInfo,
3169     fnIMultiLanguage2_GetCodePageInfo,
3170     fnIMultiLanguage2_GetFamilyCodePage,
3171     fnIMultiLanguage2_EnumCodePages,
3172     fnIMultiLanguage2_GetCharsetInfo,
3173     fnIMultiLanguage2_IsConvertible,
3174     fnIMultiLanguage2_ConvertString,
3175     fnIMultiLanguage2_ConvertStringToUnicode,
3176     fnIMultiLanguage2_ConvertStringFromUnicode,
3177     fnIMultiLanguage2_ConvertStringReset,
3178     fnIMultiLanguage2_GetRfc1766FromLcid,
3179     fnIMultiLanguage2_GetLcidFromRfc1766,
3180     fnIMultiLanguage2_EnumRfc1766,
3181     fnIMultiLanguage2_GetRfc1766Info,
3182     fnIMultiLanguage2_CreateConvertCharset,
3183     fnIMultiLanguage2_ConvertStringInIStream,
3184     fnIMultiLanguage2_ConvertStringToUnicodeEx,
3185     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
3186     fnIMultiLanguage2_DetectCodepageInIStream,
3187     fnIMultiLanguage2_DetectInputCodepage,
3188     fnIMultiLanguage2_ValidateCodePage,
3189     fnIMultiLanguage2_GetCodePageDescription,
3190     fnIMultiLanguage2_IsCodePageInstallable,
3191     fnIMultiLanguage2_SetMimeDBSource,
3192     fnIMultiLanguage2_GetNumberOfScripts,
3193     fnIMultiLanguage2_EnumScripts,
3194     fnIMultiLanguage2_ValidateCodePageEx,
3195     fnIMultiLanguage3_DetectOutboundCodePage,
3196     fnIMultiLanguage3_DetectOutboundCodePageInIStream
3197 };
3198
3199 /******************************************************************************/
3200
3201 static inline MLang_impl *impl_from_IMLangFontLink2( IMLangFontLink2 *iface )
3202 {
3203     return CONTAINING_RECORD( iface, MLang_impl, vtbl_IMLangFontLink2 );
3204 }
3205
3206 static HRESULT WINAPI fnIMLangFontLink2_QueryInterface(
3207     IMLangFontLink2 * iface,
3208     REFIID riid,
3209     void** ppvObject)
3210 {
3211     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3212     return MLang_QueryInterface( This, riid, ppvObject );
3213 }
3214
3215 static ULONG WINAPI fnIMLangFontLink2_AddRef( IMLangFontLink2* iface )
3216 {
3217     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3218     return MLang_AddRef( This );
3219 }
3220
3221 static ULONG WINAPI fnIMLangFontLink2_Release( IMLangFontLink2* iface )
3222 {
3223     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3224     return MLang_Release( This );
3225 }
3226
3227 static HRESULT WINAPI fnIMLangFontLink2_GetCharCodePages( IMLangFontLink2* This,
3228         WCHAR chSrc, DWORD *pdwCodePages)
3229 {
3230     FIXME("(%p)->%s %p\n",This, debugstr_wn(&chSrc,1),pdwCodePages);
3231     return E_NOTIMPL;
3232 }
3233
3234 static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* This,
3235         const WCHAR *pszSrc, LONG cchSrc, DWORD dwPriorityCodePages,
3236         DWORD *pdwCodePages, LONG *pcchCodePages)
3237 {
3238     return fnIMLangFontLink_GetStrCodePages((IMLangFontLink *)This,
3239             pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages);
3240 }
3241
3242 static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* This,
3243         UINT uCodePage,
3244         DWORD *pdwCodePages)
3245 {
3246     FIXME("(%p)->%i %p\n",This, uCodePage, pdwCodePages);
3247     return E_NOTIMPL;
3248 }
3249
3250 static HRESULT WINAPI fnIMLangFontLink2_CodePagesToCodePage(IMLangFontLink2* This,
3251         DWORD dwCodePages, UINT uDefaultCodePage, UINT *puCodePage)
3252 {
3253     FIXME("(%p)->%i %i %p\n",This, dwCodePages, uDefaultCodePage, puCodePage);
3254     return E_NOTIMPL;
3255 }
3256
3257 static HRESULT WINAPI fnIMLangFontLink2_GetFontCodePages(IMLangFontLink2* This,
3258         HDC hDC, HFONT hFont, DWORD *pdwCodePages)
3259 {
3260     FIXME("(%p)->%p %p %p\n",This, hDC, hFont, pdwCodePages);
3261     return E_NOTIMPL;
3262 }
3263
3264 static HRESULT WINAPI fnIMLangFontLink2_ReleaseFont(IMLangFontLink2* This,
3265         HFONT hFont)
3266 {
3267     FIXME("(%p)->%p\n",This, hFont);
3268     return E_NOTIMPL;
3269 }
3270
3271 static HRESULT WINAPI fnIMLangFontLink2_ResetFontMapping(IMLangFontLink2* This)
3272 {
3273     FIXME("(%p)->\n",This);
3274     return E_NOTIMPL;
3275 }
3276
3277 static HRESULT WINAPI fnIMLangFontLink2_MapFont(IMLangFontLink2* This,
3278         HDC hDC, DWORD dwCodePages, WCHAR chSrc, HFONT *pFont)
3279 {
3280     FIXME("(%p)->%p %i %s %p\n",This, hDC, dwCodePages, debugstr_wn(&chSrc,1), pFont);
3281     return E_NOTIMPL;
3282 }
3283
3284 static HRESULT WINAPI fnIMLangFontLink2_GetFontUnicodeRanges(IMLangFontLink2* This,
3285         HDC hDC, UINT *puiRanges, UNICODERANGE *pUranges)
3286 {
3287     FIXME("(%p)->%p %p %p\n",This, hDC, puiRanges, pUranges);
3288     return E_NOTIMPL;
3289 }
3290
3291 static HRESULT WINAPI fnIMLangFontLink2_GetScriptFontInfo(IMLangFontLink2* This,
3292         SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts,
3293         SCRIPTFONTINFO *pScriptFont)
3294 {
3295     UINT i, j;
3296
3297     TRACE("(%p)->%u %x %p %p\n", This, sid, dwFlags, puiFonts, pScriptFont);
3298
3299     if (!dwFlags) dwFlags = SCRIPTCONTF_PROPORTIONAL_FONT;
3300
3301     for (i = 0, j = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3302     {
3303         if (sid == mlang_data[i].sid)
3304         {
3305             if (pScriptFont)
3306             {
3307                 if (j >= *puiFonts) break;
3308
3309                 pScriptFont[j].scripts = 1 << mlang_data[i].sid;
3310                 if (dwFlags == SCRIPTCONTF_FIXED_FONT)
3311                 {
3312                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
3313                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3314                 }
3315                 else if (dwFlags == SCRIPTCONTF_PROPORTIONAL_FONT)
3316                 {
3317                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
3318                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3319                 }
3320             }
3321             j++;
3322         }
3323     }
3324     *puiFonts = j;
3325     return S_OK;
3326 }
3327
3328 static HRESULT WINAPI fnIMLangFontLink2_CodePageToScriptID(IMLangFontLink2* This,
3329         UINT uiCodePage, SCRIPT_ID *pSid)
3330 {
3331     FIXME("(%p)->%i %p\n",This, uiCodePage, pSid);
3332     return E_NOTIMPL;
3333 }
3334
3335 static const IMLangFontLink2Vtbl IMLangFontLink2_vtbl =
3336 {
3337     fnIMLangFontLink2_QueryInterface,
3338     fnIMLangFontLink2_AddRef,
3339     fnIMLangFontLink2_Release,
3340     fnIMLangFontLink2_GetCharCodePages,
3341     fnIMLangFontLink2_GetStrCodePages,
3342     fnIMLangFontLink2_CodePageToCodePages,
3343     fnIMLangFontLink2_CodePagesToCodePage,
3344     fnIMLangFontLink2_GetFontCodePages,
3345     fnIMLangFontLink2_ReleaseFont,
3346     fnIMLangFontLink2_ResetFontMapping,
3347     fnIMLangFontLink2_MapFont,
3348     fnIMLangFontLink2_GetFontUnicodeRanges,
3349     fnIMLangFontLink2_GetScriptFontInfo,
3350     fnIMLangFontLink2_CodePageToScriptID
3351 };
3352
3353 /******************************************************************************/
3354
3355 static inline MLang_impl *impl_from_IMLangLineBreakConsole( IMLangLineBreakConsole *iface )
3356 {
3357     return CONTAINING_RECORD( iface, MLang_impl, vtbl_IMLangLineBreakConsole );
3358 }
3359
3360 static HRESULT WINAPI fnIMLangLineBreakConsole_QueryInterface(
3361     IMLangLineBreakConsole* iface,
3362     REFIID riid,
3363     void** ppvObject)
3364 {
3365     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3366     return MLang_QueryInterface( This, riid, ppvObject );
3367 }
3368
3369 static ULONG WINAPI fnIMLangLineBreakConsole_AddRef(
3370     IMLangLineBreakConsole* iface )
3371 {
3372     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3373     return MLang_AddRef( This );
3374 }
3375
3376 static ULONG WINAPI fnIMLangLineBreakConsole_Release(
3377     IMLangLineBreakConsole* iface )
3378 {
3379     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3380     return MLang_Release( This );
3381 }
3382
3383 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineML(
3384     IMLangLineBreakConsole* iface,
3385     IMLangString* pSrcMLStr,
3386     LONG lSrcPos,
3387     LONG lSrcLen,
3388     LONG cMinColumns,
3389     LONG cMaxColumns,
3390     LONG* plLineLen,
3391     LONG* plSkipLen)
3392 {
3393     FIXME("(%p)->%p %i %i %i %i %p %p\n", iface, pSrcMLStr, lSrcPos, lSrcLen, cMinColumns, cMaxColumns, plLineLen, plSkipLen);
3394     return E_NOTIMPL;
3395 }
3396
3397 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineW(
3398     IMLangLineBreakConsole* iface,
3399     LCID locale,
3400     const WCHAR* pszSrc,
3401     LONG cchSrc,
3402     LONG cMaxColumns,
3403     LONG* pcchLine,
3404     LONG* pcchSkip )
3405 {
3406     FIXME("(%p)->%i %s %i %i %p %p\n", iface, locale, debugstr_wn(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3407
3408     *pcchLine = cchSrc;
3409     *pcchSkip = 0;
3410     return S_OK;
3411 }
3412
3413 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineA(
3414     IMLangLineBreakConsole* iface,
3415     LCID locale,
3416     UINT uCodePage,
3417     const CHAR* pszSrc,
3418     LONG cchSrc,
3419     LONG cMaxColumns,
3420     LONG* pcchLine,
3421     LONG* pcchSkip)
3422 {
3423     FIXME("(%p)->%i %i %s %i %i %p %p\n", iface, locale, uCodePage, debugstr_an(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3424
3425     *pcchLine = cchSrc;
3426     *pcchSkip = 0;
3427     return S_OK;
3428 }
3429
3430 static const IMLangLineBreakConsoleVtbl IMLangLineBreakConsole_vtbl =
3431 {
3432     fnIMLangLineBreakConsole_QueryInterface,
3433     fnIMLangLineBreakConsole_AddRef,
3434     fnIMLangLineBreakConsole_Release,
3435     fnIMLangLineBreakConsole_BreakLineML,
3436     fnIMLangLineBreakConsole_BreakLineW,
3437     fnIMLangLineBreakConsole_BreakLineA
3438 };
3439
3440 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3441 {
3442     MLang_impl *mlang;
3443     UINT i;
3444
3445     TRACE("Creating MultiLanguage object\n");
3446
3447     if( pUnkOuter )
3448         return CLASS_E_NOAGGREGATION;
3449
3450     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
3451     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
3452     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
3453     mlang->vtbl_IMultiLanguage3 = &IMultiLanguage3_vtbl;
3454     mlang->vtbl_IMLangFontLink2 = &IMLangFontLink2_vtbl;
3455     mlang->vtbl_IMLangLineBreakConsole = &IMLangLineBreakConsole_vtbl;
3456
3457     mlang->total_cp = 0;
3458     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
3459         mlang->total_cp += mlang_data[i].number_of_cp;
3460
3461     /* do not enumerate unicode flavours */
3462     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
3463
3464     mlang->ref = 1;
3465     *ppObj = mlang;
3466     TRACE("returning %p\n", mlang);
3467
3468     LockModule();
3469
3470     return S_OK;
3471 }
3472
3473 /******************************************************************************/
3474
3475 HRESULT WINAPI DllCanUnloadNow(void)
3476 {
3477     return dll_count == 0 ? S_OK : S_FALSE;
3478 }
3479
3480 HRESULT WINAPI GetGlobalFontLinkObject(void)
3481 {
3482     FIXME("\n");
3483     return S_FALSE;
3484 }