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