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