mlang: Add us-ascii encoding to the list of supported encodings.
[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 IMultiLanguage2Vtbl *vtbl_IMultiLanguage2;
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_IMultiLanguage2);
879         TRACE("Returning IID_IMultiLanguage2 %p ref = %ld\n", This, This->ref);
880         return S_OK;
881     }
882
883     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
884     return E_NOINTERFACE;
885 }
886
887 /******************************************************************************/
888
889 typedef struct tagEnumCodePage_impl
890 {
891     const IEnumCodePageVtbl *vtbl_IEnumCodePage;
892     LONG ref;
893     MIMECPINFO *cpinfo;
894     DWORD total, pos;
895 } EnumCodePage_impl;
896
897 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
898         IEnumCodePage* iface,
899         REFIID riid,
900         void** ppvObject)
901 {
902     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
903
904     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
905
906     if (IsEqualGUID(riid, &IID_IUnknown)
907         || IsEqualGUID(riid, &IID_IEnumCodePage))
908     {
909         IEnumCodePage_AddRef(iface);
910         TRACE("Returning IID_IEnumCodePage %p ref = %ld\n", This, This->ref);
911         *ppvObject = &(This->vtbl_IEnumCodePage);
912         return S_OK;
913     }
914
915     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
916     return E_NOINTERFACE;
917 }
918
919 static ULONG WINAPI fnIEnumCodePage_AddRef(
920         IEnumCodePage* iface)
921 {
922     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
923     return InterlockedIncrement(&This->ref);
924 }
925
926 static ULONG WINAPI fnIEnumCodePage_Release(
927         IEnumCodePage* iface)
928 {
929     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
930     ULONG ref = InterlockedDecrement(&This->ref);
931
932     TRACE("%p ref = %ld\n", This, ref);
933     if (ref == 0)
934     {
935         TRACE("Destroying %p\n", This);
936         HeapFree(GetProcessHeap(), 0, This->cpinfo);
937         HeapFree(GetProcessHeap(), 0, This);
938     }
939
940     return ref;
941 }
942
943 static HRESULT WINAPI fnIEnumCodePage_Clone(
944         IEnumCodePage* iface,
945         IEnumCodePage** ppEnum)
946 {
947     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
948     FIXME("%p %p\n", This, ppEnum);
949     return E_NOTIMPL;
950 }
951
952 static  HRESULT WINAPI fnIEnumCodePage_Next(
953         IEnumCodePage* iface,
954         ULONG celt,
955         PMIMECPINFO rgelt,
956         ULONG* pceltFetched)
957 {
958     ULONG i;
959
960     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
961     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
962
963     if (!pceltFetched) return S_FALSE;
964     *pceltFetched = 0;
965
966     if (!rgelt) return S_FALSE;
967
968     if (This->pos + celt > This->total)
969         celt = This->total - This->pos;
970
971     if (!celt) return S_FALSE;
972
973     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
974     *pceltFetched = celt;
975     This->pos += celt;
976
977     for (i = 0; i < celt; i++)
978     {
979         TRACE("#%lu: %08lx %u %u %s %s %s %s %s %s %d\n",
980               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
981               rgelt[i].uiFamilyCodePage,
982               wine_dbgstr_w(rgelt[i].wszDescription),
983               wine_dbgstr_w(rgelt[i].wszWebCharset),
984               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
985               wine_dbgstr_w(rgelt[i].wszBodyCharset),
986               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
987               wine_dbgstr_w(rgelt[i].wszProportionalFont),
988               rgelt[i].bGDICharset);
989     }
990     return S_OK;
991 }
992
993 static HRESULT WINAPI fnIEnumCodePage_Reset(
994         IEnumCodePage* iface)
995 {
996     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
997     TRACE("%p\n", This);
998
999     This->pos = 0;
1000     return S_OK;
1001 }
1002
1003 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1004         IEnumCodePage* iface,
1005         ULONG celt)
1006 {
1007     ICOM_THIS_MULTI(EnumCodePage_impl, vtbl_IEnumCodePage, iface);
1008     TRACE("%p %lu\n", This, celt);
1009
1010     if (celt >= This->total) return S_FALSE;
1011
1012     This->pos += celt;
1013     return S_OK;
1014 }
1015
1016 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1017 {
1018     fnIEnumCodePage_QueryInterface,
1019     fnIEnumCodePage_AddRef,
1020     fnIEnumCodePage_Release,
1021     fnIEnumCodePage_Clone,
1022     fnIEnumCodePage_Next,
1023     fnIEnumCodePage_Reset,
1024     fnIEnumCodePage_Skip
1025 };
1026
1027 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1028                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1029 {
1030     EnumCodePage_impl *ecp;
1031     MIMECPINFO *cpinfo;
1032     UINT i, n;
1033
1034     TRACE("%p, %08lx, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1035
1036     if (!grfFlags) /* enumerate internal data base of encodings */
1037         grfFlags = MIMECONTF_MIME_LATEST;
1038
1039     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1040     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
1041     ecp->ref = 1;
1042     ecp->pos = 0;
1043     ecp->total = 0;
1044     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1045     {
1046         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1047         {
1048             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1049                 ecp->total++;
1050         }
1051     }
1052
1053     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1054                             sizeof(MIMECPINFO) * ecp->total);
1055     cpinfo = ecp->cpinfo;
1056
1057     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1058     {
1059         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1060         {
1061             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1062                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1063         }
1064     }
1065
1066     TRACE("enumerated %ld codepages with flags %08lx\n", ecp->total, grfFlags);
1067
1068     *ppEnumCodePage = (IEnumCodePage*) ecp;
1069
1070     return S_OK;
1071 }
1072
1073 /******************************************************************************/
1074
1075 typedef struct tagEnumScript_impl
1076 {
1077     const IEnumScriptVtbl *vtbl_IEnumScript;
1078     LONG ref;
1079     SCRIPTINFO *script_info;
1080     DWORD total, pos;
1081 } EnumScript_impl;
1082
1083 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1084         IEnumScript* iface,
1085         REFIID riid,
1086         void** ppvObject)
1087 {
1088     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1089
1090     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1091
1092     if (IsEqualGUID(riid, &IID_IUnknown)
1093         || IsEqualGUID(riid, &IID_IEnumScript))
1094     {
1095         IEnumScript_AddRef(iface);
1096         TRACE("Returning IID_IEnumScript %p ref = %ld\n", This, This->ref);
1097         *ppvObject = &(This->vtbl_IEnumScript);
1098         return S_OK;
1099     }
1100
1101     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1102     return E_NOINTERFACE;
1103 }
1104
1105 static ULONG WINAPI fnIEnumScript_AddRef(
1106         IEnumScript* iface)
1107 {
1108     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1109     return InterlockedIncrement(&This->ref);
1110 }
1111
1112 static ULONG WINAPI fnIEnumScript_Release(
1113         IEnumScript* iface)
1114 {
1115     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1116     ULONG ref = InterlockedDecrement(&This->ref);
1117
1118     TRACE("%p ref = %ld\n", This, ref);
1119     if (ref == 0)
1120     {
1121         TRACE("Destroying %p\n", This);
1122         HeapFree(GetProcessHeap(), 0, This);
1123     }
1124
1125     return ref;
1126 }
1127
1128 static HRESULT WINAPI fnIEnumScript_Clone(
1129         IEnumScript* iface,
1130         IEnumScript** ppEnum)
1131 {
1132     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1133     FIXME("%p %p: stub!\n", This, ppEnum);
1134     return E_NOTIMPL;
1135 }
1136
1137 static  HRESULT WINAPI fnIEnumScript_Next(
1138         IEnumScript* iface,
1139         ULONG celt,
1140         PSCRIPTINFO rgelt,
1141         ULONG* pceltFetched)
1142 {
1143     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1144     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
1145
1146     if (!pceltFetched || !rgelt) return E_FAIL;
1147
1148     *pceltFetched = 0;
1149
1150     if (This->pos + celt > This->total)
1151         celt = This->total - This->pos;
1152
1153     if (!celt) return S_FALSE;
1154
1155     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1156     *pceltFetched = celt;
1157     This->pos += celt;
1158
1159     return S_OK;
1160 }
1161
1162 static HRESULT WINAPI fnIEnumScript_Reset(
1163         IEnumScript* iface)
1164 {
1165     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1166     TRACE("%p\n", This);
1167
1168     This->pos = 0;
1169     return S_OK;
1170 }
1171
1172 static  HRESULT WINAPI fnIEnumScript_Skip(
1173         IEnumScript* iface,
1174         ULONG celt)
1175 {
1176     ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
1177     TRACE("%p %lu\n", This, celt);
1178
1179     if (celt >= This->total) return S_FALSE;
1180
1181     This->pos += celt;
1182     return S_OK;
1183 }
1184
1185 static const IEnumScriptVtbl IEnumScript_vtbl =
1186 {
1187     fnIEnumScript_QueryInterface,
1188     fnIEnumScript_AddRef,
1189     fnIEnumScript_Release,
1190     fnIEnumScript_Clone,
1191     fnIEnumScript_Next,
1192     fnIEnumScript_Reset,
1193     fnIEnumScript_Skip
1194 };
1195
1196 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1197                      LANGID LangId, IEnumScript** ppEnumScript )
1198 {
1199     EnumScript_impl *es;
1200     UINT i;
1201
1202     TRACE("%p, %08lx, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
1203
1204     if (!dwFlags) /* enumerate all available scripts */
1205         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1206
1207     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1208     es->vtbl_IEnumScript = &IEnumScript_vtbl;
1209     es->ref = 1;
1210     es->pos = 0;
1211     /* do not enumerate unicode flavours */
1212     es->total = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
1213     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1214
1215     for (i = 0; i < es->total; i++)
1216     {
1217         es->script_info[i].ScriptId = i;
1218         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1219         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1220             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1221         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1222             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1223         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1224             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1225     }
1226
1227     TRACE("enumerated %ld scripts with flags %08lx\n", es->total, dwFlags);
1228
1229     *ppEnumScript = (IEnumScript *)es;
1230
1231     return S_OK;
1232 }
1233
1234 /******************************************************************************/
1235
1236 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1237         IMLangFontLink* iface,
1238         REFIID riid,
1239         void** ppvObject)
1240 {
1241     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1242     return MLang_QueryInterface( This, riid, ppvObject );
1243 }
1244
1245 static ULONG WINAPI fnIMLangFontLink_AddRef(
1246         IMLangFontLink* iface)
1247 {
1248     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1249     return MLang_AddRef( This );
1250 }
1251
1252 static ULONG WINAPI fnIMLangFontLink_Release(
1253         IMLangFontLink* iface)
1254 {
1255     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1256     return MLang_Release( This );
1257 }
1258
1259 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1260         IMLangFontLink* iface,
1261         WCHAR chSrc,
1262         DWORD* pdwCodePages)
1263 {
1264     FIXME("\n");
1265     return E_NOTIMPL;
1266 }
1267
1268 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
1269         IMLangFontLink* iface,
1270         const WCHAR* pszSrc,
1271         long cchSrc,
1272         DWORD dwPriorityCodePages,
1273         DWORD* pdwCodePages,
1274         long* pcchCodePages)
1275 {
1276     FIXME("\n");
1277     return E_NOTIMPL;
1278 }
1279
1280 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
1281         IMLangFontLink* iface,
1282         UINT uCodePage,
1283         DWORD* pdwCodePages)
1284 {
1285     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1286     CHARSETINFO cs;
1287     BOOL rc; 
1288
1289     TRACE("(%p) Seeking %u\n",This, uCodePage);
1290     memset(&cs, 0, sizeof(cs));
1291
1292     rc = TranslateCharsetInfo((DWORD*)uCodePage, &cs, TCI_SRCCODEPAGE);
1293
1294     if (rc)
1295     {
1296         *pdwCodePages = cs.fs.fsCsb[0];
1297         TRACE("resulting CodePages 0x%lx\n",*pdwCodePages);
1298     }
1299     else
1300         TRACE("CodePage Not Found\n");
1301
1302     return S_OK;
1303 }
1304
1305 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
1306         IMLangFontLink* iface,
1307         DWORD dwCodePages,
1308         UINT uDefaultCodePage,
1309         UINT* puCodePage)
1310 {
1311     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1312     DWORD mask = 0x00000000;
1313     UINT i;
1314     CHARSETINFO cs;
1315     BOOL rc; 
1316
1317     TRACE("(%p) scanning  0x%lx  default page %u\n",This, dwCodePages,
1318             uDefaultCodePage);
1319
1320     *puCodePage = 0x00000000;
1321
1322     rc = TranslateCharsetInfo((DWORD*)uDefaultCodePage, &cs, TCI_SRCCODEPAGE);
1323   
1324     if (rc && (dwCodePages & cs.fs.fsCsb[0]))
1325     {
1326         TRACE("Found Default Codepage\n");
1327         *puCodePage = uDefaultCodePage;
1328         return S_OK;
1329     }
1330
1331     
1332     for (i = 0; i < 32; i++)
1333     {
1334
1335         mask = 1 << i;
1336         if (dwCodePages & mask)
1337         {
1338             DWORD Csb[2];
1339             Csb[0] = mask;
1340             Csb[1] = 0x0;
1341             rc = TranslateCharsetInfo((DWORD*)Csb, &cs, TCI_SRCFONTSIG);
1342             if (!rc)
1343                 continue;
1344
1345             TRACE("Falling back to least significant found CodePage %u\n",
1346                     cs.ciACP);
1347             *puCodePage = cs.ciACP;
1348             return S_OK;
1349         }
1350     }
1351
1352     TRACE("no codepage found\n");
1353     return E_FAIL;
1354 }
1355
1356 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
1357         IMLangFontLink* iface,
1358         HDC hDC,
1359         HFONT hFont,
1360         DWORD* pdwCodePages)
1361 {
1362     HFONT old_font;
1363     FONTSIGNATURE fontsig;
1364     ICOM_THIS_MULTI(MLang_impl, vtbl_IMLangFontLink, iface);
1365
1366     TRACE("(%p)\n",This);
1367
1368     old_font = SelectObject(hDC,hFont);
1369     GetTextCharsetInfo(hDC,&fontsig, 0);
1370     SelectObject(hDC,old_font);
1371
1372     *pdwCodePages = fontsig.fsCsb[0];
1373     TRACE("CodePages is 0x%lx\n",fontsig.fsCsb[0]);
1374
1375     return S_OK;
1376 }
1377
1378 static HRESULT WINAPI fnIMLangFontLink_MapFont(
1379         IMLangFontLink* iface,
1380         HDC hDC,
1381         DWORD dwCodePages,
1382         HFONT hSrcFont,
1383         HFONT* phDestFont)
1384 {
1385     FIXME("\n");
1386     return E_NOTIMPL;
1387 }
1388
1389 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
1390         IMLangFontLink* iface,
1391         HFONT hFont)
1392 {
1393     FIXME("\n");
1394     return E_NOTIMPL;
1395 }
1396
1397 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
1398         IMLangFontLink* iface)
1399 {
1400     FIXME("\n");
1401     return E_NOTIMPL;
1402 }
1403
1404
1405 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
1406 {
1407     fnIMLangFontLink_QueryInterface,
1408     fnIMLangFontLink_AddRef,
1409     fnIMLangFontLink_Release,
1410     fnIMLangFontLink_GetCharCodePages,
1411     fnIMLangFontLink_GetStrCodePages,
1412     fnIMLangFontLink_CodePageToCodePages,
1413     fnIMLangFontLink_CodePagesToCodePage,
1414     fnIMLangFontLink_GetFontCodePages,
1415     fnIMLangFontLink_MapFont,
1416     fnIMLangFontLink_ReleaseFont,
1417     fnIMLangFontLink_ResetFontMapping,
1418 };
1419
1420 /******************************************************************************/
1421
1422 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
1423     IMultiLanguage* iface,
1424     REFIID riid,
1425     void** ppvObject)
1426 {
1427     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1428     return MLang_QueryInterface( This, riid, ppvObject );
1429 }
1430
1431 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
1432 {
1433     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1434     return IMLangFontLink_AddRef( ((IMLangFontLink*)This) );
1435 }
1436
1437 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
1438 {
1439     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1440     return IMLangFontLink_Release( ((IMLangFontLink*)This) );
1441 }
1442
1443 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
1444     IMultiLanguage* iface,
1445     UINT* pcCodePage)
1446 {
1447     FIXME("\n");
1448     return E_NOTIMPL;
1449 }
1450
1451 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
1452     IMultiLanguage* iface,
1453     UINT uiCodePage,
1454     PMIMECPINFO pCodePageInfo)
1455 {
1456     FIXME("\n");
1457     return E_NOTIMPL;
1458 }
1459
1460 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
1461     IMultiLanguage* iface,
1462     UINT uiCodePage,
1463     UINT* puiFamilyCodePage)
1464 {
1465     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1466 }
1467
1468 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
1469     IMultiLanguage* iface,
1470     DWORD grfFlags,
1471     IEnumCodePage** ppEnumCodePage)
1472 {
1473     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1474     TRACE("%p %08lx %p\n", This, grfFlags, ppEnumCodePage);
1475
1476     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
1477 }
1478
1479 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
1480     IMultiLanguage* iface,
1481     BSTR Charset,
1482     PMIMECSETINFO pCharsetInfo)
1483 {
1484     FIXME("\n");
1485     return E_NOTIMPL;
1486 }
1487
1488 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
1489     IMultiLanguage* iface,
1490     DWORD dwSrcEncoding,
1491     DWORD dwDstEncoding)
1492 {
1493     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
1494 }
1495
1496 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
1497     IMultiLanguage* iface,
1498     DWORD* pdwMode,
1499     DWORD dwSrcEncoding,
1500     DWORD dwDstEncoding,
1501     BYTE* pSrcStr,
1502     UINT* pcSrcSize,
1503     BYTE* pDstStr,
1504     UINT* pcDstSize)
1505 {
1506     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
1507         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
1508 }
1509
1510 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
1511     IMultiLanguage* iface,
1512     DWORD* pdwMode,
1513     DWORD dwEncoding,
1514     CHAR* pSrcStr,
1515     UINT* pcSrcSize,
1516     WCHAR* pDstStr,
1517     UINT* pcDstSize)
1518 {
1519     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
1520         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1521 }
1522
1523 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
1524     IMultiLanguage* iface,
1525     DWORD* pdwMode,
1526     DWORD dwEncoding,
1527     WCHAR* pSrcStr,
1528     UINT* pcSrcSize,
1529     CHAR* pDstStr,
1530     UINT* pcDstSize)
1531 {
1532     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
1533         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
1534 }
1535
1536 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
1537     IMultiLanguage* iface)
1538 {
1539     FIXME("\n");
1540     return E_NOTIMPL;
1541 }
1542
1543 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
1544     IMultiLanguage* iface,
1545     LCID Locale,
1546     BSTR* pbstrRfc1766)
1547 {
1548     FIXME("\n");
1549     return E_NOTIMPL;
1550 }
1551
1552 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
1553     IMultiLanguage* iface,
1554     LCID* pLocale,
1555     BSTR bstrRfc1766)
1556 {
1557     FIXME("\n");
1558     return E_NOTIMPL;
1559 }
1560
1561 /******************************************************************************/
1562
1563 typedef struct tagEnumRfc1766_impl
1564 {
1565     const IEnumRfc1766Vtbl *vtbl_IEnumRfc1766;
1566     LONG ref;
1567     RFC1766INFO *info;
1568     DWORD total, pos;
1569 } EnumRfc1766_impl;
1570
1571 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
1572         IEnumRfc1766 *iface,
1573         REFIID riid,
1574         void** ppvObject)
1575 {
1576     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1577
1578     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1579
1580     if (IsEqualGUID(riid, &IID_IUnknown)
1581         || IsEqualGUID(riid, &IID_IEnumRfc1766))
1582     {
1583         IEnumRfc1766_AddRef(iface);
1584         TRACE("Returning IID_IEnumRfc1766 %p ref = %ld\n", This, This->ref);
1585         *ppvObject = &(This->vtbl_IEnumRfc1766);
1586         return S_OK;
1587     }
1588
1589     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
1590     return E_NOINTERFACE;
1591 }
1592
1593 static ULONG WINAPI fnIEnumRfc1766_AddRef(
1594         IEnumRfc1766 *iface)
1595 {
1596     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1597     return InterlockedIncrement(&This->ref);
1598 }
1599
1600 static ULONG WINAPI fnIEnumRfc1766_Release(
1601         IEnumRfc1766 *iface)
1602 {
1603     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1604     ULONG ref = InterlockedDecrement(&This->ref);
1605
1606     TRACE("%p ref = %ld\n", This, ref);
1607     if (ref == 0)
1608     {
1609         TRACE("Destroying %p\n", This);
1610         HeapFree(GetProcessHeap(), 0, This->info);
1611         HeapFree(GetProcessHeap(), 0, This);
1612     }
1613     return ref;
1614 }
1615
1616 static HRESULT WINAPI fnIEnumRfc1766_Clone(
1617         IEnumRfc1766 *iface,
1618         IEnumRfc1766 **ppEnum)
1619 {
1620     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1621     FIXME("%p %p\n", This, ppEnum);
1622     return E_NOTIMPL;
1623 }
1624
1625 static  HRESULT WINAPI fnIEnumRfc1766_Next(
1626         IEnumRfc1766 *iface,
1627         ULONG celt,
1628         PRFC1766INFO rgelt,
1629         ULONG *pceltFetched)
1630 {
1631     ULONG i;
1632
1633     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1634     TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
1635
1636     if (!pceltFetched) return S_FALSE;
1637     *pceltFetched = 0;
1638
1639     if (!rgelt) return S_FALSE;
1640
1641     if (This->pos + celt > This->total)
1642         celt = This->total - This->pos;
1643
1644     if (!celt) return S_FALSE;
1645
1646     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
1647     *pceltFetched = celt;
1648     This->pos += celt;
1649
1650     for (i = 0; i < celt; i++)
1651     {
1652         TRACE("#%lu: %08lx %s %s\n",
1653               i, rgelt[i].lcid,
1654               wine_dbgstr_w(rgelt[i].wszRfc1766),
1655               wine_dbgstr_w(rgelt[i].wszLocaleName));
1656     }
1657     return S_OK;
1658 }
1659
1660 static HRESULT WINAPI fnIEnumRfc1766_Reset(
1661         IEnumRfc1766 *iface)
1662 {
1663     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1664     TRACE("%p\n", This);
1665
1666     This->pos = 0;
1667     return S_OK;
1668 }
1669
1670 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
1671         IEnumRfc1766 *iface,
1672         ULONG celt)
1673 {
1674     ICOM_THIS_MULTI(EnumRfc1766_impl, vtbl_IEnumRfc1766, iface);
1675     TRACE("%p %lu\n", This, celt);
1676
1677     if (celt >= This->total) return S_FALSE;
1678
1679     This->pos += celt;
1680     return S_OK;
1681 }
1682
1683 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
1684 {
1685     fnIEnumRfc1766_QueryInterface,
1686     fnIEnumRfc1766_AddRef,
1687     fnIEnumRfc1766_Release,
1688     fnIEnumRfc1766_Clone,
1689     fnIEnumRfc1766_Next,
1690     fnIEnumRfc1766_Reset,
1691     fnIEnumRfc1766_Skip
1692 };
1693
1694 struct enum_locales_data
1695 {
1696     RFC1766INFO *info;
1697     DWORD total, allocated;
1698 };
1699
1700 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
1701 {
1702     DWORD n;
1703     WCHAR *end;
1704     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
1705     RFC1766INFO *info;
1706
1707     TRACE("%s\n", debugstr_w(locale));
1708
1709     if (data->total >= data->allocated)
1710     {
1711         data->allocated += 32;
1712         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
1713         if (!data->info) return FALSE;
1714     }
1715
1716     info = &data->info[data->total];
1717
1718     info->lcid = strtolW(locale, &end, 16);
1719     if (*end) /* invalid number */
1720         return FALSE;
1721
1722     info->wszRfc1766[0] = 0;
1723     n = GetLocaleInfoW(info->lcid, LOCALE_SISO639LANGNAME, info->wszRfc1766, MAX_RFC1766_NAME);
1724     if (n && n < MAX_RFC1766_NAME)
1725     {
1726         info->wszRfc1766[n - 1] = '-';
1727         GetLocaleInfoW(info->lcid, LOCALE_SISO3166CTRYNAME, info->wszRfc1766 + n, MAX_RFC1766_NAME - n);
1728         LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, info->wszRfc1766 + n, -1, info->wszRfc1766 + n, MAX_RFC1766_NAME - n);
1729     }
1730     info->wszLocaleName[0] = 0;
1731     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
1732     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
1733     
1734     data->total++;
1735
1736     return TRUE;
1737 }
1738
1739 static HRESULT EnumRfc1766_create(MLang_impl* mlang, LANGID LangId,
1740                                   IEnumRfc1766 **ppEnum)
1741 {
1742     EnumRfc1766_impl *rfc;
1743     struct enum_locales_data data;
1744
1745     TRACE("%p, %04x, %p\n", mlang, LangId, ppEnum);
1746
1747     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
1748     rfc->vtbl_IEnumRfc1766 = &IEnumRfc1766_vtbl;
1749     rfc->ref = 1;
1750     rfc->pos = 0;
1751     rfc->total = 0;
1752
1753     data.total = 0;
1754     data.allocated = 32;
1755     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
1756     if (!data.info) return S_FALSE;
1757
1758     TlsSetValue(MLANG_tls_index, &data);
1759     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
1760     TlsSetValue(MLANG_tls_index, NULL);
1761
1762     TRACE("enumerated %ld rfc1766 structures\n", data.total);
1763
1764     if (!data.total) return FALSE;
1765
1766     rfc->info = data.info;
1767     rfc->total = data.total;
1768
1769     *ppEnum = (IEnumRfc1766 *)rfc;
1770     return S_OK;
1771 }
1772
1773 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
1774     IMultiLanguage *iface,
1775     IEnumRfc1766 **ppEnumRfc1766)
1776 {
1777     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
1778     TRACE("%p %p\n", This, ppEnumRfc1766);
1779
1780     return EnumRfc1766_create(This, 0, ppEnumRfc1766);
1781 }
1782
1783 /******************************************************************************/
1784
1785 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
1786     IMultiLanguage* iface,
1787     LCID Locale,
1788     PRFC1766INFO pRfc1766Info)
1789 {
1790     FIXME("\n");
1791     return E_NOTIMPL;
1792 }
1793
1794 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
1795     IMultiLanguage* iface,
1796     UINT uiSrcCodePage,
1797     UINT uiDstCodePage,
1798     DWORD dwProperty,
1799     IMLangConvertCharset** ppMLangConvertCharset)
1800 {
1801     FIXME("\n");
1802     return E_NOTIMPL;
1803 }
1804
1805 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
1806 {
1807     fnIMultiLanguage_QueryInterface,
1808     fnIMultiLanguage_AddRef,
1809     fnIMultiLanguage_Release,
1810     fnIMultiLanguage_GetNumberOfCodePageInfo,
1811     fnIMultiLanguage_GetCodePageInfo,
1812     fnIMultiLanguage_GetFamilyCodePage,
1813     fnIMultiLanguage_EnumCodePages,
1814     fnIMultiLanguage_GetCharsetInfo,
1815     fnIMultiLanguage_IsConvertible,
1816     fnIMultiLanguage_ConvertString,
1817     fnIMultiLanguage_ConvertStringToUnicode,
1818     fnIMultiLanguage_ConvertStringFromUnicode,
1819     fnIMultiLanguage_ConvertStringReset,
1820     fnIMultiLanguage_GetRfc1766FromLcid,
1821     fnIMultiLanguage_GetLcidFromRfc1766,
1822     fnIMultiLanguage_EnumRfc1766,
1823     fnIMultiLanguage_GetRfc1766Info,
1824     fnIMultiLanguage_CreateConvertCharset,
1825 };
1826
1827
1828 /******************************************************************************/
1829
1830 static HRESULT WINAPI fnIMultiLanguage2_QueryInterface(
1831     IMultiLanguage2* iface,
1832     REFIID riid,
1833     void** ppvObject)
1834 {
1835     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1836     return MLang_QueryInterface( This, riid, ppvObject );
1837 }
1838
1839 static ULONG WINAPI fnIMultiLanguage2_AddRef( IMultiLanguage2* iface )
1840 {
1841     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1842     return MLang_AddRef( This );
1843 }
1844
1845 static ULONG WINAPI fnIMultiLanguage2_Release( IMultiLanguage2* iface )
1846 {
1847     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1848     return MLang_Release( This );
1849 }
1850
1851 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfCodePageInfo(
1852     IMultiLanguage2* iface,
1853     UINT* pcCodePage)
1854 {
1855     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1856     TRACE("%p, %p\n", This, pcCodePage);
1857
1858     if (!pcCodePage) return S_FALSE;
1859
1860     *pcCodePage = This->total_cp;
1861     return S_OK;
1862 }
1863
1864 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
1865 {
1866     CHARSETINFO csi;
1867
1868     if (TranslateCharsetInfo((DWORD *)ml_data->family_codepage, &csi, TCI_SRCCODEPAGE))
1869         mime_cp_info->bGDICharset = csi.ciCharset;
1870     else
1871         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
1872
1873     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
1874     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
1875     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
1876     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
1877                         mime_cp_info->wszDescription, sizeof(mime_cp_info->wszDescription)/sizeof(WCHAR));
1878     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
1879                         mime_cp_info->wszWebCharset, sizeof(mime_cp_info->wszWebCharset)/sizeof(WCHAR));
1880     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
1881                         mime_cp_info->wszHeaderCharset, sizeof(mime_cp_info->wszHeaderCharset)/sizeof(WCHAR));
1882     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
1883                         mime_cp_info->wszBodyCharset, sizeof(mime_cp_info->wszBodyCharset)/sizeof(WCHAR));
1884
1885     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
1886         mime_cp_info->wszFixedWidthFont, sizeof(mime_cp_info->wszFixedWidthFont)/sizeof(WCHAR));
1887     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
1888         mime_cp_info->wszProportionalFont, sizeof(mime_cp_info->wszProportionalFont)/sizeof(WCHAR));
1889
1890     TRACE("%08lx %u %u %s %s %s %s %s %s %d\n",
1891           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
1892           mime_cp_info->uiFamilyCodePage,
1893           wine_dbgstr_w(mime_cp_info->wszDescription),
1894           wine_dbgstr_w(mime_cp_info->wszWebCharset),
1895           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
1896           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
1897           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
1898           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
1899           mime_cp_info->bGDICharset);
1900 }
1901
1902 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageInfo(
1903     IMultiLanguage2* iface,
1904     UINT uiCodePage,
1905     LANGID LangId,
1906     PMIMECPINFO pCodePageInfo)
1907 {
1908     UINT i, n;
1909
1910     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1911     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
1912
1913     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1914     {
1915         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1916         {
1917             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1918             {
1919                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
1920                 return S_OK;
1921             }
1922         }
1923     }
1924
1925     return S_FALSE;
1926 }
1927
1928 static HRESULT WINAPI fnIMultiLanguage2_GetFamilyCodePage(
1929     IMultiLanguage2* iface,
1930     UINT uiCodePage,
1931     UINT* puiFamilyCodePage)
1932 {
1933     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
1934 }
1935
1936 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
1937     IMultiLanguage2* iface,
1938     DWORD grfFlags,
1939     LANGID LangId,
1940     IEnumCodePage** ppEnumCodePage)
1941 {
1942     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1943     TRACE("%p %08lx %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
1944
1945     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
1946 }
1947
1948 static HRESULT WINAPI fnIMultiLanguage2_GetCharsetInfo(
1949     IMultiLanguage2* iface,
1950     BSTR Charset,
1951     PMIMECSETINFO pCharsetInfo)
1952 {
1953     UINT i, n;
1954
1955     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
1956     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
1957
1958     if (!pCharsetInfo) return E_FAIL;
1959
1960     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1961     {
1962         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1963         {
1964             WCHAR csetW[MAX_MIMECSET_NAME];
1965
1966             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
1967             if (!lstrcmpiW(Charset, csetW))
1968             {
1969                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
1970                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
1971                 strcpyW(pCharsetInfo->wszCharset, csetW);
1972                 return S_OK;
1973             }
1974         }
1975     }
1976
1977     /* FIXME:
1978      * Since we do not support charsets like iso-2022-jp and do not have
1979      * them in our database as a primary (web_charset) encoding this loop
1980      * does an attempt to 'approximate' charset name by header_charset.
1981      */
1982     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
1983     {
1984         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1985         {
1986             WCHAR csetW[MAX_MIMECSET_NAME];
1987
1988             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
1989             if (!lstrcmpiW(Charset, csetW))
1990             {
1991                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
1992                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
1993                 strcpyW(pCharsetInfo->wszCharset, csetW);
1994                 return S_OK;
1995             }
1996         }
1997     }
1998
1999     return E_FAIL;
2000 }
2001
2002 static HRESULT WINAPI fnIMultiLanguage2_IsConvertible(
2003     IMultiLanguage2* iface,
2004     DWORD dwSrcEncoding,
2005     DWORD dwDstEncoding)
2006 {
2007     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2008 }
2009
2010 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
2011     IMultiLanguage2* iface,
2012     DWORD* pdwMode,
2013     DWORD dwSrcEncoding,
2014     DWORD dwDstEncoding,
2015     BYTE* pSrcStr,
2016     UINT* pcSrcSize,
2017     BYTE* pDstStr,
2018     UINT* pcDstSize)
2019 {
2020     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2021         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2022 }
2023
2024 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
2025     IMultiLanguage2* iface,
2026     DWORD* pdwMode,
2027     DWORD dwEncoding,
2028     CHAR* pSrcStr,
2029     UINT* pcSrcSize,
2030     WCHAR* pDstStr,
2031     UINT* pcDstSize)
2032 {
2033     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2034         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2035 }
2036
2037 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
2038     IMultiLanguage2* iface,
2039     DWORD* pdwMode,
2040     DWORD dwEncoding,
2041     WCHAR* pSrcStr,
2042     UINT* pcSrcSize,
2043     CHAR* pDstStr,
2044     UINT* pcDstSize)
2045 {
2046     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2047         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2048 }
2049
2050 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
2051     IMultiLanguage2* iface)
2052 {
2053     FIXME("\n");
2054     return E_NOTIMPL;
2055 }
2056
2057 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766FromLcid(
2058     IMultiLanguage2* iface,
2059     LCID Locale,
2060     BSTR* pbstrRfc1766)
2061 {
2062     FIXME("\n");
2063     return E_NOTIMPL;
2064 }
2065
2066 static HRESULT WINAPI fnIMultiLanguage2_GetLcidFromRfc1766(
2067     IMultiLanguage2* iface,
2068     LCID* pLocale,
2069     BSTR bstrRfc1766)
2070 {
2071     FIXME("\n");
2072     return E_NOTIMPL;
2073 }
2074
2075 static HRESULT WINAPI fnIMultiLanguage2_EnumRfc1766(
2076     IMultiLanguage2* iface,
2077     LANGID LangId,
2078     IEnumRfc1766** ppEnumRfc1766)
2079 {
2080     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage, iface);
2081     TRACE("%p %p\n", This, ppEnumRfc1766);
2082
2083     return EnumRfc1766_create(This, LangId, ppEnumRfc1766);
2084 }
2085
2086 static HRESULT WINAPI fnIMultiLanguage2_GetRfc1766Info(
2087     IMultiLanguage2* iface,
2088     LCID Locale,
2089     LANGID LangId,
2090     PRFC1766INFO pRfc1766Info)
2091 {
2092     FIXME("\n");
2093     return E_NOTIMPL;
2094 }
2095
2096 static HRESULT WINAPI fnIMultiLanguage2_CreateConvertCharset(
2097     IMultiLanguage2* iface,
2098     UINT uiSrcCodePage,
2099     UINT uiDstCodePage,
2100     DWORD dwProperty,
2101     IMLangConvertCharset** ppMLangConvertCharset)
2102 {
2103     FIXME("\n");
2104     return E_NOTIMPL;
2105 }
2106
2107 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringInIStream(
2108     IMultiLanguage2* iface,
2109     DWORD* pdwMode,
2110     DWORD dwFlag,
2111     WCHAR* lpFallBack,
2112     DWORD dwSrcEncoding,
2113     DWORD dwDstEncoding,
2114     IStream* pstmIn,
2115     IStream* pstmOut)
2116 {
2117     FIXME("\n");
2118     return E_NOTIMPL;
2119 }
2120
2121 /*
2122  * TODO: handle dwFlag and lpFallBack
2123 */
2124 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicodeEx(
2125     IMultiLanguage2* iface,
2126     DWORD* pdwMode,
2127     DWORD dwEncoding,
2128     CHAR* pSrcStr,
2129     UINT* pcSrcSize,
2130     WCHAR* pDstStr,
2131     UINT* pcDstSize,
2132     DWORD dwFlag,
2133     WCHAR* lpFallBack)
2134 {
2135     FIXME("\n");
2136     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2137         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2138 }
2139
2140 /*****************************************************************************
2141  * MultiLanguage2::ConvertStringToUnicodeEx
2142  *
2143  * Translates the multibyte string from the specified code page to Unicode.
2144  *
2145  * PARAMS
2146  *   see ConvertStringToUnicode
2147  *   dwFlag 
2148  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
2149  *              instead unconvertible characters.
2150  *
2151  * RETURNS
2152  *   S_OK     Success.
2153  *   S_FALSE  The conversion is not supported.
2154  *   E_FAIL   Some error has occurred.
2155  *
2156  * TODO: handle dwFlag and lpFallBack
2157 */
2158 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
2159     IMultiLanguage2* This,
2160     DWORD* pdwMode,
2161     DWORD dwEncoding,
2162     WCHAR* pSrcStr,
2163     UINT* pcSrcSize,
2164     CHAR* pDstStr,
2165     UINT* pcDstSize,
2166     DWORD dwFlag,
2167     WCHAR* lpFallBack)
2168 {
2169     FIXME("\n");
2170     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2171         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2172 }
2173
2174 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
2175     IMultiLanguage2* iface,
2176     DWORD dwFlag,
2177     DWORD dwPrefWinCodePage,
2178     IStream* pstmIn,
2179     DetectEncodingInfo* lpEncoding,
2180     INT* pnScores)
2181 {
2182     FIXME("\n");
2183     return E_NOTIMPL;
2184 }
2185
2186 static HRESULT WINAPI fnIMultiLanguage2_DetectInputCodepage(
2187     IMultiLanguage2* iface,
2188     DWORD dwFlag,
2189     DWORD dwPrefWinCodePage,
2190     CHAR* pSrcStr,
2191     INT* pcSrcSize,
2192     DetectEncodingInfo* lpEncoding,
2193     INT* pnScores)
2194 {
2195     FIXME("\n");
2196     return E_NOTIMPL;
2197 }
2198
2199 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePage(
2200     IMultiLanguage2* iface,
2201     UINT uiCodePage,
2202     HWND hwnd)
2203 {
2204     FIXME("%u, %p\n", uiCodePage, hwnd);
2205     return E_NOTIMPL;
2206 }
2207
2208 static HRESULT WINAPI fnIMultiLanguage2_GetCodePageDescription(
2209     IMultiLanguage2* iface,
2210     UINT uiCodePage,
2211     LCID lcid,
2212     LPWSTR lpWideCharStr,
2213     int cchWideChar)
2214 {
2215     FIXME("%u, %04lx, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
2216     return E_NOTIMPL;
2217 }
2218
2219 static HRESULT WINAPI fnIMultiLanguage2_IsCodePageInstallable(
2220     IMultiLanguage2* iface,
2221     UINT uiCodePage)
2222 {
2223     FIXME("%u\n", uiCodePage);
2224     return E_NOTIMPL;
2225 }
2226
2227 static HRESULT WINAPI fnIMultiLanguage2_SetMimeDBSource(
2228     IMultiLanguage2* iface,
2229     MIMECONTF dwSource)
2230 {
2231     FIXME("\n");
2232     return E_NOTIMPL;
2233 }
2234
2235 static HRESULT WINAPI fnIMultiLanguage2_GetNumberOfScripts(
2236     IMultiLanguage2* iface,
2237     UINT* pnScripts)
2238 {
2239     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
2240     TRACE("%p %p\n", This, pnScripts);
2241
2242     if (!pnScripts) return S_FALSE;
2243
2244     *pnScripts = This->total_scripts;
2245     return S_OK;
2246 }
2247
2248 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
2249     IMultiLanguage2* iface,
2250     DWORD dwFlags,
2251     LANGID LangId,
2252     IEnumScript** ppEnumScript)
2253 {
2254     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
2255     TRACE("%p %08lx %04x %p\n", This, dwFlags, LangId, ppEnumScript);
2256
2257     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
2258 }
2259
2260 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
2261     IMultiLanguage2* iface,
2262     UINT uiCodePage,
2263     HWND hwnd,
2264     DWORD dwfIODControl)
2265 {
2266     ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
2267     FIXME("%p %u %p %08lx: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
2268
2269     return S_FALSE;
2270 }
2271
2272 static const IMultiLanguage2Vtbl IMultiLanguage2_vtbl =
2273 {
2274     fnIMultiLanguage2_QueryInterface,
2275     fnIMultiLanguage2_AddRef,
2276     fnIMultiLanguage2_Release,
2277     fnIMultiLanguage2_GetNumberOfCodePageInfo,
2278     fnIMultiLanguage2_GetCodePageInfo,
2279     fnIMultiLanguage2_GetFamilyCodePage,
2280     fnIMultiLanguage2_EnumCodePages,
2281     fnIMultiLanguage2_GetCharsetInfo,
2282     fnIMultiLanguage2_IsConvertible,
2283     fnIMultiLanguage2_ConvertString,
2284     fnIMultiLanguage2_ConvertStringToUnicode,
2285     fnIMultiLanguage2_ConvertStringFromUnicode,
2286     fnIMultiLanguage2_ConvertStringReset,
2287     fnIMultiLanguage2_GetRfc1766FromLcid,
2288     fnIMultiLanguage2_GetLcidFromRfc1766,
2289     fnIMultiLanguage2_EnumRfc1766,
2290     fnIMultiLanguage2_GetRfc1766Info,
2291     fnIMultiLanguage2_CreateConvertCharset,
2292     fnIMultiLanguage2_ConvertStringInIStream,
2293     fnIMultiLanguage2_ConvertStringToUnicodeEx,
2294     fnIMultiLanguage2_ConvertStringFromUnicodeEx,
2295     fnIMultiLanguage2_DetectCodepageInIStream,
2296     fnIMultiLanguage2_DetectInputCodepage,
2297     fnIMultiLanguage2_ValidateCodePage,
2298     fnIMultiLanguage2_GetCodePageDescription,
2299     fnIMultiLanguage2_IsCodePageInstallable,
2300     fnIMultiLanguage2_SetMimeDBSource,
2301     fnIMultiLanguage2_GetNumberOfScripts,
2302     fnIMultiLanguage2_EnumScripts,
2303     fnIMultiLanguage2_ValidateCodePageEx,
2304 };
2305
2306 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
2307 {
2308     MLang_impl *mlang;
2309     UINT i;
2310
2311     TRACE("Creating MultiLanguage object\n");
2312
2313     if( pUnkOuter )
2314         return CLASS_E_NOAGGREGATION;
2315
2316     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
2317     mlang->vtbl_IMLangFontLink = &IMLangFontLink_vtbl;
2318     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
2319     mlang->vtbl_IMultiLanguage2 = &IMultiLanguage2_vtbl;
2320
2321     mlang->total_cp = 0;
2322     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
2323         mlang->total_cp += mlang_data[i].number_of_cp;
2324
2325     /* do not enumerate unicode flavours */
2326     mlang->total_scripts = sizeof(mlang_data)/sizeof(mlang_data[0]) - 1;
2327
2328     mlang->ref = 1;
2329     *ppObj = (LPVOID) mlang;
2330     TRACE("returning %p\n", mlang);
2331
2332     LockModule();
2333
2334     return S_OK;
2335 }
2336
2337 /******************************************************************************/
2338
2339 HRESULT WINAPI DllCanUnloadNow(void)
2340 {
2341     return dll_count == 0 ? S_OK : S_FALSE;
2342 }
2343
2344 HRESULT WINAPI GetGlobalFontLinkObject(void)
2345 {
2346     FIXME("\n");
2347     return S_FALSE;
2348 }