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