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