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