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