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