mlang: Added IMultiLanguage3 interface stub implementation.
[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 %ld %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 %ld %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 %ld %ld %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("%ld %ld\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("%ld %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("%ld %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) -> %lx\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 = %ld\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 = %ld\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 = %ld\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 = %ld\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 = %ld\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 = %ld\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 = %ld\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 %lu %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("#%lu: %08lx %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 %lu\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, %08lx, %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 %ld codepages with flags %08lx\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 = %ld\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 = %ld\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 %lu %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 %lu\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, %08lx, %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 %ld scripts with flags %08lx\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("\n");
1285     return E_NOTIMPL;
1286 }
1287
1288 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1289         IMLangFontLink* iface,
1290         UINT uCodePage,
1291         DWORD* pdwCodePages)
1292 {
1293     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1294     CHARSETINFO cs;
1295     BOOL rc; 
1296
1297     TRACE("(%p) Seeking %u\n",This, uCodePage);
1298     memset(&cs, 0, sizeof(cs));
1299
1300     rc = TranslateCharsetInfo((DWORD*)uCodePage, &cs, TCI_SRCCODEPAGE);
1301
1302     if (rc)
1303     {
1304         *pdwCodePages = cs.fs.fsCsb[0];
1305         TRACE("resulting CodePages 0x%lx\n",*pdwCodePages);
1306     }
1307     else
1308         TRACE("CodePage Not Found\n");
1309
1310     return S_OK;
1311 }
1312
1313 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1314         IMLangFontLink* iface,
1315         DWORD dwCodePages,
1316         UINT uDefaultCodePage,
1317         UINT* puCodePage)
1318 {
1319     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1320     DWORD mask = 0x00000000;
1321     UINT i;
1322     CHARSETINFO cs;
1323     BOOL rc; 
1324
1325     TRACE("(%p) scanning  0x%lx  default page %u\n",This, dwCodePages,
1326             uDefaultCodePage);
1327
1328     *puCodePage = 0x00000000;
1329
1330     rc = TranslateCharsetInfo((DWORD*)uDefaultCodePage, &cs, TCI_SRCCODEPAGE);
1331   
1332     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
1333     {
1334         TRACE("Found Default Codepage\n");
1335         *puCodePage = uDefaultCodePage;
1336         return S_OK;
1337     }
1338
1339     
1340     for (i = 0; i < 32; i++)
1341     {
1342
1343         mask = 1 << i;
1344         if (dwCodePages & mask)
1345         {
1346             DWORD Csb[2];
1347             Csb[0] = mask;
1348             Csb[1] = 0x0;
1349             rc = TranslateCharsetInfo((DWORD*)Csb, &cs, TCI_SRCFONTSIG);
1350             if (!rc)
1351                 continue;
1352
1353             TRACE("Falling back to least significant found CodePage %u\n",
1354                     cs.ciACP);
1355             *puCodePage = cs.ciACP;
1356             return S_OK;
1357         }
1358     }
1359
1360     TRACE("no codepage found\n");
1361     return E_FAIL;
1362 }
1363
1364 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
1365         IMLangFontLink* iface,
1366         HDC hDC,
1367         HFONT hFont,
1368         DWORD* pdwCodePages)
1369 {
1370     HFONT old_font;
1371     FONTSIGNATURE fontsig;
1372     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1373
1374     TRACE("(%p)\n",This);
1375
1376     old_font = SelectObject(hDC,hFont);
1377     GetTextCharsetInfo(hDC,&fontsig, 0);
1378     SelectObject(hDC,old_font);
1379
1380     *pdwCodePages = fontsig.fsCsb[0];
1381     TRACE("CodePages is 0x%lx\n",fontsig.fsCsb[0]);
1382
1383     return S_OK;
1384 }
1385
1386 static HRESULT WINAPI fnIMLangFontLink_MapFont(
1387         IMLangFontLink* iface,
1388         HDC hDC,
1389         DWORD dwCodePages,
1390         HFONT hSrcFont,
1391         HFONT* phDestFont)
1392 {
1393     FIXME("\n");
1394     return E_NOTIMPL;
1395 }
1396
1397 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
1398         IMLangFontLink* iface,
1399         HFONT hFont)
1400 {
1401     FIXME("\n");
1402     return E_NOTIMPL;
1403 }
1404
1405 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
1406         IMLangFontLink* iface)
1407 {
1408     FIXME("\n");
1409     return E_NOTIMPL;
1410 }
1411
1412
1413 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
1414 {
1415     fnIMLangFontLink_QueryInterface,
1416     fnIMLangFontLink_AddRef,
1417     fnIMLangFontLink_Release,
1418     fnIMLangFontLink_GetCharCodePages,
1419     fnIMLangFontLink_GetStrCodePages,
1420     fnIMLangFontLink_CodePageToCodePages,
1421     fnIMLangFontLink_CodePagesToCodePage,
1422     fnIMLangFontLink_GetFontCodePages,
1423     fnIMLangFontLink_MapFont,
1424     fnIMLangFontLink_ReleaseFont,
1425     fnIMLangFontLink_ResetFontMapping,
1426 };
1427
1428 /******************************************************************************/
1429
1430 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
1431     IMultiLanguage* iface,
1432     REFIID riid,
1433     void** ppvObject)
1434 {
1435     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1436     return MLang_QueryInterface( This, riid, ppvObject );
1437 }
1438
1439 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
1440 {
1441     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1442     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
1443 }
1444
1445 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
1446 {
1447     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1448     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
1449 }
1450
1451 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
1452     IMultiLanguage* iface,
1453     UINT* pcCodePage)
1454 {
1455     FIXME("\n");
1456     return E_NOTIMPL;
1457 }
1458
1459 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
1460     IMultiLanguage* iface,
1461     UINT uiCodePage,
1462     PMIMECPINFO pCodePageInfo)
1463 {
1464     FIXME("\n");
1465     return E_NOTIMPL;
1466 }
1467
1468 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
1469     IMultiLanguage* iface,
1470     UINT uiCodePage,
1471     UINT* puiFamilyCodePage)
1472 {
1473     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1474 }
1475
1476 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
1477     IMultiLanguage* iface,
1478     DWORD grfFlags,
1479     IEnumCodePage** ppEnumCodePage)
1480 {
1481     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1482     TRACE("%p %08lx %p\n", This, grfFlags, ppEnumCodePage);
1483
1484     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
1485 }
1486
1487 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
1488     IMultiLanguage* iface,
1489     BSTR Charset,
1490     PMIMECSETINFO pCharsetInfo)
1491 {
1492     FIXME("\n");
1493     return E_NOTIMPL;
1494 }
1495
1496 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
1497     IMultiLanguage* iface,
1498     DWORD dwSrcEncoding,
1499     DWORD dwDstEncoding)
1500 {
1501     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
1502 }
1503
1504 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
1505     IMultiLanguage* iface,
1506     DWORD* pdwMode,
1507     DWORD dwSrcEncoding,
1508     DWORD dwDstEncoding,
1509     BYTE* pSrcStr,
1510     UINT* pcSrcSize,
1511     BYTE* pDstStr,
1512     UINT* pcDstSize)
1513 {
1514     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
1515         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
1516 }
1517
1518 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
1519     IMultiLanguage* iface,
1520     DWORD* pdwMode,
1521     DWORD dwEncoding,
1522     CHAR* pSrcStr,
1523     UINT* pcSrcSize,
1524     WCHAR* pDstStr,
1525     UINT* pcDstSize)
1526 {
1527     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
1528         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1529 }
1530
1531 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
1532     IMultiLanguage* iface,
1533     DWORD* pdwMode,
1534     DWORD dwEncoding,
1535     WCHAR* pSrcStr,
1536     UINT* pcSrcSize,
1537     CHAR* pDstStr,
1538     UINT* pcDstSize)
1539 {
1540     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
1541         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1542 }
1543
1544 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
1545     IMultiLanguage* iface)
1546 {
1547     FIXME("\n");
1548     return E_NOTIMPL;
1549 }
1550
1551 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
1552     IMultiLanguage* iface,
1553     LCID Locale,
1554     BSTR* pbstrRfc1766)
1555 {
1556     FIXME("\n");
1557     return E_NOTIMPL;
1558 }
1559
1560 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
1561     IMultiLanguage* iface,
1562     LCID* pLocale,
1563     BSTR bstrRfc1766)
1564 {
1565     FIXME("\n");
1566     return E_NOTIMPL;
1567 }
1568
1569 /******************************************************************************/
1570
1571 typedef struct tagEnumRfc1766_impl
1572 {
1573     const IEnumRfc1766Vtbl *vtbl_IEnumRfc1766;
1574     LONG ref;
1575     RFC1766INFO *info;
1576     DWORD total, pos;
1577 } EnumRfc1766_impl;
1578
1579 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
1580         IEnumRfc1766 *iface,
1581         REFIID riid,
1582         void** ppvObject)
1583 {
1584     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1585
1586     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1587
1588     if (IsEqualGUID(riid, &IID_IUnknown)
1589         || IsEqualGUID(riid, &IID_IEnumRfc1766))
1590     {
1591         IEnumRfc1766_AddRef(iface);
1592         TRACE("Returning IID_IEnumRfc1766 %p ref = %ld\n", This, This->ref);
1593         *ppvObject = &(This->vtbl_IEnumRfc1766);
1594         return S_OK;
1595     }
1596
1597     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
1598     return E_NOINTERFACE;
1599 }
1600
1601 static ULONG WINAPI fnIEnumRfc1766_AddRef(
1602         IEnumRfc1766 *iface)
1603 {
1604     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1605     return InterlockedIncrement(&This->ref);
1606 }
1607
1608 static ULONG WINAPI fnIEnumRfc1766_Release(
1609         IEnumRfc1766 *iface)
1610 {
1611     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1612     ULONG ref = InterlockedDecrement(&This->ref);
1613
1614     TRACE("%p ref = %ld\n", This, ref);
1615     if (ref == 0)
1616     {
1617         TRACE("Destroying %p\n", This);
1618         HeapFree(GetProcessHeap(), 0, This->info);
1619         HeapFree(GetProcessHeap(), 0, This);
1620     }
1621     return ref;
1622 }
1623
1624 static HRESULT WINAPI fnIEnumRfc1766_Clone(
1625         IEnumRfc1766 *iface,
1626         IEnumRfc1766 **ppEnum)
1627 {
1628     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1629     FIXME("%p %p\n", This, ppEnum);
1630     return E_NOTIMPL;
1631 }
1632
1633 static  HRESULT WINAPI fnIEnumRfc1766_Next(
1634         IEnumRfc1766 *iface,
1635         ULONG celt,
1636         PRFC1766INFO rgelt,
1637         ULONG *pceltFetched)
1638 {
1639     ULONG i;
1640
1641     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1642     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
1643
1644     if (!pceltFetched) return S_FALSE;
1645     *pceltFetched = 0;
1646
1647     if (!rgelt) return S_FALSE;
1648
1649     if (This->pos + celt > This->total)
1650         celt = This->total - This->pos;
1651
1652     if (!celt) return S_FALSE;
1653
1654     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
1655     *pceltFetched = celt;
1656     This->pos += celt;
1657
1658     for (i = 0; i < celt; i++)
1659     {
1660         TRACE("#%lu: %08lx %s %s\n",
1661               i, rgelt[i].lcid,
1662               wine_dbgstr_w(rgelt[i].wszRfc1766),
1663               wine_dbgstr_w(rgelt[i].wszLocaleName));
1664     }
1665     return S_OK;
1666 }
1667
1668 static HRESULT WINAPI fnIEnumRfc1766_Reset(
1669         IEnumRfc1766 *iface)
1670 {
1671     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1672     TRACE("%p\n", This);
1673
1674     This->pos = 0;
1675     return S_OK;
1676 }
1677
1678 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
1679         IEnumRfc1766 *iface,
1680         ULONG celt)
1681 {
1682     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1683     TRACE("%p %lu\n", This, celt);
1684
1685     if (celt >= This->total) return S_FALSE;
1686
1687     This->pos += celt;
1688     return S_OK;
1689 }
1690
1691 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
1692 {
1693     fnIEnumRfc1766_QueryInterface,
1694     fnIEnumRfc1766_AddRef,
1695     fnIEnumRfc1766_Release,
1696     fnIEnumRfc1766_Clone,
1697     fnIEnumRfc1766_Next,
1698     fnIEnumRfc1766_Reset,
1699     fnIEnumRfc1766_Skip
1700 };
1701
1702 struct enum_locales_data
1703 {
1704     RFC1766INFO *info;
1705     DWORD total, allocated;
1706 };
1707
1708 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
1709 {
1710     DWORD n;
1711     WCHAR *end;
1712     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
1713     RFC1766INFO *info;
1714
1715     TRACE("%s\n", debugstr_w(locale));
1716
1717     if (data->total >= data->allocated)
1718     {
1719         data->allocated += 32;
1720         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
1721         if (!data->info) return FALSE;
1722     }
1723
1724     info = &data->info[data->total];
1725
1726     info->lcid = strtolW(locale, &end, 16);
1727     if (*end) /* invalid number */
1728         return FALSE;
1729
1730     info->wszRfc1766[0] = 0;
1731     n = GetLocaleInfoW(info->lcid, LOCALE_SISO639LANGNAME, info->wszRfc1766, MAX_RFC1766_NAME);
1732     if (n && n < MAX_RFC1766_NAME)
1733     {
1734         info->wszRfc1766[n - 1] = '-';
1735         GetLocaleInfoW(info->lcid, LOCALE_SISO3166CTRYNAME, info->wszRfc1766 + n, MAX_RFC1766_NAME - n);
1736         LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, info->wszRfc1766 + n, -1, info->wszRfc1766 + n, MAX_RFC1766_NAME - n);
1737     }
1738     info->wszLocaleName[0] = 0;
1739     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
1740     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
1741     
1742     data->total++;
1743
1744     return TRUE;
1745 }
1746
1747 static HRESULT EnumRfc1766_create(MLang_impl* mlang, LANGID LangId,
1748                                   IEnumRfc1766 **ppEnum)
1749 {
1750     EnumRfc1766_impl *rfc;
1751     struct enum_locales_data data;
1752
1753     TRACE("%p, %04x, %p\n", mlang, LangId, ppEnum);
1754
1755     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
1756     rfc->vtbl_IEnumRfc1766 = &IEnumRfc1766_vtbl;
1757     rfc->ref = 1;
1758     rfc->pos = 0;
1759     rfc->total = 0;
1760
1761     data.total = 0;
1762     data.allocated = 32;
1763     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
1764     if (!data.info) return S_FALSE;
1765
1766     TlsSetValue(MLANG_tls_index, &data);
1767     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
1768     TlsSetValue(MLANG_tls_index, NULL);
1769
1770     TRACE("enumerated %ld rfc1766 structures\n", data.total);
1771
1772     if (!data.total) return FALSE;
1773
1774     rfc->info = data.info;
1775     rfc->total = data.total;
1776
1777     *ppEnum = (IEnumRfc1766 *)rfc;
1778     return S_OK;
1779 }
1780
1781 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
1782     IMultiLanguage *iface,
1783     IEnumRfc1766 **ppEnumRfc1766)
1784 {
1785     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1786     TRACE("%p %p\n", This, ppEnumRfc1766);
1787
1788     return EnumRfc1766_create(This, 0, ppEnumRfc1766);
1789 }
1790
1791 /******************************************************************************/
1792
1793 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
1794     IMultiLanguage* iface,
1795     LCID Locale,
1796     PRFC1766INFO pRfc1766Info)
1797 {
1798     FIXME("\n");
1799     return E_NOTIMPL;
1800 }
1801
1802 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
1803     IMultiLanguage* iface,
1804     UINT uiSrcCodePage,
1805     UINT uiDstCodePage,
1806     DWORD dwProperty,
1807     IMLangConvertCharset** ppMLangConvertCharset)
1808 {
1809     FIXME("\n");
1810     return E_NOTIMPL;
1811 }
1812
1813 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
1814 {
1815     fnIMultiLanguage_QueryInterface,
1816     fnIMultiLanguage_AddRef,
1817     fnIMultiLanguage_Release,
1818     fnIMultiLanguage_GetNumberOfCodePageInfo,
1819     fnIMultiLanguage_GetCodePageInfo,
1820     fnIMultiLanguage_GetFamilyCodePage,
1821     fnIMultiLanguage_EnumCodePages,
1822     fnIMultiLanguage_GetCharsetInfo,
1823     fnIMultiLanguage_IsConvertible,
1824     fnIMultiLanguage_ConvertString,
1825     fnIMultiLanguage_ConvertStringToUnicode,
1826     fnIMultiLanguage_ConvertStringFromUnicode,
1827     fnIMultiLanguage_ConvertStringReset,
1828     fnIMultiLanguage_GetRfc1766FromLcid,
1829     fnIMultiLanguage_GetLcidFromRfc1766,
1830     fnIMultiLanguage_EnumRfc1766,
1831     fnIMultiLanguage_GetRfc1766Info,
1832     fnIMultiLanguage_CreateConvertCharset,
1833 };
1834
1835
1836 /******************************************************************************/
1837
1838 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
1839     IMultiLanguage3* iface,
1840     REFIID riid,
1841     void** ppvObject)
1842 {
1843     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1844     return MLang_QueryInterface( This, riid, ppvObject );
1845 }
1846
1847 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage3* iface )
1848 {
1849     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1850     return MLang_AddRef( This );
1851 }
1852
1853 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage3* iface )
1854 {
1855     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1856     return MLang_Release( This );
1857 }
1858
1859 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
1860     IMultiLanguage3* iface,
1861     UINT* pcCodePage)
1862 {
1863     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1864     TRACE("%p, %p\n", This, pcCodePage);
1865
1866     if (!pcCodePage) return S_FALSE;
1867
1868     *pcCodePage = This->total_cp;
1869     return S_OK;
1870 }
1871
1872 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
1873 {
1874     CHARSETINFO csi;
1875
1876     if (TranslateCharsetInfo((DWORD *)ml_data->family_codepage, &csi, TCI_SRCCODEPAGE))
1877         mime_cp_info->bGDICharset = csi.ciCharset;
1878     else
1879         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
1880
1881     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
1882     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
1883     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
1884     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
1885                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
1886     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
1887                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
1888     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
1889                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
1890     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
1891                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
1892
1893     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
1894         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
1895     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
1896         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
1897
1898     TRACE("%08lx %u %u %s %s %s %s %s %s %d\n",
1899           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
1900           mime_cp_info->uiFamilyCodePage,
1901           wine_dbgstr_w(mime_cp_info->wszDescription),
1902           wine_dbgstr_w(mime_cp_info->wszWebCharset),
1903           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
1904           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
1905           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
1906           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
1907           mime_cp_info->bGDICharset);
1908 }
1909
1910 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
1911     IMultiLanguage3* iface,
1912     UINT uiCodePage,
1913     LANGID LangId,
1914     PMIMECPINFO pCodePageInfo)
1915 {
1916     UINT i, n;
1917
1918     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1919     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
1920
1921     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1922     {
1923         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1924         {
1925             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1926             {
1927                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
1928                 return S_OK;
1929             }
1930         }
1931     }
1932
1933     return S_FALSE;
1934 }
1935
1936 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
1937     IMultiLanguage3* iface,
1938     UINT uiCodePage,
1939     UINT* puiFamilyCodePage)
1940 {
1941     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1942 }
1943
1944 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
1945     IMultiLanguage3* iface,
1946     DWORD grfFlags,
1947     LANGID LangId,
1948     IEnumCodePage** ppEnumCodePage)
1949 {
1950     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1951     TRACE("%p %08lx %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
1952
1953     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
1954 }
1955
1956 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
1957     IMultiLanguage3* iface,
1958     BSTR Charset,
1959     PMIMECSETINFO pCharsetInfo)
1960 {
1961     UINT i, n;
1962
1963     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
1964     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
1965
1966     if (!pCharsetInfo) return E_FAIL;
1967
1968     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1969     {
1970         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1971         {
1972             WCHAR csetW[MAX_MIMECSET_NAME];
1973
1974             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
1975             if (!lstrcmpiW(Charset, csetW))
1976             {
1977                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
1978                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
1979                 strcpyW(pCharsetInfo->wszCharset, csetW);
1980                 return S_OK;
1981             }
1982         }
1983     }
1984
1985     /* FIXME:
1986      * Since we do not support charsets like iso-2022-jp and do not have
1987      * them in our database as a primary (web_charset) encoding this loop
1988      * does an attempt to 'approximate' charset name by header_charset.
1989      */
1990     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1991     {
1992         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1993         {
1994             WCHAR csetW[MAX_MIMECSET_NAME];
1995
1996             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
1997             if (!lstrcmpiW(Charset, csetW))
1998             {
1999                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2000                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2001                 strcpyW(pCharsetInfo->wszCharset, csetW);
2002                 return S_OK;
2003             }
2004         }
2005     }
2006
2007     return E_FAIL;
2008 }
2009
2010 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2011     IMultiLanguage3* iface,
2012     DWORD dwSrcEncoding,
2013     DWORD dwDstEncoding)
2014 {
2015     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2016 }
2017
2018 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2019     IMultiLanguage3* iface,
2020     DWORD* pdwMode,
2021     DWORD dwSrcEncoding,
2022     DWORD dwDstEncoding,
2023     BYTE* pSrcStr,
2024     UINT* pcSrcSize,
2025     BYTE* pDstStr,
2026     UINT* pcDstSize)
2027 {
2028     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2029         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2030 }
2031
2032 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2033     IMultiLanguage3* iface,
2034     DWORD* pdwMode,
2035     DWORD dwEncoding,
2036     CHAR* pSrcStr,
2037     UINT* pcSrcSize,
2038     WCHAR* pDstStr,
2039     UINT* pcDstSize)
2040 {
2041     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2042         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2043 }
2044
2045 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2046     IMultiLanguage3* iface,
2047     DWORD* pdwMode,
2048     DWORD dwEncoding,
2049     WCHAR* pSrcStr,
2050     UINT* pcSrcSize,
2051     CHAR* pDstStr,
2052     UINT* pcDstSize)
2053 {
2054     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2055         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2056 }
2057
2058 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2059     IMultiLanguage3* iface)
2060 {
2061     FIXME("\n");
2062     return E_NOTIMPL;
2063 }
2064
2065 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2066     IMultiLanguage3* iface,
2067     LCID Locale,
2068     BSTR* pbstrRfc1766)
2069 {
2070     FIXME("\n");
2071     return E_NOTIMPL;
2072 }
2073
2074 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2075     IMultiLanguage3* iface,
2076     LCID* pLocale,
2077     BSTR bstrRfc1766)
2078 {
2079     FIXME("\n");
2080     return E_NOTIMPL;
2081 }
2082
2083 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2084     IMultiLanguage3* iface,
2085     LANGID LangId,
2086     IEnumRfc1766** ppEnumRfc1766)
2087 {
2088     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2089     TRACE("%p %p\n", This, ppEnumRfc1766);
2090
2091     return EnumRfc1766_create(This, LangId, ppEnumRfc1766);
2092 }
2093
2094 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2095     IMultiLanguage3* iface,
2096     LCID Locale,
2097     LANGID LangId,
2098     PRFC1766INFO pRfc1766Info)
2099 {
2100     FIXME("\n");
2101     return E_NOTIMPL;
2102 }
2103
2104 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2105     IMultiLanguage3* iface,
2106     UINT uiSrcCodePage,
2107     UINT uiDstCodePage,
2108     DWORD dwProperty,
2109     IMLangConvertCharset** ppMLangConvertCharset)
2110 {
2111     FIXME("\n");
2112     return E_NOTIMPL;
2113 }
2114
2115 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2116     IMultiLanguage3* iface,
2117     DWORD* pdwMode,
2118     DWORD dwFlag,
2119     WCHAR* lpFallBack,
2120     DWORD dwSrcEncoding,
2121     DWORD dwDstEncoding,
2122     IStream* pstmIn,
2123     IStream* pstmOut)
2124 {
2125     FIXME("\n");
2126     return E_NOTIMPL;
2127 }
2128
2129 /*
2130  * TODO: handle dwFlag and lpFallBack
2131 */
2132 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
2133     IMultiLanguage3* iface,
2134     DWORD* pdwMode,
2135     DWORD dwEncoding,
2136     CHAR* pSrcStr,
2137     UINT* pcSrcSize,
2138     WCHAR* pDstStr,
2139     UINT* pcDstSize,
2140     DWORD dwFlag,
2141     WCHAR* lpFallBack)
2142 {
2143     FIXME("\n");
2144     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2145         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2146 }
2147
2148 /*****************************************************************************
2149  * MultiLanguage2::ConvertStringToUnicodeEx
2150  *
2151  * Translates the multibyte string from the specified code page to Unicode.
2152  *
2153  * PARAMS
2154  *   see ConvertStringToUnicode
2155  *   dwFlag 
2156  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
2157  *              instead unconvertible characters.
2158  *
2159  * RETURNS
2160  *   S_OK     Success.
2161  *   S_FALSE  The conversion is not supported.
2162  *   E_FAIL   Some error has occurred.
2163  *
2164  * TODO: handle dwFlag and lpFallBack
2165 */
2166 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
2167     IMultiLanguage3* This,
2168     DWORD* pdwMode,
2169     DWORD dwEncoding,
2170     WCHAR* pSrcStr,
2171     UINT* pcSrcSize,
2172     CHAR* pDstStr,
2173     UINT* pcDstSize,
2174     DWORD dwFlag,
2175     WCHAR* lpFallBack)
2176 {
2177     FIXME("\n");
2178     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2179         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2180 }
2181
2182 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
2183     IMultiLanguage3* iface,
2184     DWORD dwFlag,
2185     DWORD dwPrefWinCodePage,
2186     IStream* pstmIn,
2187     DetectEncodingInfo* lpEncoding,
2188     INT* pnScores)
2189 {
2190     FIXME("\n");
2191     return E_NOTIMPL;
2192 }
2193
2194 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
2195     IMultiLanguage3* iface,
2196     DWORD dwFlag,
2197     DWORD dwPrefWinCodePage,
2198     CHAR* pSrcStr,
2199     INT* pcSrcSize,
2200     DetectEncodingInfo* lpEncoding,
2201     INT* pnScores)
2202 {
2203     FIXME("\n");
2204     return E_NOTIMPL;
2205 }
2206
2207 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
2208     IMultiLanguage3* iface,
2209     UINT uiCodePage,
2210     HWND hwnd)
2211 {
2212     FIXME("%u, %p\n", uiCodePage, hwnd);
2213     return E_NOTIMPL;
2214 }
2215
2216 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
2217     IMultiLanguage3* iface,
2218     UINT uiCodePage,
2219     LCID lcid,
2220     LPWSTR lpWideCharStr,
2221     int cchWideChar)
2222 {
2223     FIXME("%u, %04lx, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
2224     return E_NOTIMPL;
2225 }
2226
2227 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
2228     IMultiLanguage3* iface,
2229     UINT uiCodePage)
2230 {
2231     FIXME("%u\n", uiCodePage);
2232     return E_NOTIMPL;
2233 }
2234
2235 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
2236     IMultiLanguage3* iface,
2237     MIMECONTF dwSource)
2238 {
2239     FIXME("0x%08x\n", dwSource);
2240     return S_OK;
2241 }
2242
2243 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
2244     IMultiLanguage3* iface,
2245     UINT* pnScripts)
2246 {
2247     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2248     TRACE("%p %p\n", This, pnScripts);
2249
2250     if (!pnScripts) return S_FALSE;
2251
2252     *pnScripts = This->total_scripts;
2253     return S_OK;
2254 }
2255
2256 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
2257     IMultiLanguage3* iface,
2258     DWORD dwFlags,
2259     LANGID LangId,
2260     IEnumScript** ppEnumScript)
2261 {
2262     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2263     TRACE("%p %08lx %04x %p\n", This, dwFlags, LangId, ppEnumScript);
2264
2265     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
2266 }
2267
2268 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
2269     IMultiLanguage3* iface,
2270     UINT uiCodePage,
2271     HWND hwnd,
2272     DWORD dwfIODControl)
2273 {
2274     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2275     FIXME("%p %u %p %08lx: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
2276
2277     return S_FALSE;
2278 }
2279
2280 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
2281     IMultiLanguage3 *iface,
2282     DWORD dwFlags,
2283     LPCWSTR lpWideCharStr,
2284     UINT cchWideChar,
2285     UINT *puiPreferredCodePages,
2286     UINT nPreferredCodePages,
2287     UINT *puiDetectedCodePages,
2288     UINT *pnDetectedCodePages,
2289     WCHAR *lpSpecialChar)
2290 {
2291     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2292     FIXME("(%p)->(%08lx %s %u %p %u %p %p %p)\n", This, dwFlags, debugstr_w(lpWideCharStr),
2293           cchWideChar, puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
2294           pnDetectedCodePages, lpSpecialChar);
2295     return E_NOTIMPL;
2296 }
2297
2298 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
2299     IMultiLanguage3 *iface,
2300     DWORD dwFlags,
2301     IStream *pStrIn,
2302     UINT *puiPreferredCodePages,
2303     UINT nPreferredCodePages,
2304     UINT *puiDetectedCodePages,
2305     UINT *pnDetectedCodePages,
2306     WCHAR *lpSpecialChar)
2307 {
2308     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage3, iface);
2309     FIXME("(%p)->(%08lx %p %p %u %p %p %p)\n", This, dwFlags, pStrIn,
2310           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
2311           pnDetectedCodePages, lpSpecialChar);
2312     return E_NOTIMPL;
2313 }
2314
2315 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
2316 {
2317     fnIMultiLanguage2_QueryInterface,
2318     fnIMultiLanguage2_AddRef,
2319     fnIMultiLanguage2_Release,
2320     fnIMultiLanguage2_GetNumberOfCodePageInfo,
2321     fnIMultiLanguage2_GetCodePageInfo,
2322     fnIMultiLanguage2_GetFamilyCodePage,
2323     fnIMultiLanguage2_EnumCodePages,
2324     fnIMultiLanguage2_GetCharsetInfo,
2325     fnIMultiLanguage2_IsConvertible,
2326     fnIMultiLanguage2_ConvertString,
2327     fnIMultiLanguage2_ConvertStringToUnicode,
2328     fnIMultiLanguage2_ConvertStringFromUnicode,
2329     fnIMultiLanguage2_ConvertStringReset,
2330     fnIMultiLanguage2_GetRfc1766FromLcid,
2331     fnIMultiLanguage2_GetLcidFromRfc1766,
2332     fnIMultiLanguage2_EnumRfc1766,
2333     fnIMultiLanguage2_GetRfc1766Info,
2334     fnIMultiLanguage2_CreateConvertCharset,
2335     fnIMultiLanguage2_ConvertStringInIStream,
2336     fnIMultiLanguage2_ConvertStringToUnicodeEx,
2337     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
2338     fnIMultiLanguage2_DetectCodepageInIStream,
2339     fnIMultiLanguage2_DetectInputCodepage,
2340     fnIMultiLanguage2_ValidateCodePage,
2341     fnIMultiLanguage2_GetCodePageDescription,
2342     fnIMultiLanguage2_IsCodePageInstallable,
2343     fnIMultiLanguage2_SetMimeDBSource,
2344     fnIMultiLanguage2_GetNumberOfScripts,
2345     fnIMultiLanguage2_EnumScripts,
2346     fnIMultiLanguage2_ValidateCodePageEx,
2347     fnIMultiLanguage3_DetectOutboundCodePage,
2348     fnIMultiLanguage3_DetectOutboundCodePageInIStream
2349 };
2350
2351 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
2352 {
2353     MLang_impl *mlang;
2354     UINT i;
2355
2356     TRACE("Creating MultiLanguage object\n");
2357
2358     if( pUnkOuter )
2359         return CLASS_E_NOAGGREGATION;
2360
2361     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
2362     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
2363     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
2364     mlang->vtbl_IMultiLanguage3 = &IMultiLanguage3_vtbl;
2365
2366     mlang->total_cp = 0;
2367     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2368         mlang->total_cp += mlang_data[i].number_of_cp;
2369
2370     /* do not enumerate unicode flavours */
2371     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
2372
2373     mlang->ref = 1;
2374     *ppObj = (LPVOID) mlang;
2375     TRACE("returning %p\n", mlang);
2376
2377     LockModule();
2378
2379     return S_OK;
2380 }
2381
2382 /******************************************************************************/
2383
2384 HRESULT WINAPI DllCanUnloadNow(void)
2385 {
2386     return dll_count == 0 ? S_OK : S_FALSE;
2387 }
2388
2389 HRESULT WINAPI GetGlobalFontLinkObject(void)
2390 {
2391     FIXME("\n");
2392     return S_FALSE;
2393 }