xref: /reactos/dll/win32/mlang/mlang.c (revision 8a978a17)
1 /*
2  *    MLANG Class Factory
3  *
4  * Copyright 2002 Lionel Ulmer
5  * Copyright 2003,2004 Mike McCormack
6  * Copyright 2004,2005 Dmitry Timoshkov
7  * Copyright 2009 Detlef Riekenberg
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
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 "objbase.h"
36 #include "rpcproxy.h"
37 #include "mlang.h"
38 #include "mimeole.h"
39 
40 #include "wine/debug.h"
41 #include "wine/list.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(mlang);
44 
45 #include "initguid.h"
46 
47 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj);
48 static HRESULT MLangConvertCharset_create(IUnknown *outer, void **obj);
49 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum);
50 
51 static HINSTANCE instance;
52 static DWORD MLANG_tls_index; /* to store various per thead data */
53 
54 /* FIXME:
55  * Under what circumstances HKEY_CLASSES_ROOT\MIME\Database\Codepage and
56  * HKEY_CLASSES_ROOT\MIME\Database\Charset are used?
57  */
58 
59 typedef struct
60 {
61     const char *description;
62     UINT cp;
63     DWORD flags;
64     const char *web_charset;
65     const char *header_charset;
66     const char *body_charset;
67     const WCHAR *alias;
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 (Auto-Select)",
121       50936, MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
122              MIMECONTF_MIME_LATEST,
123       "_autodetect_chs", "_autodetect_chs", "_autodetect_chs" },
124     { "Chinese Simplified (GB2312)",
125       936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
126            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID |
127            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
128            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
129       "gb2312", "gb2312", "gb2312" },
130     { "Chinese Simplified (GB2312-80)",
131       20936, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
132              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
133       "x-cp20936", "x-cp20936", "x-cp20936" },
134     { "Chinese Simplified (HZ)",
135       52936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
136              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
137              MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
138              MIMECONTF_MIME_LATEST,
139       "hz-gb-2312", "hz-gb-2312", "hz-gb-2312" },
140     { "Chinese Simplified (GB18030)",
141       54936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
142              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
143              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
144              MIMECONTF_MIME_LATEST,
145       "GB18030", "GB18030", "GB18030" },
146     { "Chinese Simplified (GBK)",
147       936, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
148            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
149            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
150            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
151       "gbk", "gbk", "gbk" }
152 };
153 static const MIME_CP_INFO chinese_traditional_cp[] =
154 {
155     { "Chinese Traditional (Auto-Select)",
156       50950, MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
157              MIMECONTF_MIME_LATEST,
158       "_autodetect_cht", "_autodetect_cht", "_autodetect_cht" },
159     { "Chinese Traditional (Big5)",
160       950, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
161            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
162            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
163            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
164       "big5", "big5", "big5" },
165     { "Chinese Traditional (CNS)",
166       20000, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
167              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
168       "x-Chinese-CNS", "x-Chinese-CNS", "x-Chinese-CNS" }
169 };
170 static const MIME_CP_INFO central_european_cp[] =
171 {
172     { "Central European (DOS)",
173       852, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
174            MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
175            MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
176       "ibm852", "ibm852", "ibm852" },
177     { "Central European (Windows)",
178       1250, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
179             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
180             MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
181             MIMECONTF_MIME_LATEST,
182       "windows-1250", "windows-1250", "windows-1250" },
183     { "Central European (Mac)",
184       10029, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
185              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
186       "x-mac-ce", "x-mac-ce", "x-mac-ce" },
187     { "Central European (ISO)",
188       28592, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
189              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
190              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
191              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
192       "iso-8859-2", "iso-8859-2", "iso-8859-2" }
193 };
194 static const MIME_CP_INFO cyrillic_cp[] =
195 {
196     { "OEM Cyrillic",
197       855, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
198            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
199       "ibm855", "ibm855", "ibm855" },
200     { "Cyrillic (DOS)",
201       866, MIMECONTF_BROWSER | MIMECONTF_IMPORT | MIMECONTF_SAVABLE_BROWSER |
202            MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
203            MIMECONTF_MIME_LATEST,
204       "cp866", "cp866", "cp866" },
205 #if 0 /* Windows has 20866 as an official code page for KOI8-R */
206     { "Cyrillic (KOI8-R)",
207       878, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
208            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
209       "koi8-r", "koi8-r", "koi8-r" },
210 #endif
211     { "Cyrillic (Windows)",
212       1251, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
213             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
214             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
215       "windows-1251", "windows-1251", "windows-1251" },
216     { "Cyrillic (Mac)",
217       10007, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
218              MIMECONTF_MIME_LATEST,
219       "x-mac-cyrillic", "x-mac-cyrillic", "x-mac-cyrillic" },
220     { "Cyrillic (KOI8-R)",
221       20866, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
222              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
223              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
224              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
225       "koi8-r", "koi8-r", "koi8-r" },
226     { "Cyrillic (KOI8-U)",
227       21866, 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       "koi8-u", "koi8-u", "koi8-u" },
232     { "Cyrillic (ISO)",
233       28595, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
234              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
235              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
236              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
237       "iso-8859-5", "iso-8859-5", "iso-8859-5" }
238 };
239 static const MIME_CP_INFO greek_cp[] =
240 {
241     { "Greek (DOS)",
242       737, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
243            MIMECONTF_MIME_LATEST,
244       "ibm737", "ibm737", "ibm737" },
245     { "Greek, Modern (DOS)",
246       869, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
247            MIMECONTF_MIME_LATEST,
248       "ibm869", "ibm869", "ibm869" },
249     { "IBM EBCDIC (Greek Modern)",
250       875, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
251            MIMECONTF_MIME_LATEST,
252       "cp875", "cp875", "cp875" },
253     { "Greek (Windows)",
254       1253, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
255             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
256             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
257       "windows-1253", "windows-1253", "windows-1253" },
258     { "Greek (Mac)",
259       10006, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
260              MIMECONTF_MIME_LATEST,
261       "x-mac-greek", "x-mac-greek", "x-mac-greek" },
262     { "Greek (ISO)",
263       28597, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
264              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
265              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
266              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
267       "iso-8859-7", "iso-8859-7", "iso-8859-7" }
268 };
269 static const MIME_CP_INFO hebrew_cp[] =
270 {
271     { "Hebrew (424)",
272       424, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
273            MIMECONTF_MIME_LATEST,
274       "ibm424", "ibm424", "ibm424" },
275     { "Hebrew (856)",
276       856, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
277            MIMECONTF_MIME_LATEST,
278       "cp856", "cp856", "cp856" },
279     { "Hebrew (DOS)",
280       862, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
281            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
282            MIMECONTF_MIME_LATEST,
283       "dos-862", "dos-862", "dos-862" },
284     { "Hebrew (Windows)",
285       1255, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
286             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
287             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
288       "windows-1255", "windows-1255", "windows-1255" },
289     { "Hebrew (ISO-Visual)",
290       28598, MIMECONTF_BROWSER | MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
291              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
292              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
293       "iso-8859-8", "iso-8859-8", "iso-8859-8" }
294 };
295 static const MIME_CP_INFO japanese_cp[] =
296 {
297     { "Japanese (Auto-Select)",
298       50932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
299              MIMECONTF_IMPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
300              MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
301       "_autodetect", "_autodetect", "_autodetect" },
302     { "Japanese (EUC)",
303       51932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
304              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
305              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
306              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
307       "euc-jp", "euc-jp", "euc-jp" },
308     { "Japanese (JIS)",
309       50220, MIMECONTF_IMPORT | MIMECONTF_MAILNEWS | MIMECONTF_EXPORT |
310              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
311              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST |
312              MIMECONTF_MIME_IE4,
313       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
314     { "Japanese (JIS 0208-1990 and 0212-1990)",
315       20932, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
316              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
317       "EUC-JP","EUC-JP","EUC-JP"},
318     { "Japanese (JIS-Allow 1 byte Kana)",
319       50221, MIMECONTF_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_SAVABLE_BROWSER |
320              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID_NLS |
321              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
322       "csISO2022JP","iso-2022-jp","iso-2022-jp"},
323     { "Japanese (JIS-Allow 1 byte Kana - SO/SI)",
324       50222, MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_VALID |
325              MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
326       "iso-2022-jp","iso-2022-jp","iso-2022-jp"},
327     { "Japanese (Mac)",
328       10001, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
329              MIMECONTF_VALID | MIMECONTF_PRIVCONVERTER | MIMECONTF_MIME_LATEST,
330       "x-mac-japanese","x-mac-japanese","x-mac-japanese"},
331     { "Japanese (Shift-JIS)",
332       932, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
333            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
334            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
335            MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
336       "shift_jis", "iso-2022-jp", "iso-2022-jp" }
337 };
338 static const MIME_CP_INFO korean_cp[] =
339 {
340     { "Korean",
341       949, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
342            MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
343            MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID_NLS |
344            MIMECONTF_MIME_LATEST,
345       "ks_c_5601-1987", "ks_c_5601-1987", "ks_c_5601-1987" }
346 };
347 static const MIME_CP_INFO thai_cp[] =
348 {
349     { "Thai (Windows)",
350       874, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_MIME_LATEST,
351       "ibm-thai", "ibm-thai", "ibm-thai" }
352 };
353 static const MIME_CP_INFO turkish_cp[] =
354 {
355     { "Turkish (DOS)",
356       857, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
357            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
358       "ibm857", "ibm857", "ibm857" },
359     { "IBM EBCDIC (Turkish Latin-5)",
360       1026, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
361             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
362       "ibm1026", "ibm1026", "ibm1026" },
363     { "Turkish (Windows)",
364       1254, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
365             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
366             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
367             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
368       "windows-1254", "windows-1254", "windows-1254" },
369     { "Turkish (Mac)",
370       10081, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
371              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
372       "x-mac-turkish", "x-mac-turkish", "x-mac-turkish" },
373     { "Latin 3 (ISO)",
374       28593, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
375              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
376              MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
377       "iso-8859-3", "iso-8859-3", "iso-8859-3" },
378     { "Turkish (ISO)",
379       28599, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
380              MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
381              MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
382              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
383       "iso-8859-9", "iso-8859-9", "iso-8859-9" }
384 };
385 static const MIME_CP_INFO vietnamese_cp[] =
386 {
387     { "Vietnamese (Windows)",
388       1258, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
389             MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
390             MIMECONTF_EXPORT | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
391             MIMECONTF_MIME_LATEST,
392       "windows-1258", "windows-1258", "windows-1258" }
393 };
394 
395 static const WCHAR asciiW[] = {'a','s','c','i','i',0};
396 
397 static const MIME_CP_INFO western_cp[] =
398 {
399     { "IBM EBCDIC (US-Canada)",
400       37, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
401           MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
402       "ibm037", "ibm037", "ibm037" },
403     { "OEM United States",
404       437, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
405            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
406       "ibm437", "ibm437", "ibm437" },
407     { "IBM EBCDIC (International)",
408       500, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
409            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
410       "ibm500", "ibm500", "ibm500" },
411     { "Western European (DOS)",
412       850, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
413            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
414       "ibm850", "ibm850", "ibm850" },
415     { "Portuguese (DOS)",
416       860, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
417            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
418       "ibm860", "ibm860", "ibm860" },
419     { "Icelandic (DOS)",
420       861, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
421            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
422       "ibm861", "ibm861", "ibm861" },
423     { "French Canadian (DOS)",
424       863, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
425            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
426       "ibm863", "ibm863", "ibm863" },
427     { "Nordic (DOS)",
428       865, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
429            MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
430       "ibm865", "ibm865", "ibm865" },
431     { "Western European (Windows)",
432       1252, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_MINIMAL |
433             MIMECONTF_IMPORT | MIMECONTF_SAVABLE_MAILNEWS |
434             MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT | MIMECONTF_VALID |
435             MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
436       "windows-1252", "windows-1252", "iso-8859-1" },
437     { "Western European (Mac)",
438       10000, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
439              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
440       "macintosh", "macintosh", "macintosh" },
441     { "Icelandic (Mac)",
442       10079, MIMECONTF_IMPORT | MIMECONTF_EXPORT | MIMECONTF_VALID |
443              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
444       "x-mac-icelandic", "x-mac-icelandic", "x-mac-icelandic" },
445     { "US-ASCII",
446       20127, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT | MIMECONTF_EXPORT |
447              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_VALID |
448              MIMECONTF_VALID_NLS | MIMECONTF_MIME_LATEST,
449       "us-ascii", "us-ascii", "us-ascii", asciiW },
450     { "Western European (ISO)",
451       28591, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
452              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
453              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
454              MIMECONTF_MIME_LATEST,
455       "iso-8859-1", "iso-8859-1", "iso-8859-1" },
456     { "Latin 9 (ISO)",
457       28605, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
458              MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
459              MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
460              MIMECONTF_MIME_LATEST,
461       "iso-8859-15", "iso-8859-15", "iso-8859-15" }
462 };
463 static const MIME_CP_INFO unicode_cp[] =
464 {
465     { "Unicode",
466       CP_UNICODE, MIMECONTF_MINIMAL | MIMECONTF_IMPORT |
467                   MIMECONTF_SAVABLE_BROWSER | MIMECONTF_EXPORT |
468                   MIMECONTF_VALID | MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 |
469                   MIMECONTF_MIME_LATEST,
470       "unicode", "unicode", "unicode" },
471     { "Unicode (UTF-7)",
472       CP_UTF7, MIMECONTF_MAILNEWS | MIMECONTF_IMPORT |
473                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_EXPORT | MIMECONTF_VALID |
474                MIMECONTF_VALID_NLS | MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
475       "utf-7", "utf-7", "utf-7" },
476     { "Unicode (UTF-8)",
477       CP_UTF8, MIMECONTF_MAILNEWS | MIMECONTF_BROWSER | MIMECONTF_IMPORT |
478                MIMECONTF_SAVABLE_MAILNEWS | MIMECONTF_SAVABLE_BROWSER |
479                MIMECONTF_EXPORT | MIMECONTF_VALID | MIMECONTF_VALID_NLS |
480                MIMECONTF_MIME_IE4 | MIMECONTF_MIME_LATEST,
481       "utf-8", "utf-8", "utf-8" }
482 };
483 
484 static const struct mlang_data
485 {
486     const char *description;
487     UINT family_codepage;
488     UINT number_of_cp;
489     const MIME_CP_INFO *mime_cp_info;
490     const char *fixed_font;
491     const char *proportional_font;
492     SCRIPT_ID sid;
493 } mlang_data[] =
494 {
495     { "Arabic", 1256, ARRAY_SIZE(arabic_cp), arabic_cp,
496       "Simplified Arabic Fixed","Simplified Arabic", sidArabic },
497     { "Baltic",  1257, ARRAY_SIZE(baltic_cp), baltic_cp,
498       "Courier New","Arial", sidAsciiLatin },
499     { "Chinese Simplified", 936, ARRAY_SIZE(chinese_simplified_cp), chinese_simplified_cp,
500       "Simsun","Simsun", sidHan },
501     { "Chinese Traditional", 950, ARRAY_SIZE(chinese_traditional_cp), chinese_traditional_cp,
502       "MingLiu","New MingLiu", sidBopomofo },
503     { "Central European", 1250, ARRAY_SIZE(central_european_cp), central_european_cp,
504       "Courier New","Arial", sidAsciiLatin },
505     { "Cyrillic", 1251, ARRAY_SIZE(cyrillic_cp), cyrillic_cp,
506       "Courier New","Arial", sidCyrillic },
507     { "Greek", 1253, ARRAY_SIZE(greek_cp), greek_cp,
508       "Courier New","Arial", sidGreek },
509     { "Hebrew", 1255, ARRAY_SIZE(hebrew_cp), hebrew_cp,
510       "Miriam Fixed","David", sidHebrew },
511     { "Japanese", 932, ARRAY_SIZE(japanese_cp), japanese_cp,
512       "MS Gothic","MS PGothic", sidKana },
513     { "Korean", 949, ARRAY_SIZE(korean_cp), korean_cp,
514       "GulimChe","Gulim", sidHangul },
515     { "Thai", 874, ARRAY_SIZE(thai_cp), thai_cp,
516       "Tahoma","Tahoma", sidThai },
517     { "Turkish", 1254, ARRAY_SIZE(turkish_cp), turkish_cp,
518       "Courier New","Arial", sidAsciiLatin },
519     { "Vietnamese", 1258, ARRAY_SIZE(vietnamese_cp), vietnamese_cp,
520       "Courier New","Arial", sidAsciiLatin },
521     { "Western European", 1252, ARRAY_SIZE(western_cp), western_cp,
522       "Courier New","Arial", sidAsciiLatin },
523     { "Unicode", CP_UNICODE, ARRAY_SIZE(unicode_cp), unicode_cp,
524       "Courier New","Arial" }
525 };
526 
527 struct font_list
528 {
529     struct list list_entry;
530     HFONT base_font;
531     HFONT font;
532     UINT charset;
533 };
534 
535 static struct list font_cache = LIST_INIT(font_cache);
536 static CRITICAL_SECTION font_cache_critical;
537 static CRITICAL_SECTION_DEBUG font_cache_critical_debug =
538 {
539     0, 0, &font_cache_critical,
540     { &font_cache_critical_debug.ProcessLocksList, &font_cache_critical_debug.ProcessLocksList },
541     0, 0, { (DWORD_PTR)(__FILE__ ": font_cache_critical") }
542 };
543 static CRITICAL_SECTION font_cache_critical = { &font_cache_critical_debug, -1, 0, 0, 0, 0 };
544 
545 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info);
546 
547 static LONG dll_count;
548 
549 /*
550  * Japanese Detection and Conversion Functions
551  */
552 
553 #define HANKATA(A)  ((A >= 161) && (A <= 223))
554 #define ISEUC(A)    ((A >= 161) && (A <= 254))
555 #define NOTEUC(A,B) (((A >= 129) && (A <= 159)) && ((B >= 64) && (B <= 160)))
556 #define SJIS1(A)    (((A >= 129) && (A <= 159)) || ((A >= 224) && (A <= 239)))
557 #define SJIS2(A)    ((A >= 64) && (A <= 252))
558 #define ISMARU(A)   ((A >= 202) && (A <= 206))
559 #define ISNIGORI(A) (((A >= 182) && (A <= 196)) || ((A >= 202) && (A <= 206)))
560 
561 static UINT DetectJapaneseCode(LPCSTR input, DWORD count)
562 {
563     UINT code = 0;
564     DWORD i = 0;
565     unsigned char c1,c2;
566 
567     while ((code == 0 || code == 51932) && i < count)
568     {
569         c1 = input[i];
570         if (c1 == 0x1b /* ESC */)
571         {
572             i++;
573             if (i >= count)
574                 return code;
575             c1 = input[i];
576             if (c1 == '$')
577             {
578                 i++;
579                 if (i >= count)
580                     return code;
581                 c1 = input[i];
582                 if (c1 =='B' || c1 == '@')
583                     code = 50220;
584             }
585             if (c1 == 'K')
586                 code = 50220;
587         }
588         else if (c1 >= 129)
589         {
590             i++;
591             if (i >= count)
592                 return code;
593             c2 = input[i];
594             if NOTEUC(c1,c2)
595                 code = 932;
596             else if (ISEUC(c1) && ISEUC(c2))
597                 code = 51932;
598             else if (((c1 == 142)) && HANKATA(c2))
599                 code = 51932;
600         }
601         i++;
602     }
603     return code;
604 }
605 
606 static inline void jis2sjis(unsigned char *p1, unsigned char *p2)
607 {
608     unsigned char c1 = *p1;
609     unsigned char c2 = *p2;
610     int row = c1 < 95 ? 112 : 176;
611     int cell = c1 % 2 ? 31 + (c2 > 95) : 126;
612 
613     *p1 = ((c1 + 1) >> 1) + row;
614     *p2 = c2 + cell;
615 }
616 
617 static inline void sjis2jis(unsigned char *p1, unsigned char *p2)
618 {
619     unsigned char c1 = *p1;
620     unsigned char c2 = *p2;
621     int shift = c2 < 159;
622     int row = c1 < 160 ? 112 : 176;
623     int cell = shift ? (31 + (c2 > 127)): 126;
624 
625     *p1 = ((c1 - row) << 1) - shift;
626     *p2 -= cell;
627 }
628 
629 static int han2zen(unsigned char *p1, unsigned char *p2)
630 {
631     BOOL maru = FALSE;
632     BOOL nigori = FALSE;
633     static const unsigned char char1[] = {129,129,129,129,129,131,131,131,131,
634         131,131,131,131,131,131,129,131,131,131,131,131,131,131,131,131,131,
635         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
636         131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
637         131,129,129 };
638     static const unsigned char char2[] = {66,117,118,65,69,146,64,66,68,70,
639         72,131,133,135,98,91,65,67,69,71,73,74,76,78,80,82,84,86,88,90,92,94,
640         96,99,101,103,105,106,107,108,109,110,113,116,119,122,125,126,128,
641         129,130,132,134,136,137,138,139,140,141,143,147,74,75};
642 
643     if (( *p2 == 222) && ((ISNIGORI(*p1) || (*p1 == 179))))
644             nigori = TRUE;
645     else if ((*p2 == 223) && (ISMARU(*p1)))
646             maru = TRUE;
647 
648     if (*p1 >= 161 && *p1 <= 223)
649     {
650         unsigned char index = *p1 - 161;
651         *p1 = char1[index];
652         *p2 = char2[index];
653     }
654 
655     if (maru || nigori)
656     {
657         if (nigori)
658         {
659             if (((*p2 >= 74) && (*p2 <= 103)) || ((*p2 >= 110) && (*p2 <= 122)))
660                 (*p2)++;
661             else if ((*p1 == 131) && (*p2 == 69))
662                 *p2 = 148;
663         }
664         else if ((maru) && ((*p2 >= 110) && (*p2 <= 122)))
665             *p2+= 2;
666 
667         return 1;
668     }
669 
670     return 0;
671 }
672 
673 
674 static UINT ConvertJIS2SJIS(LPCSTR input, DWORD count, LPSTR output)
675 {
676     DWORD i = 0;
677     int j = 0;
678     unsigned char p2,p;
679     BOOL shifted = FALSE;
680 
681     while (i < count)
682     {
683         p = input[i];
684         if (p == 0x1b /* ESC */)
685         {
686             i++;
687             if (i >= count)
688                 return 0;
689             p2 = input[i];
690             if (p2 == '$' || p2 =='(')
691                 i++;
692             if (p2 == 'K' || p2 =='$')
693                 shifted = TRUE;
694             else
695                 shifted = FALSE;
696         }
697         else
698         {
699             if (shifted)
700             {
701                 i++;
702                 if (i >= count)
703                     return 0;
704                 p2 = input[i];
705                 jis2sjis(&p,&p2);
706                 output[j++]=p;
707                 output[j++]=p2;
708             }
709             else
710             {
711                 output[j++] = p;
712             }
713         }
714         i++;
715     }
716     return j;
717 }
718 
719 static inline int exit_shift(LPSTR out, int c)
720 {
721     if (out)
722     {
723         out[c] = 0x1b;
724         out[c+1] = '(';
725         out[c+2] = 'B';
726     }
727     return 3;
728 }
729 
730 static inline int enter_shift(LPSTR out, int c)
731 {
732     if (out)
733     {
734         out[c] = 0x1b;
735         out[c+1] = '$';
736         out[c+2] = 'B';
737     }
738     return 3;
739 }
740 
741 
742 static UINT ConvertSJIS2JIS(LPCSTR input, DWORD count, LPSTR output)
743 {
744     DWORD i = 0;
745     int j = 0;
746     unsigned char p2,p;
747     BOOL shifted = FALSE;
748 
749     while (i < count)
750     {
751         p = input[i] & 0xff;
752         if (p == 10 || p == 13) /* NL and CR */
753         {
754             if (shifted)
755             {
756                 shifted = FALSE;
757                 j += exit_shift(output,j);
758             }
759             if (output)
760                 output[j++] = p;
761             else
762                 j++;
763         }
764         else
765         {
766             if (SJIS1(p))
767             {
768                 i++;
769                 if (i >= count)
770                     return 0;
771                 p2 = input[i] & 0xff;
772                 if (SJIS2(p2))
773                 {
774                     sjis2jis(&p,&p2);
775                     if (!shifted)
776                     {
777                         shifted = TRUE;
778                         j+=enter_shift(output,j);
779                     }
780                 }
781 
782                 if (output)
783                 {
784                     output[j++]=p;
785                     output[j++]=p2;
786                 }
787                 else
788                     j+=2;
789             }
790             else
791             {
792                 if (HANKATA(p))
793                 {
794                     if ((i+1) >= count)
795                         return 0;
796                     p2 = input[i+1] & 0xff;
797                     i+=han2zen(&p,&p2);
798                     sjis2jis(&p,&p2);
799                     if (!shifted)
800                     {
801                         shifted = TRUE;
802                         j+=enter_shift(output,j);
803                     }
804                     if (output)
805                     {
806                         output[j++]=p;
807                         output[j++]=p2;
808                     }
809                     else
810                         j+=2;
811                 }
812                 else
813                 {
814                     if (shifted)
815                     {
816                         shifted = FALSE;
817                         j += exit_shift(output,j);
818                     }
819                     if (output)
820                         output[j++]=p;
821                     else
822                         j++;
823                 }
824             }
825         }
826         i++;
827     }
828     if (shifted)
829         j += exit_shift(output,j);
830     return j;
831 }
832 
833 static UINT ConvertJISJapaneseToUnicode(LPCSTR input, DWORD count,
834                                         LPWSTR output, DWORD out_count)
835 {
836     CHAR *sjis_string;
837     UINT rc = 0;
838     sjis_string = HeapAlloc(GetProcessHeap(),0,count);
839     rc = ConvertJIS2SJIS(input,count,sjis_string);
840     if (rc)
841     {
842         TRACE("%s\n",debugstr_an(sjis_string,rc));
843         if (output)
844             rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
845         else
846             rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
847     }
848     HeapFree(GetProcessHeap(),0,sjis_string);
849     return rc;
850 
851 }
852 
853 static UINT ConvertUnknownJapaneseToUnicode(LPCSTR input, DWORD count,
854                                             LPWSTR output, DWORD out_count)
855 {
856     CHAR *sjis_string;
857     UINT rc = 0;
858     int code = DetectJapaneseCode(input,count);
859     TRACE("Japanese code %i\n",code);
860 
861     switch (code)
862     {
863     case 0:
864         if (output)
865             rc = MultiByteToWideChar(CP_ACP,0,input,count,output,out_count);
866         else
867             rc = MultiByteToWideChar(CP_ACP,0,input,count,0,0);
868         break;
869 
870     case 932:
871         if (output)
872             rc = MultiByteToWideChar(932,0,input,count,output,out_count);
873         else
874             rc = MultiByteToWideChar(932,0,input,count,0,0);
875         break;
876 
877     case 51932:
878         if (output)
879             rc = MultiByteToWideChar(20932,0,input,count,output,out_count);
880         else
881             rc = MultiByteToWideChar(20932,0,input,count,0,0);
882         break;
883 
884     case 50220:
885         sjis_string = HeapAlloc(GetProcessHeap(),0,count);
886         rc = ConvertJIS2SJIS(input,count,sjis_string);
887         if (rc)
888         {
889             TRACE("%s\n",debugstr_an(sjis_string,rc));
890             if (output)
891                 rc = MultiByteToWideChar(932,0,sjis_string,rc,output,out_count);
892             else
893                 rc = MultiByteToWideChar(932,0,sjis_string,rc,0,0);
894         }
895         HeapFree(GetProcessHeap(),0,sjis_string);
896         break;
897     }
898     return rc;
899 }
900 
901 static UINT ConvertJapaneseUnicodeToJIS(LPCWSTR input, DWORD count,
902                                         LPSTR output, DWORD out_count)
903 {
904     CHAR *sjis_string;
905     INT len;
906     UINT rc = 0;
907 
908     len = WideCharToMultiByte(932,0,input,count,0,0,NULL,NULL);
909     sjis_string = HeapAlloc(GetProcessHeap(),0,len);
910     WideCharToMultiByte(932,0,input,count,sjis_string,len,NULL,NULL);
911     TRACE("%s\n",debugstr_an(sjis_string,len));
912 
913     rc = ConvertSJIS2JIS(sjis_string, len, NULL);
914     if (out_count >= rc)
915     {
916         ConvertSJIS2JIS(sjis_string, len, output);
917     }
918     HeapFree(GetProcessHeap(),0,sjis_string);
919     return rc;
920 
921 }
922 
923 /*
924  * Dll lifetime tracking declaration
925  */
926 static void LockModule(void)
927 {
928     InterlockedIncrement(&dll_count);
929 }
930 
931 static void UnlockModule(void)
932 {
933     InterlockedDecrement(&dll_count);
934 }
935 
936 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
937 {
938     switch(fdwReason) {
939         case DLL_PROCESS_ATTACH:
940             instance = hInstDLL;
941             MLANG_tls_index = TlsAlloc();
942             DisableThreadLibraryCalls(hInstDLL);
943 	    break;
944 	case DLL_PROCESS_DETACH:
945             if (lpv) break;
946             TlsFree(MLANG_tls_index);
947 	    break;
948     }
949     return TRUE;
950 }
951 
952 HRESULT WINAPI ConvertINetMultiByteToUnicode(
953     LPDWORD pdwMode,
954     DWORD dwEncoding,
955     LPCSTR pSrcStr,
956     LPINT pcSrcSize,
957     LPWSTR pDstStr,
958     LPINT pcDstSize)
959 {
960     INT src_len = -1;
961 
962     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
963           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
964 
965     if (!pcDstSize)
966         return E_FAIL;
967 
968     if (!pcSrcSize)
969         pcSrcSize = &src_len;
970 
971     if (!*pcSrcSize)
972     {
973         *pcDstSize = 0;
974         return S_OK;
975     }
976 
977     /* forwarding euc-jp to EUC-JP */
978     if (dwEncoding == 51932)
979         dwEncoding = 20932;
980 
981     switch (dwEncoding)
982     {
983     case CP_UNICODE:
984         if (*pcSrcSize == -1)
985             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
986         *pcDstSize = min(*pcSrcSize, *pcDstSize);
987         *pcSrcSize *= sizeof(WCHAR);
988         if (pDstStr)
989             memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
990         break;
991 
992     case 50220:
993     case 50221:
994     case 50222:
995         *pcDstSize = ConvertJISJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
996         break;
997     case 50932:
998         *pcDstSize = ConvertUnknownJapaneseToUnicode(pSrcStr,*pcSrcSize,pDstStr,*pcDstSize);
999         break;
1000 
1001     default:
1002         if (*pcSrcSize == -1)
1003             *pcSrcSize = lstrlenA(pSrcStr);
1004 
1005         if (pDstStr)
1006             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
1007         else
1008             *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
1009         break;
1010     }
1011 
1012     if (!*pcDstSize)
1013         return E_FAIL;
1014 
1015     return S_OK;
1016 }
1017 
1018 HRESULT WINAPI ConvertINetUnicodeToMultiByte(
1019     LPDWORD pdwMode,
1020     DWORD dwEncoding,
1021     LPCWSTR pSrcStr,
1022     LPINT pcSrcSize,
1023     LPSTR pDstStr,
1024     LPINT pcDstSize)
1025 {
1026     INT destsz, size;
1027     INT src_len = -1;
1028 
1029     TRACE("%p %d %s %p %p %p\n", pdwMode, dwEncoding,
1030           debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
1031 
1032     if (!pcDstSize)
1033         return S_OK;
1034 
1035     if (!pcSrcSize)
1036         pcSrcSize = &src_len;
1037 
1038     destsz = (pDstStr) ? *pcDstSize : 0;
1039     *pcDstSize = 0;
1040 
1041     if (!pSrcStr || !*pcSrcSize)
1042         return S_OK;
1043 
1044     if (*pcSrcSize == -1)
1045         *pcSrcSize = lstrlenW(pSrcStr);
1046 
1047     /* forwarding euc-jp to EUC-JP */
1048     if (dwEncoding == 51932)
1049         dwEncoding = 20932;
1050 
1051     if (dwEncoding == CP_UNICODE)
1052     {
1053         if (*pcSrcSize == -1)
1054             *pcSrcSize = lstrlenW(pSrcStr);
1055 
1056         size = min(*pcSrcSize, destsz) * sizeof(WCHAR);
1057         if (pDstStr)
1058             memmove(pDstStr, pSrcStr, size);
1059 
1060         if (size >= destsz)
1061             goto fail;
1062     }
1063     else if (dwEncoding == 50220 || dwEncoding == 50221 || dwEncoding == 50222)
1064     {
1065         size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, NULL, 0);
1066         if (!size)
1067             goto fail;
1068 
1069         if (pDstStr)
1070         {
1071             size = ConvertJapaneseUnicodeToJIS(pSrcStr, *pcSrcSize, pDstStr,
1072                                                destsz);
1073             if (!size)
1074                 goto fail;
1075         }
1076 
1077     }
1078     else
1079     {
1080         size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1081                                    NULL, 0, NULL, NULL);
1082         if (!size)
1083             goto fail;
1084 
1085         if (pDstStr)
1086         {
1087             size = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize,
1088                                        pDstStr, destsz, NULL, NULL);
1089             if (!size)
1090                 goto fail;
1091         }
1092     }
1093 
1094     *pcDstSize = size;
1095     return S_OK;
1096 
1097 fail:
1098     *pcSrcSize = 0;
1099     *pcDstSize = 0;
1100     return E_FAIL;
1101 }
1102 
1103 HRESULT WINAPI ConvertINetString(
1104     LPDWORD pdwMode,
1105     DWORD dwSrcEncoding,
1106     DWORD dwDstEncoding,
1107     LPCSTR pSrcStr,
1108     LPINT pcSrcSize,
1109     LPSTR pDstStr,
1110     LPINT pcDstSize
1111 )
1112 {
1113     TRACE("%p %d %d %s %p %p %p\n", pdwMode, dwSrcEncoding, dwDstEncoding,
1114           debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
1115 
1116     if (dwSrcEncoding == CP_UNICODE)
1117     {
1118         INT cSrcSizeW;
1119         if (pcSrcSize && *pcSrcSize != -1)
1120         {
1121             cSrcSizeW = *pcSrcSize / sizeof(WCHAR);
1122             pcSrcSize = &cSrcSizeW;
1123         }
1124         return ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, (LPCWSTR)pSrcStr, pcSrcSize, pDstStr, pcDstSize);
1125     }
1126     else if (dwDstEncoding == CP_UNICODE)
1127     {
1128         HRESULT hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, (LPWSTR)pDstStr, pcDstSize);
1129         *pcDstSize *= sizeof(WCHAR);
1130         return hr;
1131     }
1132     else
1133     {
1134         INT cDstSizeW;
1135         LPWSTR pDstStrW;
1136         HRESULT hr;
1137 
1138         TRACE("convert %s from %d to %d\n", debugstr_a(pSrcStr), dwSrcEncoding, dwDstEncoding);
1139 
1140         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, NULL, &cDstSizeW);
1141         if (hr != S_OK)
1142             return hr;
1143 
1144         pDstStrW = HeapAlloc(GetProcessHeap(), 0, cDstSizeW * sizeof(WCHAR));
1145         hr = ConvertINetMultiByteToUnicode(pdwMode, dwSrcEncoding, pSrcStr, pcSrcSize, pDstStrW, &cDstSizeW);
1146         if (hr == S_OK)
1147             hr = ConvertINetUnicodeToMultiByte(pdwMode, dwDstEncoding, pDstStrW, &cDstSizeW, pDstStr, pcDstSize);
1148 
1149         HeapFree(GetProcessHeap(), 0, pDstStrW);
1150         return hr;
1151     }
1152 }
1153 
1154 static HRESULT GetFamilyCodePage(
1155     UINT uiCodePage,
1156     UINT* puiFamilyCodePage)
1157 {
1158     UINT i, n;
1159 
1160     TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
1161 
1162     if (!puiFamilyCodePage) return S_FALSE;
1163 
1164     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
1165     {
1166         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1167         {
1168             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
1169             {
1170                 *puiFamilyCodePage = mlang_data[i].family_codepage;
1171                 return S_OK;
1172             }
1173         }
1174     }
1175 
1176     return S_FALSE;
1177 }
1178 
1179 HRESULT WINAPI IsConvertINetStringAvailable(
1180     DWORD dwSrcEncoding,
1181     DWORD dwDstEncoding)
1182 {
1183     UINT src_family, dst_family;
1184 
1185     TRACE("%d %d\n", dwSrcEncoding, dwDstEncoding);
1186 
1187     if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
1188         GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
1189         return S_FALSE;
1190 
1191     if (src_family == dst_family) return S_OK;
1192 
1193     /* we can convert any codepage to/from unicode */
1194     if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
1195 
1196     return S_FALSE;
1197 }
1198 
1199 static inline HRESULT lcid_to_rfc1766A( LCID lcid, LPSTR rfc1766, INT len )
1200 {
1201     CHAR buffer[MAX_RFC1766_NAME];
1202     INT n = GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1203     INT i;
1204 
1205     if (n)
1206     {
1207         i = PRIMARYLANGID(lcid);
1208         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1209             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1210             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1211 
1212             buffer[n - 1] = '-';
1213             i = GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1214             if (!i)
1215                 buffer[n - 1] = '\0';
1216         }
1217         else
1218             i = 0;
1219 
1220         LCMapStringA( LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len );
1221         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1222     }
1223     return E_FAIL;
1224 }
1225 
1226 static inline HRESULT lcid_to_rfc1766W( LCID lcid, LPWSTR rfc1766, INT len )
1227 {
1228     WCHAR buffer[MAX_RFC1766_NAME];
1229     INT n = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME, buffer, MAX_RFC1766_NAME);
1230     INT i;
1231 
1232     if (n)
1233     {
1234         i = PRIMARYLANGID(lcid);
1235         if ((((i == LANG_ENGLISH) || (i == LANG_CHINESE) || (i == LANG_ARABIC)) &&
1236             (SUBLANGID(lcid) == SUBLANG_DEFAULT)) ||
1237             (SUBLANGID(lcid) > SUBLANG_DEFAULT)) {
1238 
1239             buffer[n - 1] = '-';
1240             i = GetLocaleInfoW(lcid, LOCALE_SISO3166CTRYNAME, buffer + n, MAX_RFC1766_NAME - n);
1241             if (!i)
1242                 buffer[n - 1] = '\0';
1243         }
1244         else
1245             i = 0;
1246 
1247         LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, buffer, n + i, rfc1766, len);
1248         return ((n + i) > len) ? E_INVALIDARG : S_OK;
1249     }
1250     return E_FAIL;
1251 }
1252 
1253 HRESULT WINAPI LcidToRfc1766A(
1254     LCID lcid,
1255     LPSTR pszRfc1766,
1256     INT nChar)
1257 {
1258     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1259     if (!pszRfc1766)
1260         return E_INVALIDARG;
1261 
1262     return lcid_to_rfc1766A(lcid, pszRfc1766, nChar);
1263 }
1264 
1265 HRESULT WINAPI LcidToRfc1766W(
1266     LCID lcid,
1267     LPWSTR pszRfc1766,
1268     INT nChar)
1269 {
1270     TRACE("%04x %p %u\n", lcid, pszRfc1766, nChar);
1271     if (!pszRfc1766)
1272         return E_INVALIDARG;
1273 
1274     return lcid_to_rfc1766W(lcid, pszRfc1766, nChar);
1275 }
1276 
1277 static HRESULT lcid_from_rfc1766(IEnumRfc1766 *iface, LCID *lcid, LPCWSTR rfc1766)
1278 {
1279     RFC1766INFO info;
1280     ULONG num;
1281 
1282     while (IEnumRfc1766_Next(iface, 1, &info, &num) == S_OK)
1283     {
1284         if (!wcsicmp(info.wszRfc1766, rfc1766))
1285         {
1286             *lcid = info.lcid;
1287             return S_OK;
1288         }
1289         if (lstrlenW(rfc1766) == 2 && !memcmp(info.wszRfc1766, rfc1766, 2 * sizeof(WCHAR)))
1290         {
1291             *lcid = PRIMARYLANGID(info.lcid);
1292             return S_OK;
1293         }
1294     }
1295 
1296     return E_FAIL;
1297 }
1298 
1299 HRESULT WINAPI Rfc1766ToLcidW(LCID *pLocale, LPCWSTR pszRfc1766)
1300 {
1301     IEnumRfc1766 *enumrfc1766;
1302     HRESULT hr;
1303 
1304     TRACE("(%p, %s)\n", pLocale, debugstr_w(pszRfc1766));
1305 
1306     if (!pLocale || !pszRfc1766)
1307         return E_INVALIDARG;
1308 
1309     hr = EnumRfc1766_create(0, &enumrfc1766);
1310     if (FAILED(hr))
1311         return hr;
1312 
1313     hr = lcid_from_rfc1766(enumrfc1766, pLocale, pszRfc1766);
1314     IEnumRfc1766_Release(enumrfc1766);
1315 
1316     return hr;
1317 }
1318 
1319 HRESULT WINAPI Rfc1766ToLcidA(LCID *lcid, LPCSTR rfc1766A)
1320 {
1321     WCHAR rfc1766W[MAX_RFC1766_NAME + 1];
1322 
1323     if (!rfc1766A)
1324         return E_INVALIDARG;
1325 
1326     MultiByteToWideChar(CP_ACP, 0, rfc1766A, -1, rfc1766W, MAX_RFC1766_NAME);
1327     rfc1766W[MAX_RFC1766_NAME] = 0;
1328 
1329     return Rfc1766ToLcidW(lcid, rfc1766W);
1330 }
1331 
1332 static HRESULT map_font(HDC hdc, DWORD codepages, HFONT src_font, HFONT *dst_font)
1333 {
1334     struct font_list *font_list_entry;
1335     CHARSETINFO charset_info;
1336     HFONT new_font, old_font;
1337     LOGFONTW font_attr;
1338     DWORD mask, Csb[2];
1339     BOOL found_cached;
1340     UINT charset;
1341     BOOL ret;
1342     UINT i;
1343 
1344     if (hdc == NULL || src_font == NULL) return E_FAIL;
1345 
1346     for (i = 0; i < 32; i++)
1347     {
1348         mask = (DWORD)(1 << i);
1349         if (codepages & mask)
1350         {
1351             Csb[0] = mask;
1352             Csb[1] = 0x0;
1353             ret = TranslateCharsetInfo(Csb, &charset_info, TCI_SRCFONTSIG);
1354             if (!ret) continue;
1355 
1356             /* use cached font if possible */
1357             found_cached = FALSE;
1358             EnterCriticalSection(&font_cache_critical);
1359             LIST_FOR_EACH_ENTRY(font_list_entry, &font_cache, struct font_list, list_entry)
1360             {
1361                 if (font_list_entry->charset == charset_info.ciCharset &&
1362                     font_list_entry->base_font == src_font)
1363                 {
1364                     if (dst_font != NULL)
1365                         *dst_font = font_list_entry->font;
1366                     found_cached = TRUE;
1367                 }
1368             }
1369             LeaveCriticalSection(&font_cache_critical);
1370             if (found_cached) return S_OK;
1371 
1372             GetObjectW(src_font, sizeof(font_attr), &font_attr);
1373             font_attr.lfCharSet = (BYTE)charset_info.ciCharset;
1374             font_attr.lfWidth = 0;
1375             font_attr.lfFaceName[0] = 0;
1376             new_font = CreateFontIndirectW(&font_attr);
1377             if (new_font == NULL) continue;
1378 
1379             old_font = SelectObject(hdc, new_font);
1380             charset = GetTextCharset(hdc);
1381             SelectObject(hdc, old_font);
1382             if (charset == charset_info.ciCharset)
1383             {
1384                 font_list_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_list_entry));
1385                 if (font_list_entry == NULL) return E_OUTOFMEMORY;
1386 
1387                 font_list_entry->base_font = src_font;
1388                 font_list_entry->font = new_font;
1389                 font_list_entry->charset = charset;
1390 
1391                 EnterCriticalSection(&font_cache_critical);
1392                 list_add_tail(&font_cache, &font_list_entry->list_entry);
1393                 LeaveCriticalSection(&font_cache_critical);
1394 
1395                 if (dst_font != NULL)
1396                     *dst_font = new_font;
1397                 return S_OK;
1398             }
1399         }
1400     }
1401 
1402     return E_FAIL;
1403 }
1404 
1405 static HRESULT release_font(HFONT font)
1406 {
1407     struct font_list *font_list_entry;
1408     HRESULT hr;
1409 
1410     hr = E_FAIL;
1411     EnterCriticalSection(&font_cache_critical);
1412     LIST_FOR_EACH_ENTRY(font_list_entry, &font_cache, struct font_list, list_entry)
1413     {
1414         if (font_list_entry->font == font)
1415         {
1416             list_remove(&font_list_entry->list_entry);
1417             DeleteObject(font);
1418             HeapFree(GetProcessHeap(), 0, font_list_entry);
1419             hr = S_OK;
1420             break;
1421         }
1422     }
1423     LeaveCriticalSection(&font_cache_critical);
1424 
1425     return hr;
1426 }
1427 
1428 static HRESULT clear_font_cache(void)
1429 {
1430     struct font_list *font_list_entry;
1431     struct font_list *font_list_entry2;
1432 
1433     EnterCriticalSection(&font_cache_critical);
1434     LIST_FOR_EACH_ENTRY_SAFE(font_list_entry, font_list_entry2, &font_cache, struct font_list, list_entry)
1435     {
1436         list_remove(&font_list_entry->list_entry);
1437         DeleteObject(font_list_entry->font);
1438         HeapFree(GetProcessHeap(), 0, font_list_entry);
1439     }
1440     LeaveCriticalSection(&font_cache_critical);
1441 
1442     return S_OK;
1443 }
1444 
1445 /******************************************************************************
1446  * MLANG ClassFactory
1447  */
1448 typedef struct {
1449     IClassFactory IClassFactory_iface;
1450     LONG ref;
1451     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1452 } IClassFactoryImpl;
1453 
1454 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1455 {
1456     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
1457 }
1458 
1459 struct object_creation_info
1460 {
1461     const CLSID *clsid;
1462     LPCSTR szClassName;
1463     HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
1464 };
1465 
1466 static const struct object_creation_info object_creation[] =
1467 {
1468     { &CLSID_CMultiLanguage, "CLSID_CMultiLanguage", MultiLanguage_create },
1469     { &CLSID_CMLangConvertCharset, "CLSID_CMLangConvertCharset", MLangConvertCharset_create }
1470 };
1471 
1472 static HRESULT WINAPI MLANGCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
1473 {
1474     TRACE("%s\n", debugstr_guid(riid) );
1475 
1476     if (IsEqualGUID(riid, &IID_IUnknown)
1477 	|| IsEqualGUID(riid, &IID_IClassFactory))
1478     {
1479 	IClassFactory_AddRef(iface);
1480         *ppobj = iface;
1481 	return S_OK;
1482     }
1483 
1484     *ppobj = NULL;
1485     WARN("(%p)->(%s,%p), not found\n", iface, debugstr_guid(riid), ppobj);
1486     return E_NOINTERFACE;
1487 }
1488 
1489 static ULONG WINAPI MLANGCF_AddRef(IClassFactory *iface)
1490 {
1491     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1492     return InterlockedIncrement(&This->ref);
1493 }
1494 
1495 static ULONG WINAPI MLANGCF_Release(IClassFactory *iface)
1496 {
1497     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1498     ULONG ref = InterlockedDecrement(&This->ref);
1499 
1500     if (ref == 0)
1501     {
1502         TRACE("Destroying %p\n", This);
1503 	HeapFree(GetProcessHeap(), 0, This);
1504     }
1505 
1506     return ref;
1507 }
1508 
1509 static HRESULT WINAPI MLANGCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
1510         REFIID riid, void **ppobj)
1511 {
1512     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
1513     HRESULT hres;
1514     LPUNKNOWN punk;
1515 
1516     TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
1517 
1518     *ppobj = NULL;
1519     hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
1520     if (SUCCEEDED(hres)) {
1521         hres = IUnknown_QueryInterface(punk, riid, ppobj);
1522         IUnknown_Release(punk);
1523     }
1524     TRACE("returning (%p) -> %x\n", *ppobj, hres);
1525     return hres;
1526 }
1527 
1528 static HRESULT WINAPI MLANGCF_LockServer(IClassFactory *iface, BOOL dolock)
1529 {
1530     if (dolock)
1531         LockModule();
1532     else
1533         UnlockModule();
1534 
1535     return S_OK;
1536 }
1537 
1538 static const IClassFactoryVtbl MLANGCF_Vtbl =
1539 {
1540     MLANGCF_QueryInterface,
1541     MLANGCF_AddRef,
1542     MLANGCF_Release,
1543     MLANGCF_CreateInstance,
1544     MLANGCF_LockServer
1545 };
1546 
1547 /******************************************************************
1548  *		DllGetClassObject (MLANG.@)
1549  */
1550 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1551 {
1552     unsigned int i;
1553     IClassFactoryImpl *factory;
1554 
1555     TRACE("%s %s %p\n",debugstr_guid(rclsid), debugstr_guid(iid), ppv);
1556 
1557     if ( !IsEqualGUID( &IID_IClassFactory, iid )
1558 	 && ! IsEqualGUID( &IID_IUnknown, iid) )
1559 	return E_NOINTERFACE;
1560 
1561     for (i = 0; i < ARRAY_SIZE(object_creation); i++)
1562     {
1563 	if (IsEqualGUID(object_creation[i].clsid, rclsid))
1564 	    break;
1565     }
1566 
1567     if (i == ARRAY_SIZE(object_creation))
1568     {
1569 	FIXME("%s: no class found.\n", debugstr_guid(rclsid));
1570 	return CLASS_E_CLASSNOTAVAILABLE;
1571     }
1572 
1573     TRACE("Creating a class factory for %s\n",object_creation[i].szClassName);
1574 
1575     factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
1576     if (factory == NULL) return E_OUTOFMEMORY;
1577 
1578     factory->IClassFactory_iface.lpVtbl = &MLANGCF_Vtbl;
1579     factory->ref = 1;
1580 
1581     factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
1582 
1583     *ppv = &factory->IClassFactory_iface;
1584 
1585     TRACE("(%p) <- %p\n", ppv, &factory->IClassFactory_iface);
1586 
1587     return S_OK;
1588 }
1589 
1590 
1591 /******************************************************************************/
1592 
1593 typedef struct tagMLang_impl
1594 {
1595     IMLangFontLink IMLangFontLink_iface;
1596     IMultiLanguage IMultiLanguage_iface;
1597     IMultiLanguage3 IMultiLanguage3_iface;
1598     IMLangFontLink2 IMLangFontLink2_iface;
1599     IMLangLineBreakConsole IMLangLineBreakConsole_iface;
1600     LONG ref;
1601     DWORD total_cp, total_scripts;
1602 } MLang_impl;
1603 
1604 /******************************************************************************/
1605 
1606 typedef struct tagEnumCodePage_impl
1607 {
1608     IEnumCodePage IEnumCodePage_iface;
1609     LONG ref;
1610     MIMECPINFO *cpinfo;
1611     DWORD total, pos;
1612 } EnumCodePage_impl;
1613 
1614 static inline EnumCodePage_impl *impl_from_IEnumCodePage( IEnumCodePage *iface )
1615 {
1616     return CONTAINING_RECORD( iface, EnumCodePage_impl, IEnumCodePage_iface );
1617 }
1618 
1619 static HRESULT WINAPI fnIEnumCodePage_QueryInterface(
1620         IEnumCodePage* iface,
1621         REFIID riid,
1622         void** ppvObject)
1623 {
1624     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1625 
1626     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1627 
1628     if (IsEqualGUID(riid, &IID_IUnknown)
1629 	|| IsEqualGUID(riid, &IID_IEnumCodePage))
1630     {
1631 	IEnumCodePage_AddRef(iface);
1632         TRACE("Returning IID_IEnumCodePage %p ref = %d\n", This, This->ref);
1633 	*ppvObject = &This->IEnumCodePage_iface;
1634         return S_OK;
1635     }
1636 
1637     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1638     return E_NOINTERFACE;
1639 }
1640 
1641 static ULONG WINAPI fnIEnumCodePage_AddRef(
1642         IEnumCodePage* iface)
1643 {
1644     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1645     return InterlockedIncrement(&This->ref);
1646 }
1647 
1648 static ULONG WINAPI fnIEnumCodePage_Release(
1649         IEnumCodePage* iface)
1650 {
1651     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1652     ULONG ref = InterlockedDecrement(&This->ref);
1653 
1654     TRACE("%p ref = %d\n", This, ref);
1655     if (ref == 0)
1656     {
1657         TRACE("Destroying %p\n", This);
1658         HeapFree(GetProcessHeap(), 0, This->cpinfo);
1659         HeapFree(GetProcessHeap(), 0, This);
1660     }
1661 
1662     return ref;
1663 }
1664 
1665 static HRESULT WINAPI fnIEnumCodePage_Clone(
1666         IEnumCodePage* iface,
1667         IEnumCodePage** ppEnum)
1668 {
1669     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1670     FIXME("%p %p\n", This, ppEnum);
1671     return E_NOTIMPL;
1672 }
1673 
1674 static  HRESULT WINAPI fnIEnumCodePage_Next(
1675         IEnumCodePage* iface,
1676         ULONG celt,
1677         PMIMECPINFO rgelt,
1678         ULONG* pceltFetched)
1679 {
1680     ULONG i;
1681     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1682 
1683     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1684 
1685     if (!pceltFetched) return S_FALSE;
1686     *pceltFetched = 0;
1687 
1688     if (!rgelt) return S_FALSE;
1689 
1690     if (This->pos + celt > This->total)
1691         celt = This->total - This->pos;
1692 
1693     if (!celt) return S_FALSE;
1694 
1695     memcpy(rgelt, This->cpinfo + This->pos, celt * sizeof(MIMECPINFO));
1696     *pceltFetched = celt;
1697     This->pos += celt;
1698 
1699     for (i = 0; i < celt; i++)
1700     {
1701         TRACE("#%u: %08x %u %u %s %s %s %s %s %s %d\n",
1702               i, rgelt[i].dwFlags, rgelt[i].uiCodePage,
1703               rgelt[i].uiFamilyCodePage,
1704               wine_dbgstr_w(rgelt[i].wszDescription),
1705               wine_dbgstr_w(rgelt[i].wszWebCharset),
1706               wine_dbgstr_w(rgelt[i].wszHeaderCharset),
1707               wine_dbgstr_w(rgelt[i].wszBodyCharset),
1708               wine_dbgstr_w(rgelt[i].wszFixedWidthFont),
1709               wine_dbgstr_w(rgelt[i].wszProportionalFont),
1710               rgelt[i].bGDICharset);
1711     }
1712     return S_OK;
1713 }
1714 
1715 static HRESULT WINAPI fnIEnumCodePage_Reset(
1716         IEnumCodePage* iface)
1717 {
1718     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1719 
1720     TRACE("%p\n", This);
1721 
1722     This->pos = 0;
1723     return S_OK;
1724 }
1725 
1726 static  HRESULT WINAPI fnIEnumCodePage_Skip(
1727         IEnumCodePage* iface,
1728         ULONG celt)
1729 {
1730     EnumCodePage_impl *This = impl_from_IEnumCodePage( iface );
1731 
1732     TRACE("%p %u\n", This, celt);
1733 
1734     if (celt >= This->total) return S_FALSE;
1735 
1736     This->pos += celt;
1737     return S_OK;
1738 }
1739 
1740 static const IEnumCodePageVtbl IEnumCodePage_vtbl =
1741 {
1742     fnIEnumCodePage_QueryInterface,
1743     fnIEnumCodePage_AddRef,
1744     fnIEnumCodePage_Release,
1745     fnIEnumCodePage_Clone,
1746     fnIEnumCodePage_Next,
1747     fnIEnumCodePage_Reset,
1748     fnIEnumCodePage_Skip
1749 };
1750 
1751 static HRESULT EnumCodePage_create( MLang_impl* mlang, DWORD grfFlags,
1752                      LANGID LangId, IEnumCodePage** ppEnumCodePage )
1753 {
1754     EnumCodePage_impl *ecp;
1755     MIMECPINFO *cpinfo;
1756     UINT i, n;
1757 
1758     TRACE("%p, %08x, %04x, %p\n", mlang, grfFlags, LangId, ppEnumCodePage);
1759 
1760     if (!grfFlags) /* enumerate internal data base of encodings */
1761         grfFlags = MIMECONTF_MIME_LATEST;
1762 
1763     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
1764     ecp->IEnumCodePage_iface.lpVtbl = &IEnumCodePage_vtbl;
1765     ecp->ref = 1;
1766     ecp->pos = 0;
1767     ecp->total = 0;
1768     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
1769     {
1770         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1771         {
1772             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1773                 ecp->total++;
1774         }
1775     }
1776 
1777     ecp->cpinfo = HeapAlloc(GetProcessHeap(), 0,
1778                             sizeof(MIMECPINFO) * ecp->total);
1779     cpinfo = ecp->cpinfo;
1780 
1781     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
1782     {
1783         for (n = 0; n < mlang_data[i].number_of_cp; n++)
1784         {
1785             if (mlang_data[i].mime_cp_info[n].flags & grfFlags)
1786                 fill_cp_info(&mlang_data[i], n, cpinfo++);
1787         }
1788     }
1789 
1790     TRACE("enumerated %d codepages with flags %08x\n", ecp->total, grfFlags);
1791 
1792     *ppEnumCodePage = &ecp->IEnumCodePage_iface;
1793 
1794     return S_OK;
1795 }
1796 
1797 /******************************************************************************/
1798 
1799 typedef struct tagEnumScript_impl
1800 {
1801     IEnumScript IEnumScript_iface;
1802     LONG ref;
1803     SCRIPTINFO *script_info;
1804     DWORD total, pos;
1805 } EnumScript_impl;
1806 
1807 static inline EnumScript_impl *impl_from_IEnumScript( IEnumScript *iface )
1808 {
1809     return CONTAINING_RECORD( iface, EnumScript_impl, IEnumScript_iface );
1810 }
1811 
1812 static HRESULT WINAPI fnIEnumScript_QueryInterface(
1813         IEnumScript* iface,
1814         REFIID riid,
1815         void** ppvObject)
1816 {
1817     EnumScript_impl *This = impl_from_IEnumScript( iface );
1818 
1819     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
1820 
1821     if (IsEqualGUID(riid, &IID_IUnknown)
1822         || IsEqualGUID(riid, &IID_IEnumScript))
1823     {
1824         IEnumScript_AddRef(iface);
1825         TRACE("Returning IID_IEnumScript %p ref = %d\n", This, This->ref);
1826         *ppvObject = &This->IEnumScript_iface;
1827         return S_OK;
1828     }
1829 
1830     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
1831     return E_NOINTERFACE;
1832 }
1833 
1834 static ULONG WINAPI fnIEnumScript_AddRef(
1835         IEnumScript* iface)
1836 {
1837     EnumScript_impl *This = impl_from_IEnumScript( iface );
1838     return InterlockedIncrement(&This->ref);
1839 }
1840 
1841 static ULONG WINAPI fnIEnumScript_Release(
1842         IEnumScript* iface)
1843 {
1844     EnumScript_impl *This = impl_from_IEnumScript( iface );
1845     ULONG ref = InterlockedDecrement(&This->ref);
1846 
1847     TRACE("%p ref = %d\n", This, ref);
1848     if (ref == 0)
1849     {
1850         TRACE("Destroying %p\n", This);
1851         HeapFree(GetProcessHeap(), 0, This->script_info);
1852         HeapFree(GetProcessHeap(), 0, This);
1853     }
1854 
1855     return ref;
1856 }
1857 
1858 static HRESULT WINAPI fnIEnumScript_Clone(
1859         IEnumScript* iface,
1860         IEnumScript** ppEnum)
1861 {
1862     EnumScript_impl *This = impl_from_IEnumScript( iface );
1863     FIXME("%p %p: stub!\n", This, ppEnum);
1864     return E_NOTIMPL;
1865 }
1866 
1867 static  HRESULT WINAPI fnIEnumScript_Next(
1868         IEnumScript* iface,
1869         ULONG celt,
1870         PSCRIPTINFO rgelt,
1871         ULONG* pceltFetched)
1872 {
1873     EnumScript_impl *This = impl_from_IEnumScript( iface );
1874 
1875     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
1876 
1877     if (!pceltFetched || !rgelt) return E_FAIL;
1878 
1879     *pceltFetched = 0;
1880 
1881     if (This->pos + celt > This->total)
1882         celt = This->total - This->pos;
1883 
1884     if (!celt) return S_FALSE;
1885 
1886     memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
1887     *pceltFetched = celt;
1888     This->pos += celt;
1889 
1890     return S_OK;
1891 }
1892 
1893 static HRESULT WINAPI fnIEnumScript_Reset(
1894         IEnumScript* iface)
1895 {
1896     EnumScript_impl *This = impl_from_IEnumScript( iface );
1897 
1898     TRACE("%p\n", This);
1899 
1900     This->pos = 0;
1901     return S_OK;
1902 }
1903 
1904 static  HRESULT WINAPI fnIEnumScript_Skip(
1905         IEnumScript* iface,
1906         ULONG celt)
1907 {
1908     EnumScript_impl *This = impl_from_IEnumScript( iface );
1909 
1910     TRACE("%p %u\n", This, celt);
1911 
1912     if (celt >= This->total) return S_FALSE;
1913 
1914     This->pos += celt;
1915     return S_OK;
1916 }
1917 
1918 static const IEnumScriptVtbl IEnumScript_vtbl =
1919 {
1920     fnIEnumScript_QueryInterface,
1921     fnIEnumScript_AddRef,
1922     fnIEnumScript_Release,
1923     fnIEnumScript_Clone,
1924     fnIEnumScript_Next,
1925     fnIEnumScript_Reset,
1926     fnIEnumScript_Skip
1927 };
1928 
1929 static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
1930                      LANGID LangId, IEnumScript** ppEnumScript )
1931 {
1932     EnumScript_impl *es;
1933     UINT i;
1934 
1935     TRACE("%p, %08x, %04x, %p\n", mlang, dwFlags, LangId, ppEnumScript);
1936 
1937     if (!dwFlags) /* enumerate all available scripts */
1938         dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
1939 
1940     es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
1941     es->IEnumScript_iface.lpVtbl = &IEnumScript_vtbl;
1942     es->ref = 1;
1943     es->pos = 0;
1944     /* do not enumerate unicode flavours */
1945     es->total = ARRAY_SIZE(mlang_data) - 1;
1946     es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
1947 
1948     for (i = 0; i < es->total; i++)
1949     {
1950         es->script_info[i].ScriptId = i;
1951         es->script_info[i].uiCodePage = mlang_data[i].family_codepage;
1952         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].description, -1,
1953             es->script_info[i].wszDescription, MAX_SCRIPT_NAME);
1954         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
1955             es->script_info[i].wszFixedWidthFont, MAX_MIMEFACE_NAME);
1956         MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
1957             es->script_info[i].wszProportionalFont, MAX_MIMEFACE_NAME);
1958     }
1959 
1960     TRACE("enumerated %d scripts with flags %08x\n", es->total, dwFlags);
1961 
1962     *ppEnumScript = &es->IEnumScript_iface;
1963 
1964     return S_OK;
1965 }
1966 
1967 /******************************************************************************/
1968 
1969 static inline MLang_impl *impl_from_IMLangFontLink( IMLangFontLink *iface )
1970 {
1971     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink_iface );
1972 }
1973 
1974 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
1975         IMLangFontLink* iface,
1976         REFIID riid,
1977         void** ppvObject)
1978 {
1979     MLang_impl *This = impl_from_IMLangFontLink( iface );
1980     return IMultiLanguage3_QueryInterface( &This->IMultiLanguage3_iface, riid, ppvObject );
1981 }
1982 
1983 static ULONG WINAPI fnIMLangFontLink_AddRef(
1984         IMLangFontLink* iface)
1985 {
1986     MLang_impl *This = impl_from_IMLangFontLink( iface );
1987     return IMultiLanguage3_AddRef( &This->IMultiLanguage3_iface );
1988 }
1989 
1990 static ULONG WINAPI fnIMLangFontLink_Release(
1991         IMLangFontLink* iface)
1992 {
1993     MLang_impl *This = impl_from_IMLangFontLink( iface );
1994     return IMultiLanguage3_Release( &This->IMultiLanguage3_iface );
1995 }
1996 
1997 static HRESULT WINAPI fnIMLangFontLink_GetCharCodePages(
1998         IMLangFontLink* iface,
1999         WCHAR ch_src,
2000         DWORD* codepages)
2001 {
2002     MLang_impl *This = impl_from_IMLangFontLink( iface );
2003     return IMLangFontLink2_GetCharCodePages(&This->IMLangFontLink2_iface, ch_src, codepages);
2004 }
2005 
2006 static HRESULT WINAPI fnIMLangFontLink_GetStrCodePages(
2007         IMLangFontLink* iface,
2008         const WCHAR* src,
2009         LONG src_len,
2010         DWORD priority_cp,
2011         DWORD* codepages,
2012         LONG* ret_len)
2013 {
2014     MLang_impl *This = impl_from_IMLangFontLink( iface );
2015     return IMLangFontLink2_GetStrCodePages(&This->IMLangFontLink2_iface, src, src_len, priority_cp,
2016         codepages, ret_len);
2017 }
2018 
2019 static HRESULT WINAPI fnIMLangFontLink_CodePageToCodePages(
2020         IMLangFontLink* iface,
2021         UINT codepage,
2022         DWORD* codepages)
2023 {
2024     MLang_impl *This = impl_from_IMLangFontLink( iface );
2025     return IMLangFontLink2_CodePageToCodePages(&This->IMLangFontLink2_iface, codepage, codepages);
2026 }
2027 
2028 static HRESULT WINAPI fnIMLangFontLink_CodePagesToCodePage(
2029         IMLangFontLink* iface,
2030         DWORD codepages,
2031         UINT def_codepage,
2032         UINT* codepage)
2033 {
2034     MLang_impl *This = impl_from_IMLangFontLink(iface);
2035     return IMLangFontLink2_CodePagesToCodePage(&This->IMLangFontLink2_iface, codepages,
2036         def_codepage, codepage);
2037 }
2038 
2039 static HRESULT WINAPI fnIMLangFontLink_GetFontCodePages(
2040         IMLangFontLink* iface,
2041         HDC hdc,
2042         HFONT hfont,
2043         DWORD* codepages)
2044 {
2045     MLang_impl *This = impl_from_IMLangFontLink(iface);
2046     return IMLangFontLink2_GetFontCodePages(&This->IMLangFontLink2_iface, hdc, hfont, codepages);
2047 }
2048 
2049 static HRESULT WINAPI fnIMLangFontLink_MapFont(
2050         IMLangFontLink* iface,
2051         HDC hDC,
2052         DWORD dwCodePages,
2053         HFONT hSrcFont,
2054         HFONT* phDestFont)
2055 {
2056     TRACE("(%p)->%p %08x %p %p\n",iface, hDC, dwCodePages, hSrcFont, phDestFont);
2057 
2058     return map_font(hDC, dwCodePages, hSrcFont, phDestFont);
2059 }
2060 
2061 static HRESULT WINAPI fnIMLangFontLink_ReleaseFont(
2062         IMLangFontLink* iface,
2063         HFONT hFont)
2064 {
2065     TRACE("(%p)->%p\n",iface, hFont);
2066 
2067     return release_font(hFont);
2068 }
2069 
2070 static HRESULT WINAPI fnIMLangFontLink_ResetFontMapping(
2071         IMLangFontLink* iface)
2072 {
2073     TRACE("(%p)\n",iface);
2074 
2075     return clear_font_cache();
2076 }
2077 
2078 
2079 static const IMLangFontLinkVtbl IMLangFontLink_vtbl =
2080 {
2081     fnIMLangFontLink_QueryInterface,
2082     fnIMLangFontLink_AddRef,
2083     fnIMLangFontLink_Release,
2084     fnIMLangFontLink_GetCharCodePages,
2085     fnIMLangFontLink_GetStrCodePages,
2086     fnIMLangFontLink_CodePageToCodePages,
2087     fnIMLangFontLink_CodePagesToCodePage,
2088     fnIMLangFontLink_GetFontCodePages,
2089     fnIMLangFontLink_MapFont,
2090     fnIMLangFontLink_ReleaseFont,
2091     fnIMLangFontLink_ResetFontMapping,
2092 };
2093 
2094 /******************************************************************************/
2095 
2096 static inline MLang_impl *impl_from_IMultiLanguage( IMultiLanguage *iface )
2097 {
2098     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage_iface );
2099 }
2100 
2101 static HRESULT WINAPI fnIMultiLanguage_QueryInterface(
2102     IMultiLanguage* iface,
2103     REFIID riid,
2104     void** obj)
2105 {
2106     MLang_impl *This = impl_from_IMultiLanguage( iface );
2107     return IMultiLanguage3_QueryInterface(&This->IMultiLanguage3_iface, riid, obj);
2108 }
2109 
2110 static ULONG WINAPI fnIMultiLanguage_AddRef( IMultiLanguage* iface )
2111 {
2112     MLang_impl *This = impl_from_IMultiLanguage( iface );
2113     return IMultiLanguage3_AddRef(&This->IMultiLanguage3_iface);
2114 }
2115 
2116 static ULONG WINAPI fnIMultiLanguage_Release( IMultiLanguage* iface )
2117 {
2118     MLang_impl *This = impl_from_IMultiLanguage( iface );
2119     return IMultiLanguage3_Release(&This->IMultiLanguage3_iface);
2120 }
2121 
2122 static HRESULT WINAPI fnIMultiLanguage_GetNumberOfCodePageInfo(
2123     IMultiLanguage* iface,
2124     UINT* cp)
2125 {
2126     MLang_impl *This = impl_from_IMultiLanguage( iface );
2127     TRACE("(%p, %p)\n", This, cp);
2128     return IMultiLanguage3_GetNumberOfCodePageInfo(&This->IMultiLanguage3_iface, cp);
2129 }
2130 
2131 static HRESULT WINAPI fnIMultiLanguage_GetCodePageInfo(
2132     IMultiLanguage* iface,
2133     UINT uiCodePage,
2134     PMIMECPINFO pCodePageInfo)
2135 {
2136     UINT i, n;
2137     MLang_impl *This = impl_from_IMultiLanguage( iface );
2138 
2139     TRACE("%p, %u, %p\n", This, uiCodePage, pCodePageInfo);
2140 
2141     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
2142     {
2143         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2144         {
2145             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2146             {
2147                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2148                 return S_OK;
2149             }
2150         }
2151     }
2152 
2153     return S_FALSE;
2154 }
2155 
2156 static HRESULT WINAPI fnIMultiLanguage_GetFamilyCodePage(
2157     IMultiLanguage* iface,
2158     UINT cp,
2159     UINT* family_cp)
2160 {
2161     MLang_impl *This = impl_from_IMultiLanguage( iface );
2162     return IMultiLanguage3_GetFamilyCodePage(&This->IMultiLanguage3_iface, cp, family_cp);
2163 }
2164 
2165 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
2166     IMultiLanguage* iface,
2167     DWORD grfFlags,
2168     IEnumCodePage** ppEnumCodePage)
2169 {
2170     MLang_impl *This = impl_from_IMultiLanguage( iface );
2171 
2172     TRACE("%p %08x %p\n", This, grfFlags, ppEnumCodePage);
2173 
2174     return EnumCodePage_create( This, grfFlags, 0, ppEnumCodePage );
2175 }
2176 
2177 static HRESULT WINAPI fnIMultiLanguage_GetCharsetInfo(
2178     IMultiLanguage* iface,
2179     BSTR Charset,
2180     PMIMECSETINFO pCharsetInfo)
2181 {
2182     MLang_impl *This = impl_from_IMultiLanguage( iface );
2183     return IMultiLanguage3_GetCharsetInfo( &This->IMultiLanguage3_iface, Charset, pCharsetInfo );
2184 }
2185 
2186 static HRESULT WINAPI fnIMultiLanguage_IsConvertible(
2187     IMultiLanguage* iface,
2188     DWORD src_enc,
2189     DWORD dst_enc)
2190 {
2191     MLang_impl *This = impl_from_IMultiLanguage( iface );
2192     return IMultiLanguage3_IsConvertible(&This->IMultiLanguage3_iface, src_enc, dst_enc);
2193 }
2194 
2195 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
2196     IMultiLanguage* iface,
2197     DWORD* mode,
2198     DWORD src_enc,
2199     DWORD dst_enc,
2200     BYTE* src,
2201     UINT* src_size,
2202     BYTE* dest,
2203     UINT* dest_size)
2204 {
2205     MLang_impl *This = impl_from_IMultiLanguage( iface );
2206     return IMultiLanguage3_ConvertString(&This->IMultiLanguage3_iface, mode, src_enc,
2207         dst_enc, src, src_size, dest, dest_size);
2208 }
2209 
2210 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
2211     IMultiLanguage* iface,
2212     DWORD* mode,
2213     DWORD src_enc,
2214     CHAR* src,
2215     UINT* src_size,
2216     WCHAR* dest,
2217     UINT* dest_size)
2218 {
2219     MLang_impl *This = impl_from_IMultiLanguage( iface );
2220     return IMultiLanguage3_ConvertStringToUnicode(&This->IMultiLanguage3_iface,
2221         mode, src_enc, src, src_size, dest, dest_size);
2222 }
2223 
2224 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
2225     IMultiLanguage* iface,
2226     DWORD* mode,
2227     DWORD encoding,
2228     WCHAR* src,
2229     UINT* src_size,
2230     CHAR* dest,
2231     UINT* dest_size)
2232 {
2233     MLang_impl *This = impl_from_IMultiLanguage(iface);
2234     return IMultiLanguage3_ConvertStringFromUnicode(&This->IMultiLanguage3_iface,
2235         mode, encoding, src, src_size, dest, dest_size);
2236 }
2237 
2238 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
2239     IMultiLanguage* iface)
2240 {
2241     MLang_impl *This = impl_from_IMultiLanguage( iface );
2242     return IMultiLanguage3_ConvertStringReset(&This->IMultiLanguage3_iface);
2243 }
2244 
2245 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766FromLcid(
2246     IMultiLanguage* iface,
2247     LCID lcid,
2248     BSTR* pbstrRfc1766)
2249 {
2250     MLang_impl *This = impl_from_IMultiLanguage(iface);
2251     return IMultiLanguage3_GetRfc1766FromLcid(&This->IMultiLanguage3_iface, lcid, pbstrRfc1766);
2252 }
2253 
2254 static HRESULT WINAPI fnIMultiLanguage_GetLcidFromRfc1766(
2255     IMultiLanguage* iface,
2256     LCID* locale,
2257     BSTR rfc1766)
2258 {
2259     MLang_impl *This = impl_from_IMultiLanguage(iface);
2260     return IMultiLanguage3_GetLcidFromRfc1766(&This->IMultiLanguage3_iface, locale, rfc1766);
2261 }
2262 
2263 /******************************************************************************/
2264 
2265 typedef struct tagEnumRfc1766_impl
2266 {
2267     IEnumRfc1766 IEnumRfc1766_iface;
2268     LONG ref;
2269     RFC1766INFO *info;
2270     DWORD total, pos;
2271 } EnumRfc1766_impl;
2272 
2273 static inline EnumRfc1766_impl *impl_from_IEnumRfc1766( IEnumRfc1766 *iface )
2274 {
2275     return CONTAINING_RECORD( iface, EnumRfc1766_impl, IEnumRfc1766_iface );
2276 }
2277 
2278 static HRESULT WINAPI fnIEnumRfc1766_QueryInterface(
2279         IEnumRfc1766 *iface,
2280         REFIID riid,
2281         void** ppvObject)
2282 {
2283     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2284 
2285     TRACE("%p -> %s\n", This, debugstr_guid(riid) );
2286 
2287     if (IsEqualGUID(riid, &IID_IUnknown)
2288         || IsEqualGUID(riid, &IID_IEnumRfc1766))
2289     {
2290         IEnumRfc1766_AddRef(iface);
2291         TRACE("Returning IID_IEnumRfc1766 %p ref = %d\n", This, This->ref);
2292         *ppvObject = &This->IEnumRfc1766_iface;
2293         return S_OK;
2294     }
2295 
2296     WARN("(%p) -> (%s,%p), not found\n",This,debugstr_guid(riid),ppvObject);
2297     return E_NOINTERFACE;
2298 }
2299 
2300 static ULONG WINAPI fnIEnumRfc1766_AddRef(
2301         IEnumRfc1766 *iface)
2302 {
2303     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2304     return InterlockedIncrement(&This->ref);
2305 }
2306 
2307 static ULONG WINAPI fnIEnumRfc1766_Release(
2308         IEnumRfc1766 *iface)
2309 {
2310     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2311     ULONG ref = InterlockedDecrement(&This->ref);
2312 
2313     TRACE("%p ref = %d\n", This, ref);
2314     if (ref == 0)
2315     {
2316         TRACE("Destroying %p\n", This);
2317         HeapFree(GetProcessHeap(), 0, This->info);
2318         HeapFree(GetProcessHeap(), 0, This);
2319     }
2320     return ref;
2321 }
2322 
2323 static HRESULT WINAPI fnIEnumRfc1766_Clone(
2324         IEnumRfc1766 *iface,
2325         IEnumRfc1766 **ppEnum)
2326 {
2327     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2328 
2329     FIXME("%p %p\n", This, ppEnum);
2330     return E_NOTIMPL;
2331 }
2332 
2333 static  HRESULT WINAPI fnIEnumRfc1766_Next(
2334         IEnumRfc1766 *iface,
2335         ULONG celt,
2336         PRFC1766INFO rgelt,
2337         ULONG *pceltFetched)
2338 {
2339     ULONG i;
2340     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2341 
2342     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched);
2343 
2344     if (!pceltFetched) return S_FALSE;
2345     *pceltFetched = 0;
2346 
2347     if (!rgelt) return S_FALSE;
2348 
2349     if (This->pos + celt > This->total)
2350         celt = This->total - This->pos;
2351 
2352     if (!celt) return S_FALSE;
2353 
2354     memcpy(rgelt, This->info + This->pos, celt * sizeof(RFC1766INFO));
2355     *pceltFetched = celt;
2356     This->pos += celt;
2357 
2358     for (i = 0; i < celt; i++)
2359     {
2360         TRACE("#%u: %08x %s %s\n",
2361               i, rgelt[i].lcid,
2362               wine_dbgstr_w(rgelt[i].wszRfc1766),
2363               wine_dbgstr_w(rgelt[i].wszLocaleName));
2364     }
2365     return S_OK;
2366 }
2367 
2368 static HRESULT WINAPI fnIEnumRfc1766_Reset(
2369         IEnumRfc1766 *iface)
2370 {
2371     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2372 
2373     TRACE("%p\n", This);
2374 
2375     This->pos = 0;
2376     return S_OK;
2377 }
2378 
2379 static  HRESULT WINAPI fnIEnumRfc1766_Skip(
2380         IEnumRfc1766 *iface,
2381         ULONG celt)
2382 {
2383     EnumRfc1766_impl *This = impl_from_IEnumRfc1766( iface );
2384 
2385     TRACE("%p %u\n", This, celt);
2386 
2387     if (celt >= This->total) return S_FALSE;
2388 
2389     This->pos += celt;
2390     return S_OK;
2391 }
2392 
2393 static const IEnumRfc1766Vtbl IEnumRfc1766_vtbl =
2394 {
2395     fnIEnumRfc1766_QueryInterface,
2396     fnIEnumRfc1766_AddRef,
2397     fnIEnumRfc1766_Release,
2398     fnIEnumRfc1766_Clone,
2399     fnIEnumRfc1766_Next,
2400     fnIEnumRfc1766_Reset,
2401     fnIEnumRfc1766_Skip
2402 };
2403 
2404 struct enum_locales_data
2405 {
2406     RFC1766INFO *info;
2407     DWORD total, allocated;
2408 };
2409 
2410 static BOOL CALLBACK enum_locales_proc(LPWSTR locale)
2411 {
2412     WCHAR *end;
2413     struct enum_locales_data *data = TlsGetValue(MLANG_tls_index);
2414     RFC1766INFO *info;
2415 
2416     TRACE("%s\n", debugstr_w(locale));
2417 
2418     if (data->total >= data->allocated)
2419     {
2420         data->allocated += 32;
2421         data->info = HeapReAlloc(GetProcessHeap(), 0, data->info, data->allocated * sizeof(RFC1766INFO));
2422         if (!data->info) return FALSE;
2423     }
2424 
2425     info = &data->info[data->total];
2426 
2427     info->lcid = wcstol(locale, &end, 16);
2428     if (*end) /* invalid number */
2429         return FALSE;
2430 
2431     info->wszRfc1766[0] = 0;
2432     lcid_to_rfc1766W( info->lcid, info->wszRfc1766, MAX_RFC1766_NAME );
2433 
2434     info->wszLocaleName[0] = 0;
2435     GetLocaleInfoW(info->lcid, LOCALE_SLANGUAGE, info->wszLocaleName, MAX_LOCALE_NAME);
2436     TRACE("ISO639: %s SLANGUAGE: %s\n", wine_dbgstr_w(info->wszRfc1766), wine_dbgstr_w(info->wszLocaleName));
2437 
2438     data->total++;
2439 
2440     return TRUE;
2441 }
2442 
2443 static HRESULT EnumRfc1766_create(LANGID LangId, IEnumRfc1766 **ppEnum)
2444 {
2445     EnumRfc1766_impl *rfc;
2446     struct enum_locales_data data;
2447 
2448     TRACE("%04x, %p\n", LangId, ppEnum);
2449 
2450     rfc = HeapAlloc( GetProcessHeap(), 0, sizeof(EnumRfc1766_impl) );
2451     rfc->IEnumRfc1766_iface.lpVtbl = &IEnumRfc1766_vtbl;
2452     rfc->ref = 1;
2453     rfc->pos = 0;
2454     rfc->total = 0;
2455 
2456     data.total = 0;
2457     data.allocated = 160;
2458     data.info = HeapAlloc(GetProcessHeap(), 0, data.allocated * sizeof(RFC1766INFO));
2459     if (!data.info)
2460     {
2461         HeapFree(GetProcessHeap(), 0, rfc);
2462         return E_OUTOFMEMORY;
2463     }
2464 
2465     TlsSetValue(MLANG_tls_index, &data);
2466     EnumSystemLocalesW(enum_locales_proc, 0/*LOCALE_SUPPORTED*/);
2467     TlsSetValue(MLANG_tls_index, NULL);
2468 
2469     TRACE("enumerated %d rfc1766 structures\n", data.total);
2470 
2471     if (!data.total)
2472     {
2473         HeapFree(GetProcessHeap(), 0, data.info);
2474         HeapFree(GetProcessHeap(), 0, rfc);
2475         return E_FAIL;
2476     }
2477 
2478     rfc->info = data.info;
2479     rfc->total = data.total;
2480 
2481     *ppEnum = &rfc->IEnumRfc1766_iface;
2482     return S_OK;
2483 }
2484 
2485 static HRESULT WINAPI fnIMultiLanguage_EnumRfc1766(
2486     IMultiLanguage *iface,
2487     IEnumRfc1766 **ppEnumRfc1766)
2488 {
2489     MLang_impl *This = impl_from_IMultiLanguage( iface );
2490 
2491     TRACE("%p %p\n", This, ppEnumRfc1766);
2492 
2493     return EnumRfc1766_create(0, ppEnumRfc1766);
2494 }
2495 
2496 /******************************************************************************/
2497 
2498 static HRESULT WINAPI fnIMultiLanguage_GetRfc1766Info(
2499     IMultiLanguage* iface,
2500     LCID Locale,
2501     PRFC1766INFO pRfc1766Info)
2502 {
2503     LCTYPE type = LOCALE_SLANGUAGE;
2504 
2505     TRACE("(%p, 0x%04x, %p)\n", iface, Locale, pRfc1766Info);
2506 
2507     if (!pRfc1766Info)
2508         return E_INVALIDARG;
2509 
2510     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2511         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2512         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2513 
2514         if (!SUBLANGID(Locale))
2515             type = LOCALE_SENGLANGUAGE; /* suppress country */
2516     }
2517     else
2518     {
2519         if (!SUBLANGID(Locale)) {
2520             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2521             return E_FAIL;
2522         }
2523     }
2524 
2525     pRfc1766Info->lcid = Locale;
2526     pRfc1766Info->wszRfc1766[0] = 0;
2527     pRfc1766Info->wszLocaleName[0] = 0;
2528 
2529     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2530         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2531             return S_OK;
2532 
2533     /* Locale not supported */
2534     return E_INVALIDARG;
2535 }
2536 
2537 static HRESULT WINAPI fnIMultiLanguage_CreateConvertCharset(
2538     IMultiLanguage* iface,
2539     UINT src_cp,
2540     UINT dst_cp,
2541     DWORD prop,
2542     IMLangConvertCharset** convert_charset)
2543 {
2544     MLang_impl *This = impl_from_IMultiLanguage(iface);
2545     return IMultiLanguage3_CreateConvertCharset(&This->IMultiLanguage3_iface, src_cp, dst_cp, prop, convert_charset);
2546 }
2547 
2548 static const IMultiLanguageVtbl IMultiLanguage_vtbl =
2549 {
2550     fnIMultiLanguage_QueryInterface,
2551     fnIMultiLanguage_AddRef,
2552     fnIMultiLanguage_Release,
2553     fnIMultiLanguage_GetNumberOfCodePageInfo,
2554     fnIMultiLanguage_GetCodePageInfo,
2555     fnIMultiLanguage_GetFamilyCodePage,
2556     fnIMultiLanguage_EnumCodePages,
2557     fnIMultiLanguage_GetCharsetInfo,
2558     fnIMultiLanguage_IsConvertible,
2559     fnIMultiLanguage_ConvertString,
2560     fnIMultiLanguage_ConvertStringToUnicode,
2561     fnIMultiLanguage_ConvertStringFromUnicode,
2562     fnIMultiLanguage_ConvertStringReset,
2563     fnIMultiLanguage_GetRfc1766FromLcid,
2564     fnIMultiLanguage_GetLcidFromRfc1766,
2565     fnIMultiLanguage_EnumRfc1766,
2566     fnIMultiLanguage_GetRfc1766Info,
2567     fnIMultiLanguage_CreateConvertCharset,
2568 };
2569 
2570 
2571 /******************************************************************************/
2572 
2573 static inline MLang_impl *impl_from_IMultiLanguage3( IMultiLanguage3 *iface )
2574 {
2575     return CONTAINING_RECORD( iface, MLang_impl, IMultiLanguage3_iface );
2576 }
2577 
2578 static HRESULT WINAPI fnIMultiLanguage3_QueryInterface(
2579     IMultiLanguage3* iface,
2580     REFIID riid,
2581     void** obj)
2582 {
2583     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2584 
2585     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2586 
2587     if (IsEqualGUID(riid, &IID_IUnknown) ||
2588         IsEqualGUID(riid, &IID_IMultiLanguage))
2589     {
2590         *obj = &This->IMultiLanguage_iface;
2591     }
2592     else if (IsEqualGUID(riid, &IID_IMLangCodePages) ||
2593              IsEqualGUID(riid, &IID_IMLangFontLink))
2594     {
2595         *obj = &This->IMLangFontLink_iface;
2596     }
2597     else if (IsEqualGUID(riid, &IID_IMLangFontLink2))
2598     {
2599         *obj = &This->IMLangFontLink2_iface;
2600     }
2601     else if (IsEqualGUID(riid, &IID_IMultiLanguage2) ||
2602              IsEqualGUID(riid, &IID_IMultiLanguage3))
2603     {
2604         *obj = &This->IMultiLanguage3_iface;
2605     }
2606     else if (IsEqualGUID(riid, &IID_IMLangLineBreakConsole))
2607     {
2608         *obj = &This->IMLangLineBreakConsole_iface;
2609     }
2610     else
2611     {
2612         WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), obj);
2613         *obj = NULL;
2614         return E_NOINTERFACE;
2615     }
2616 
2617     IMultiLanguage3_AddRef(iface);
2618     return S_OK;
2619 }
2620 
2621 static ULONG WINAPI fnIMultiLanguage3_AddRef( IMultiLanguage3* iface )
2622 {
2623     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2624     return InterlockedIncrement(&This->ref);
2625 }
2626 
2627 static ULONG WINAPI fnIMultiLanguage3_Release( IMultiLanguage3* iface )
2628 {
2629     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2630     ULONG ref = InterlockedDecrement(&This->ref);
2631 
2632     TRACE("(%p)->(%d)\n", This, ref);
2633     if (ref == 0)
2634     {
2635         HeapFree(GetProcessHeap(), 0, This);
2636         UnlockModule();
2637     }
2638 
2639     return ref;
2640 }
2641 
2642 static HRESULT WINAPI fnIMultiLanguage3_GetNumberOfCodePageInfo(
2643     IMultiLanguage3* iface,
2644     UINT* pcCodePage)
2645 {
2646     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2647 
2648     TRACE("%p, %p\n", This, pcCodePage);
2649 
2650     if (!pcCodePage) return E_INVALIDARG;
2651 
2652     *pcCodePage = This->total_cp;
2653     return S_OK;
2654 }
2655 
2656 static void fill_cp_info(const struct mlang_data *ml_data, UINT index, MIMECPINFO *mime_cp_info)
2657 {
2658     CHARSETINFO csi;
2659 
2660     if (TranslateCharsetInfo((DWORD*)(DWORD_PTR)ml_data->family_codepage, &csi,
2661                              TCI_SRCCODEPAGE))
2662         mime_cp_info->bGDICharset = csi.ciCharset;
2663     else
2664         mime_cp_info->bGDICharset = DEFAULT_CHARSET;
2665 
2666     mime_cp_info->dwFlags = ml_data->mime_cp_info[index].flags;
2667     mime_cp_info->uiCodePage = ml_data->mime_cp_info[index].cp;
2668     mime_cp_info->uiFamilyCodePage = ml_data->family_codepage;
2669     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].description, -1,
2670                         mime_cp_info->wszDescription, ARRAY_SIZE(mime_cp_info->wszDescription));
2671     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].web_charset, -1,
2672                         mime_cp_info->wszWebCharset, ARRAY_SIZE(mime_cp_info->wszWebCharset));
2673     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].header_charset, -1,
2674                         mime_cp_info->wszHeaderCharset, ARRAY_SIZE(mime_cp_info->wszHeaderCharset));
2675     MultiByteToWideChar(CP_ACP, 0, ml_data->mime_cp_info[index].body_charset, -1,
2676                         mime_cp_info->wszBodyCharset, ARRAY_SIZE(mime_cp_info->wszBodyCharset));
2677 
2678     MultiByteToWideChar(CP_ACP, 0, ml_data->fixed_font, -1,
2679         mime_cp_info->wszFixedWidthFont, ARRAY_SIZE(mime_cp_info->wszFixedWidthFont));
2680     MultiByteToWideChar(CP_ACP, 0, ml_data->proportional_font, -1,
2681         mime_cp_info->wszProportionalFont, ARRAY_SIZE(mime_cp_info->wszProportionalFont));
2682 
2683     TRACE("%08x %u %u %s %s %s %s %s %s %d\n",
2684           mime_cp_info->dwFlags, mime_cp_info->uiCodePage,
2685           mime_cp_info->uiFamilyCodePage,
2686           wine_dbgstr_w(mime_cp_info->wszDescription),
2687           wine_dbgstr_w(mime_cp_info->wszWebCharset),
2688           wine_dbgstr_w(mime_cp_info->wszHeaderCharset),
2689           wine_dbgstr_w(mime_cp_info->wszBodyCharset),
2690           wine_dbgstr_w(mime_cp_info->wszFixedWidthFont),
2691           wine_dbgstr_w(mime_cp_info->wszProportionalFont),
2692           mime_cp_info->bGDICharset);
2693 }
2694 
2695 static HRESULT WINAPI fnIMultiLanguage3_GetCodePageInfo(
2696     IMultiLanguage3* iface,
2697     UINT uiCodePage,
2698     LANGID LangId,
2699     PMIMECPINFO pCodePageInfo)
2700 {
2701     UINT i, n;
2702     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2703 
2704     TRACE("%p, %u, %04x, %p\n", This, uiCodePage, LangId, pCodePageInfo);
2705 
2706     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
2707     {
2708         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2709         {
2710             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
2711             {
2712                 fill_cp_info(&mlang_data[i], n, pCodePageInfo);
2713                 return S_OK;
2714             }
2715         }
2716     }
2717 
2718     return S_FALSE;
2719 }
2720 
2721 static HRESULT WINAPI fnIMultiLanguage3_GetFamilyCodePage(
2722     IMultiLanguage3* iface,
2723     UINT uiCodePage,
2724     UINT* puiFamilyCodePage)
2725 {
2726     return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
2727 }
2728 
2729 static HRESULT WINAPI fnIMultiLanguage3_EnumCodePages(
2730     IMultiLanguage3* iface,
2731     DWORD grfFlags,
2732     LANGID LangId,
2733     IEnumCodePage** ppEnumCodePage)
2734 {
2735     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2736 
2737     TRACE("%p %08x %04x %p\n", This, grfFlags, LangId, ppEnumCodePage);
2738 
2739     return EnumCodePage_create( This, grfFlags, LangId, ppEnumCodePage );
2740 }
2741 
2742 static HRESULT WINAPI fnIMultiLanguage3_GetCharsetInfo(
2743     IMultiLanguage3* iface,
2744     BSTR Charset,
2745     PMIMECSETINFO pCharsetInfo)
2746 {
2747     UINT i, n;
2748     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2749 
2750     TRACE("%p %s %p\n", This, debugstr_w(Charset), pCharsetInfo);
2751 
2752     if (!pCharsetInfo) return E_FAIL;
2753 
2754     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
2755     {
2756         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2757         {
2758             WCHAR csetW[MAX_MIMECSET_NAME];
2759 
2760             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].web_charset, -1, csetW, MAX_MIMECSET_NAME);
2761             if (!lstrcmpiW(Charset, csetW))
2762             {
2763                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2764                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2765                 lstrcpyW(pCharsetInfo->wszCharset, csetW);
2766                 return S_OK;
2767             }
2768             if (mlang_data[i].mime_cp_info[n].alias && !lstrcmpiW(Charset, mlang_data[i].mime_cp_info[n].alias))
2769             {
2770                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2771                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2772                 lstrcpyW(pCharsetInfo->wszCharset, mlang_data[i].mime_cp_info[n].alias);
2773                 return S_OK;
2774             }
2775         }
2776     }
2777 
2778     /* FIXME:
2779      * Since we do not support charsets like iso-2022-jp and do not have
2780      * them in our database as a primary (web_charset) encoding this loop
2781      * does an attempt to 'approximate' charset name by header_charset.
2782      */
2783     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
2784     {
2785         for (n = 0; n < mlang_data[i].number_of_cp; n++)
2786         {
2787             WCHAR csetW[MAX_MIMECSET_NAME];
2788 
2789             MultiByteToWideChar(CP_ACP, 0, mlang_data[i].mime_cp_info[n].header_charset, -1, csetW, MAX_MIMECSET_NAME);
2790             if (!lstrcmpiW(Charset, csetW))
2791             {
2792                 pCharsetInfo->uiCodePage = mlang_data[i].family_codepage;
2793                 pCharsetInfo->uiInternetEncoding = mlang_data[i].mime_cp_info[n].cp;
2794                 lstrcpyW(pCharsetInfo->wszCharset, csetW);
2795                 return S_OK;
2796             }
2797         }
2798     }
2799 
2800     return E_FAIL;
2801 }
2802 
2803 static HRESULT WINAPI fnIMultiLanguage3_IsConvertible(
2804     IMultiLanguage3* iface,
2805     DWORD dwSrcEncoding,
2806     DWORD dwDstEncoding)
2807 {
2808     return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
2809 }
2810 
2811 static HRESULT WINAPI fnIMultiLanguage3_ConvertString(
2812     IMultiLanguage3* iface,
2813     DWORD* pdwMode,
2814     DWORD dwSrcEncoding,
2815     DWORD dwDstEncoding,
2816     BYTE* pSrcStr,
2817     UINT* pcSrcSize,
2818     BYTE* pDstStr,
2819     UINT* pcDstSize)
2820 {
2821     return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
2822         (LPCSTR)pSrcStr, (LPINT)pcSrcSize, (LPSTR)pDstStr, (LPINT)pcDstSize);
2823 }
2824 
2825 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringToUnicode(
2826     IMultiLanguage3* iface,
2827     DWORD* pdwMode,
2828     DWORD dwEncoding,
2829     CHAR* pSrcStr,
2830     UINT* pcSrcSize,
2831     WCHAR* pDstStr,
2832     UINT* pcDstSize)
2833 {
2834     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
2835         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2836 }
2837 
2838 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringFromUnicode(
2839     IMultiLanguage3* iface,
2840     DWORD* pdwMode,
2841     DWORD dwEncoding,
2842     WCHAR* pSrcStr,
2843     UINT* pcSrcSize,
2844     CHAR* pDstStr,
2845     UINT* pcDstSize)
2846 {
2847     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
2848         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
2849 }
2850 
2851 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringReset(
2852     IMultiLanguage3* iface)
2853 {
2854     FIXME("\n");
2855     return E_NOTIMPL;
2856 }
2857 
2858 static HRESULT WINAPI fnIMultiLanguage3_GetRfc1766FromLcid(
2859     IMultiLanguage3* iface,
2860     LCID lcid,
2861     BSTR* pbstrRfc1766)
2862 {
2863     WCHAR buf[MAX_RFC1766_NAME];
2864 
2865     TRACE("%p %04x %p\n", iface, lcid, pbstrRfc1766);
2866     if (!pbstrRfc1766)
2867         return E_INVALIDARG;
2868 
2869     if (!lcid_to_rfc1766W( lcid, buf, MAX_RFC1766_NAME ))
2870     {
2871         *pbstrRfc1766 = SysAllocString( buf );
2872         return S_OK;
2873     }
2874     return E_FAIL;
2875 }
2876 
2877 static HRESULT WINAPI fnIMultiLanguage3_GetLcidFromRfc1766(
2878     IMultiLanguage3* iface,
2879     LCID* pLocale,
2880     BSTR bstrRfc1766)
2881 {
2882     HRESULT hr;
2883     IEnumRfc1766 *rfc1766;
2884 
2885     TRACE("%p %p %s\n", iface, pLocale, debugstr_w(bstrRfc1766));
2886 
2887     if (!pLocale || !bstrRfc1766)
2888         return E_INVALIDARG;
2889 
2890     hr = IMultiLanguage3_EnumRfc1766(iface, 0, &rfc1766);
2891     if (FAILED(hr))
2892         return hr;
2893 
2894     hr = lcid_from_rfc1766(rfc1766, pLocale, bstrRfc1766);
2895 
2896     IEnumRfc1766_Release(rfc1766);
2897     return hr;
2898 }
2899 
2900 static HRESULT WINAPI fnIMultiLanguage3_EnumRfc1766(
2901     IMultiLanguage3* iface,
2902     LANGID LangId,
2903     IEnumRfc1766** ppEnumRfc1766)
2904 {
2905     MLang_impl *This = impl_from_IMultiLanguage3( iface );
2906 
2907     TRACE("%p %p\n", This, ppEnumRfc1766);
2908 
2909     return EnumRfc1766_create(LangId, ppEnumRfc1766);
2910 }
2911 
2912 static HRESULT WINAPI fnIMultiLanguage3_GetRfc1766Info(
2913     IMultiLanguage3* iface,
2914     LCID Locale,
2915     LANGID LangId,
2916     PRFC1766INFO pRfc1766Info)
2917 {
2918     static LANGID last_lang = -1;
2919     LCTYPE type = LOCALE_SLANGUAGE;
2920 
2921     TRACE("(%p, 0x%04x, 0x%04x, %p)\n", iface, Locale, LangId, pRfc1766Info);
2922 
2923     if (!pRfc1766Info)
2924         return E_INVALIDARG;
2925 
2926     if ((PRIMARYLANGID(Locale) == LANG_ENGLISH) ||
2927         (PRIMARYLANGID(Locale) == LANG_CHINESE) ||
2928         (PRIMARYLANGID(Locale) == LANG_ARABIC)) {
2929 
2930         if (!SUBLANGID(Locale))
2931             type = LOCALE_SENGLANGUAGE; /* suppress country */
2932     }
2933     else
2934     {
2935         if (!SUBLANGID(Locale)) {
2936             TRACE("SUBLANGID missing in 0x%04x\n", Locale);
2937             return E_FAIL;
2938         }
2939     }
2940 
2941     pRfc1766Info->lcid = Locale;
2942     pRfc1766Info->wszRfc1766[0] = 0;
2943     pRfc1766Info->wszLocaleName[0] = 0;
2944 
2945     if ((PRIMARYLANGID(LangId) != LANG_ENGLISH) &&
2946         (last_lang != LangId)) {
2947         FIXME("Only English names supported (requested: 0x%04x)\n", LangId);
2948         last_lang = LangId;
2949     }
2950 
2951     if ((!lcid_to_rfc1766W(Locale, pRfc1766Info->wszRfc1766, MAX_RFC1766_NAME)) &&
2952         (GetLocaleInfoW(Locale, type, pRfc1766Info->wszLocaleName, MAX_LOCALE_NAME) > 0))
2953             return S_OK;
2954 
2955     /* Locale not supported */
2956     return E_INVALIDARG;
2957 }
2958 
2959 static HRESULT WINAPI fnIMultiLanguage3_CreateConvertCharset(
2960     IMultiLanguage3* iface,
2961     UINT src_cp,
2962     UINT dst_cp,
2963     DWORD prop,
2964     IMLangConvertCharset** convert_charset)
2965 {
2966     HRESULT hr;
2967 
2968     TRACE("(%u %u 0x%08x %p)\n", src_cp, dst_cp, prop, convert_charset);
2969 
2970     hr = MLangConvertCharset_create(NULL, (void**)convert_charset);
2971     if (FAILED(hr)) return hr;
2972 
2973     return IMLangConvertCharset_Initialize(*convert_charset, src_cp, dst_cp, prop);
2974 }
2975 
2976 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringInIStream(
2977     IMultiLanguage3* iface,
2978     DWORD* pdwMode,
2979     DWORD dwFlag,
2980     WCHAR* lpFallBack,
2981     DWORD dwSrcEncoding,
2982     DWORD dwDstEncoding,
2983     IStream* pstmIn,
2984     IStream* pstmOut)
2985 {
2986     char *src, *dst = NULL;
2987     INT srclen, dstlen;
2988     STATSTG stat;
2989     HRESULT hr;
2990 
2991     TRACE("%p %0x8 %s %u %u %p %p\n",
2992           pdwMode, dwFlag, debugstr_w(lpFallBack), dwSrcEncoding, dwDstEncoding, pstmIn, pstmOut);
2993 
2994     FIXME("dwFlag and lpFallBack not handled\n");
2995 
2996     hr = IStream_Stat(pstmIn, &stat, STATFLAG_NONAME);
2997     if (FAILED(hr)) return hr;
2998 
2999     if (stat.cbSize.QuadPart > MAXLONG) return E_INVALIDARG;
3000     if (!(src = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart))) return E_OUTOFMEMORY;
3001 
3002     hr = IStream_Read(pstmIn, src, stat.cbSize.QuadPart, (ULONG *)&srclen);
3003     if (FAILED(hr)) goto exit;
3004 
3005     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, NULL, &dstlen);
3006     if (FAILED(hr)) goto exit;
3007 
3008     if (!(dst = HeapAlloc(GetProcessHeap(), 0, dstlen)))
3009     {
3010         hr = E_OUTOFMEMORY;
3011         goto exit;
3012     }
3013     hr = ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding, src, &srclen, dst, &dstlen);
3014     if (FAILED(hr)) goto exit;
3015 
3016     hr = IStream_Write(pstmOut, dst, dstlen, NULL);
3017 
3018 exit:
3019     HeapFree(GetProcessHeap(), 0, src);
3020     HeapFree(GetProcessHeap(), 0, dst);
3021     return hr;
3022 }
3023 
3024 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringToUnicodeEx(
3025     IMultiLanguage3* iface,
3026     DWORD* pdwMode,
3027     DWORD dwEncoding,
3028     CHAR* pSrcStr,
3029     UINT* pcSrcSize,
3030     WCHAR* pDstStr,
3031     UINT* pcDstSize,
3032     DWORD dwFlag,
3033     WCHAR* lpFallBack)
3034 {
3035     if (dwFlag || lpFallBack)
3036         FIXME("Ignoring dwFlag (0x%x/%d) and lpFallBack (%p)\n",
3037                 dwFlag, dwFlag, lpFallBack);
3038 
3039     return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
3040         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3041 }
3042 
3043 /*****************************************************************************
3044  * MultiLanguage2::ConvertStringToUnicodeEx
3045  *
3046  * Translates the multibyte string from the specified code page to Unicode.
3047  *
3048  * PARAMS
3049  *   see ConvertStringToUnicode
3050  *   dwFlag
3051  *   lpFallBack if dwFlag contains MLCONVCHARF_USEDEFCHAR, lpFallBack string used
3052  *              instead unconvertible characters.
3053  *
3054  * RETURNS
3055  *   S_OK     Success.
3056  *   S_FALSE  The conversion is not supported.
3057  *   E_FAIL   Some error has occurred.
3058  *
3059  * TODO: handle dwFlag and lpFallBack
3060 */
3061 static HRESULT WINAPI fnIMultiLanguage3_ConvertStringFromUnicodeEx(
3062     IMultiLanguage3* This,
3063     DWORD* pdwMode,
3064     DWORD dwEncoding,
3065     WCHAR* pSrcStr,
3066     UINT* pcSrcSize,
3067     CHAR* pDstStr,
3068     UINT* pcDstSize,
3069     DWORD dwFlag,
3070     WCHAR* lpFallBack)
3071 {
3072     FIXME("\n");
3073     return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
3074         pSrcStr, (LPINT)pcSrcSize, pDstStr, (LPINT)pcDstSize);
3075 }
3076 
3077 static HRESULT WINAPI fnIMultiLanguage3_DetectCodepageInIStream(
3078     IMultiLanguage3* iface,
3079     DWORD dwFlag,
3080     DWORD dwPrefWinCodePage,
3081     IStream* pstmIn,
3082     DetectEncodingInfo* lpEncoding,
3083     INT* pnScores)
3084 {
3085     FIXME("\n");
3086     return E_NOTIMPL;
3087 }
3088 
3089 static HRESULT WINAPI fnIMultiLanguage3_DetectInputCodepage(
3090     IMultiLanguage3* iface,
3091     DWORD dwFlag,
3092     DWORD dwPrefWinCodePage,
3093     CHAR* pSrcStr,
3094     INT* pcSrcSize,
3095     DetectEncodingInfo* lpEncoding,
3096     INT* pnScores)
3097 {
3098     FIXME("\n");
3099     return E_NOTIMPL;
3100 }
3101 
3102 static HRESULT WINAPI fnIMultiLanguage3_ValidateCodePage(
3103     IMultiLanguage3* iface,
3104     UINT uiCodePage,
3105     HWND hwnd)
3106 {
3107     return IMultiLanguage3_ValidateCodePageEx(iface,uiCodePage,hwnd,0);
3108 }
3109 
3110 static HRESULT WINAPI fnIMultiLanguage3_GetCodePageDescription(
3111     IMultiLanguage3* iface,
3112     UINT uiCodePage,
3113     LCID lcid,
3114     LPWSTR lpWideCharStr,
3115     int cchWideChar)
3116 {
3117     /* Find first instance */
3118     unsigned int i,n;
3119 
3120     TRACE ("%u, %04x, %p, %d\n", uiCodePage, lcid, lpWideCharStr, cchWideChar);
3121     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
3122     {
3123         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3124         {
3125             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3126             {
3127                 MultiByteToWideChar(CP_ACP, 0,
3128                                     mlang_data[i].mime_cp_info[n].description,
3129                                     -1, lpWideCharStr, cchWideChar);
3130                 return S_OK;
3131             }
3132         }
3133     }
3134 
3135     return S_FALSE;
3136 }
3137 
3138 static HRESULT WINAPI fnIMultiLanguage3_IsCodePageInstallable(
3139     IMultiLanguage3* iface,
3140     UINT uiCodePage)
3141 {
3142     TRACE("%u\n", uiCodePage);
3143 
3144     /* FIXME: the installable set is usually larger than the set of valid codepages */
3145     return IMultiLanguage3_ValidateCodePageEx(iface, uiCodePage, NULL, CPIOD_PEEK);
3146 }
3147 
3148 static HRESULT WINAPI fnIMultiLanguage3_SetMimeDBSource(
3149     IMultiLanguage3* iface,
3150     MIMECONTF dwSource)
3151 {
3152     FIXME("0x%08x\n", dwSource);
3153     return S_OK;
3154 }
3155 
3156 static HRESULT WINAPI fnIMultiLanguage3_GetNumberOfScripts(
3157     IMultiLanguage3* iface,
3158     UINT* pnScripts)
3159 {
3160     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3161 
3162     TRACE("%p %p\n", This, pnScripts);
3163 
3164     if (!pnScripts) return S_FALSE;
3165 
3166     *pnScripts = This->total_scripts;
3167     return S_OK;
3168 }
3169 
3170 static HRESULT WINAPI fnIMultiLanguage3_EnumScripts(
3171     IMultiLanguage3* iface,
3172     DWORD dwFlags,
3173     LANGID LangId,
3174     IEnumScript** ppEnumScript)
3175 {
3176     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3177 
3178     TRACE("%p %08x %04x %p\n", This, dwFlags, LangId, ppEnumScript);
3179 
3180     return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
3181 }
3182 
3183 static HRESULT WINAPI fnIMultiLanguage3_ValidateCodePageEx(
3184     IMultiLanguage3* iface,
3185     UINT uiCodePage,
3186     HWND hwnd,
3187     DWORD dwfIODControl)
3188 {
3189     unsigned int i;
3190     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3191 
3192     TRACE("%p %u %p %08x\n", This, uiCodePage, hwnd, dwfIODControl);
3193 
3194     /* quick check for kernel32 supported code pages */
3195     if (IsValidCodePage(uiCodePage))
3196         return S_OK;
3197 
3198     /* check for mlang supported code pages */
3199     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
3200     {
3201         UINT n;
3202         for (n = 0; n < mlang_data[i].number_of_cp; n++)
3203         {
3204             if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
3205                 return S_OK;
3206         }
3207     }
3208 
3209     if (dwfIODControl != CPIOD_PEEK)
3210         FIXME("Request to install codepage language pack not handled\n");
3211 
3212     return S_FALSE;
3213 }
3214 
3215 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePage(
3216     IMultiLanguage3 *iface,
3217     DWORD dwFlags,
3218     LPCWSTR lpWideCharStr,
3219     UINT cchWideChar,
3220     UINT *puiPreferredCodePages,
3221     UINT nPreferredCodePages,
3222     UINT *puiDetectedCodePages,
3223     UINT *pnDetectedCodePages,
3224     WCHAR *lpSpecialChar)
3225 {
3226     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3227 
3228     FIXME("(%p)->(%08x %s %p %u %p %p(%u) %s)\n", This, dwFlags, debugstr_w(lpWideCharStr),
3229           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3230           pnDetectedCodePages, pnDetectedCodePages ? *pnDetectedCodePages : 0,
3231           debugstr_w(lpSpecialChar));
3232 
3233     if (!puiDetectedCodePages || !pnDetectedCodePages || !*pnDetectedCodePages)
3234         return E_INVALIDARG;
3235 
3236     puiDetectedCodePages[0] = CP_UTF8;
3237     *pnDetectedCodePages = 1;
3238     return S_OK;
3239 }
3240 
3241 static HRESULT WINAPI fnIMultiLanguage3_DetectOutboundCodePageInIStream(
3242     IMultiLanguage3 *iface,
3243     DWORD dwFlags,
3244     IStream *pStrIn,
3245     UINT *puiPreferredCodePages,
3246     UINT nPreferredCodePages,
3247     UINT *puiDetectedCodePages,
3248     UINT *pnDetectedCodePages,
3249     WCHAR *lpSpecialChar)
3250 {
3251     MLang_impl *This = impl_from_IMultiLanguage3( iface );
3252 
3253     FIXME("(%p)->(%08x %p %p %u %p %p(%u) %s)\n", This, dwFlags, pStrIn,
3254           puiPreferredCodePages, nPreferredCodePages, puiDetectedCodePages,
3255           pnDetectedCodePages, pnDetectedCodePages ? *pnDetectedCodePages : 0,
3256           debugstr_w(lpSpecialChar));
3257 
3258     if (!puiDetectedCodePages || !pnDetectedCodePages || !*pnDetectedCodePages)
3259         return E_INVALIDARG;
3260 
3261     puiDetectedCodePages[0] = CP_UTF8;
3262     *pnDetectedCodePages = 1;
3263     return S_OK;
3264 }
3265 
3266 static const IMultiLanguage3Vtbl IMultiLanguage3_vtbl =
3267 {
3268     fnIMultiLanguage3_QueryInterface,
3269     fnIMultiLanguage3_AddRef,
3270     fnIMultiLanguage3_Release,
3271     fnIMultiLanguage3_GetNumberOfCodePageInfo,
3272     fnIMultiLanguage3_GetCodePageInfo,
3273     fnIMultiLanguage3_GetFamilyCodePage,
3274     fnIMultiLanguage3_EnumCodePages,
3275     fnIMultiLanguage3_GetCharsetInfo,
3276     fnIMultiLanguage3_IsConvertible,
3277     fnIMultiLanguage3_ConvertString,
3278     fnIMultiLanguage3_ConvertStringToUnicode,
3279     fnIMultiLanguage3_ConvertStringFromUnicode,
3280     fnIMultiLanguage3_ConvertStringReset,
3281     fnIMultiLanguage3_GetRfc1766FromLcid,
3282     fnIMultiLanguage3_GetLcidFromRfc1766,
3283     fnIMultiLanguage3_EnumRfc1766,
3284     fnIMultiLanguage3_GetRfc1766Info,
3285     fnIMultiLanguage3_CreateConvertCharset,
3286     fnIMultiLanguage3_ConvertStringInIStream,
3287     fnIMultiLanguage3_ConvertStringToUnicodeEx,
3288     fnIMultiLanguage3_ConvertStringFromUnicodeEx,
3289     fnIMultiLanguage3_DetectCodepageInIStream,
3290     fnIMultiLanguage3_DetectInputCodepage,
3291     fnIMultiLanguage3_ValidateCodePage,
3292     fnIMultiLanguage3_GetCodePageDescription,
3293     fnIMultiLanguage3_IsCodePageInstallable,
3294     fnIMultiLanguage3_SetMimeDBSource,
3295     fnIMultiLanguage3_GetNumberOfScripts,
3296     fnIMultiLanguage3_EnumScripts,
3297     fnIMultiLanguage3_ValidateCodePageEx,
3298     fnIMultiLanguage3_DetectOutboundCodePage,
3299     fnIMultiLanguage3_DetectOutboundCodePageInIStream
3300 };
3301 
3302 /******************************************************************************/
3303 
3304 static inline MLang_impl *impl_from_IMLangFontLink2( IMLangFontLink2 *iface )
3305 {
3306     return CONTAINING_RECORD( iface, MLang_impl, IMLangFontLink2_iface );
3307 }
3308 
3309 static HRESULT WINAPI fnIMLangFontLink2_QueryInterface(
3310     IMLangFontLink2 * iface,
3311     REFIID riid,
3312     void** ppvObject)
3313 {
3314     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3315     return IMultiLanguage3_QueryInterface( &This->IMultiLanguage3_iface, riid, ppvObject );
3316 }
3317 
3318 static ULONG WINAPI fnIMLangFontLink2_AddRef( IMLangFontLink2* iface )
3319 {
3320     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3321     return IMultiLanguage3_AddRef( &This->IMultiLanguage3_iface );
3322 }
3323 
3324 static ULONG WINAPI fnIMLangFontLink2_Release( IMLangFontLink2* iface )
3325 {
3326     MLang_impl *This = impl_from_IMLangFontLink2( iface );
3327     return IMultiLanguage3_Release( &This->IMultiLanguage3_iface );
3328 }
3329 
3330 static HRESULT WINAPI fnIMLangFontLink2_GetCharCodePages( IMLangFontLink2* iface,
3331         WCHAR ch_src, DWORD *ret_codepages)
3332 {
3333     MLang_impl *This = impl_from_IMLangFontLink2(iface);
3334     unsigned int i;
3335 
3336     TRACE("(%p)->(%s %p)\n", This, debugstr_wn(&ch_src, 1), ret_codepages);
3337 
3338     *ret_codepages = 0;
3339 
3340     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
3341     {
3342         BOOL used_dc;
3343         CHAR buf;
3344 
3345         WideCharToMultiByte(mlang_data[i].family_codepage, WC_NO_BEST_FIT_CHARS,
3346             &ch_src, 1, &buf, 1, NULL, &used_dc);
3347 
3348         /* If default char is not used, current codepage include the given symbol */
3349         if (!used_dc)
3350         {
3351             DWORD codepages;
3352 
3353             IMLangFontLink2_CodePageToCodePages(iface,
3354                 mlang_data[i].family_codepage, &codepages);
3355             *ret_codepages |= codepages;
3356         }
3357     }
3358     return S_OK;
3359 }
3360 
3361 static HRESULT WINAPI fnIMLangFontLink2_GetStrCodePages( IMLangFontLink2* iface,
3362         const WCHAR *src, LONG src_len, DWORD priority_cp,
3363         DWORD *codepages, LONG *ret_len)
3364 {
3365     MLang_impl *This = impl_from_IMLangFontLink2(iface);
3366     LONG i;
3367     DWORD cps = 0;
3368 
3369     TRACE("(%p)->(%s:%d %x %p %p)\n", This, debugstr_wn(src, src_len), src_len, priority_cp,
3370         codepages, ret_len);
3371 
3372     if (codepages) *codepages = 0;
3373     if (ret_len) *ret_len = 0;
3374 
3375     if (!src || !src_len || src_len < 0)
3376         return E_INVALIDARG;
3377 
3378     for (i = 0; i < src_len; i++)
3379     {
3380         DWORD cp;
3381         HRESULT ret;
3382 
3383         ret = IMLangFontLink2_GetCharCodePages(iface, src[i], &cp);
3384         if (ret != S_OK) return E_FAIL;
3385 
3386         if (!cps) cps = cp;
3387         else cps &= cp;
3388 
3389         /* FIXME: not tested */
3390         if (priority_cp & cps) break;
3391     }
3392 
3393     if (codepages) *codepages = cps;
3394     if (ret_len) *ret_len = min( i + 1, src_len );
3395     return S_OK;
3396 }
3397 
3398 static HRESULT WINAPI fnIMLangFontLink2_CodePageToCodePages(IMLangFontLink2* iface,
3399         UINT codepage,
3400         DWORD *codepages)
3401 {
3402     MLang_impl *This = impl_from_IMLangFontLink2(iface);
3403     CHARSETINFO cs;
3404     BOOL rc;
3405 
3406     TRACE("(%p)->(%u %p)\n", This, codepage, codepages);
3407 
3408     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)codepage, &cs, TCI_SRCCODEPAGE);
3409     if (rc)
3410     {
3411         *codepages = cs.fs.fsCsb[0];
3412         TRACE("resulting codepages 0x%x\n", *codepages);
3413         return S_OK;
3414     }
3415 
3416     TRACE("codepage not found\n");
3417     *codepages = 0;
3418     return E_FAIL;
3419 }
3420 
3421 static HRESULT WINAPI fnIMLangFontLink2_CodePagesToCodePage(IMLangFontLink2* iface,
3422         DWORD codepages, UINT def_codepage, UINT *codepage)
3423 {
3424     MLang_impl *This = impl_from_IMLangFontLink2(iface);
3425     DWORD mask = 0;
3426     CHARSETINFO cs;
3427     BOOL rc;
3428     UINT i;
3429 
3430     TRACE("(%p)->(0x%x %u %p)\n", This, codepages, def_codepage, codepage);
3431 
3432     *codepage = 0;
3433 
3434     rc = TranslateCharsetInfo((DWORD*)(DWORD_PTR)def_codepage, &cs, TCI_SRCCODEPAGE);
3435     if (rc && (codepages & cs.fs.fsCsb[0]))
3436     {
3437         TRACE("Found Default Codepage\n");
3438         *codepage = def_codepage;
3439         return S_OK;
3440     }
3441 
3442     for (i = 0; i < 32; i++)
3443     {
3444         mask = 1 << i;
3445         if (codepages & mask)
3446         {
3447             DWORD Csb[2];
3448             Csb[0] = mask;
3449             Csb[1] = 0x0;
3450             rc = TranslateCharsetInfo(Csb, &cs, TCI_SRCFONTSIG);
3451             if (!rc)
3452                 continue;
3453 
3454             TRACE("Falling back to least significant found CodePage %u\n",
3455                     cs.ciACP);
3456             *codepage = cs.ciACP;
3457             return S_OK;
3458         }
3459     }
3460 
3461     TRACE("no codepage found\n");
3462     return E_FAIL;
3463 }
3464 
3465 static HRESULT WINAPI fnIMLangFontLink2_GetFontCodePages(IMLangFontLink2 *iface,
3466         HDC hdc, HFONT hfont, DWORD *codepages)
3467 {
3468     MLang_impl *This = impl_from_IMLangFontLink2(iface);
3469     FONTSIGNATURE fontsig;
3470     HFONT old_font;
3471 
3472     TRACE("(%p)->(%p %p %p)\n", This, hdc, hfont, codepages);
3473 
3474     old_font = SelectObject(hdc, hfont);
3475     GetTextCharsetInfo(hdc, &fontsig, 0);
3476     SelectObject(hdc, old_font);
3477 
3478     *codepages = fontsig.fsCsb[0];
3479     TRACE("ret 0x%x\n", fontsig.fsCsb[0]);
3480 
3481     return S_OK;
3482 }
3483 
3484 static HRESULT WINAPI fnIMLangFontLink2_ReleaseFont(IMLangFontLink2* This,
3485         HFONT hFont)
3486 {
3487     TRACE("(%p)->%p\n",This, hFont);
3488 
3489     return release_font(hFont);
3490 }
3491 
3492 static HRESULT WINAPI fnIMLangFontLink2_ResetFontMapping(IMLangFontLink2* This)
3493 {
3494     TRACE("(%p)\n",This);
3495 
3496     return clear_font_cache();
3497 }
3498 
3499 static HRESULT WINAPI fnIMLangFontLink2_MapFont(IMLangFontLink2* This,
3500         HDC hDC, DWORD dwCodePages, WCHAR chSrc, HFONT *pFont)
3501 {
3502     HFONT old_font;
3503 
3504     TRACE("(%p)->%p %08x %04x %p\n",This, hDC, dwCodePages, chSrc, pFont);
3505 
3506     if (!hDC) return E_FAIL;
3507 
3508     if (dwCodePages != 0)
3509     {
3510         old_font = GetCurrentObject(hDC, OBJ_FONT);
3511         return map_font(hDC, dwCodePages, old_font, pFont);
3512     }
3513     else
3514     {
3515         if (pFont == NULL) return E_INVALIDARG;
3516         FIXME("the situation where dwCodepages is set to zero is not implemented\n");
3517         return E_FAIL;
3518     }
3519 }
3520 
3521 static HRESULT WINAPI fnIMLangFontLink2_GetFontUnicodeRanges(IMLangFontLink2* This,
3522         HDC hDC, UINT *puiRanges, UNICODERANGE *pUranges)
3523 {
3524     DWORD size;
3525     GLYPHSET *gs;
3526 
3527     TRACE("(%p)->%p %p %p\n", This, hDC, puiRanges, pUranges);
3528 
3529     if (!puiRanges) return E_INVALIDARG;
3530     if (!(size = GetFontUnicodeRanges(hDC, NULL))) return E_FAIL;
3531     if (!(gs = HeapAlloc(GetProcessHeap(), 0, size))) return E_OUTOFMEMORY;
3532 
3533     GetFontUnicodeRanges(hDC, gs);
3534     *puiRanges = gs->cRanges;
3535     if (pUranges)
3536     {
3537         UINT i;
3538         for (i = 0; i < gs->cRanges; i++)
3539         {
3540             if (i >= *puiRanges) break;
3541             pUranges[i].wcFrom = gs->ranges[i].wcLow;
3542             pUranges[i].wcTo   = gs->ranges[i].wcLow + gs->ranges[i].cGlyphs;
3543         }
3544         *puiRanges = i;
3545     }
3546     HeapFree(GetProcessHeap(), 0, gs);
3547     return S_OK;
3548 }
3549 
3550 static HRESULT WINAPI fnIMLangFontLink2_GetScriptFontInfo(IMLangFontLink2* This,
3551         SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts,
3552         SCRIPTFONTINFO *pScriptFont)
3553 {
3554     UINT i, j;
3555 
3556     TRACE("(%p)->%u %x %p %p\n", This, sid, dwFlags, puiFonts, pScriptFont);
3557 
3558     if (!dwFlags) dwFlags = SCRIPTCONTF_PROPORTIONAL_FONT;
3559 
3560     for (i = 0, j = 0; i < ARRAY_SIZE(mlang_data); i++)
3561     {
3562         if (sid == mlang_data[i].sid)
3563         {
3564             if (pScriptFont)
3565             {
3566                 if (j >= *puiFonts) break;
3567 
3568                 pScriptFont[j].scripts = (SCRIPT_IDS)1 << mlang_data[i].sid;
3569                 if (dwFlags == SCRIPTCONTF_FIXED_FONT)
3570                 {
3571                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].fixed_font, -1,
3572                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3573                 }
3574                 else if (dwFlags == SCRIPTCONTF_PROPORTIONAL_FONT)
3575                 {
3576                     MultiByteToWideChar(CP_ACP, 0, mlang_data[i].proportional_font, -1,
3577                         pScriptFont[j].wszFont, MAX_MIMEFACE_NAME);
3578                 }
3579             }
3580             j++;
3581         }
3582     }
3583     *puiFonts = j;
3584     return S_OK;
3585 }
3586 
3587 static HRESULT WINAPI fnIMLangFontLink2_CodePageToScriptID(IMLangFontLink2* This,
3588         UINT uiCodePage, SCRIPT_ID *pSid)
3589 {
3590     UINT i;
3591 
3592     TRACE("(%p)->%i %p\n", This, uiCodePage, pSid);
3593 
3594     if (uiCodePage == CP_UNICODE) return E_FAIL;
3595 
3596     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
3597     {
3598         if (uiCodePage == mlang_data[i].family_codepage)
3599         {
3600             if (pSid) *pSid = mlang_data[i].sid;
3601             return S_OK;
3602         }
3603     }
3604     return E_FAIL;
3605 }
3606 
3607 static const IMLangFontLink2Vtbl IMLangFontLink2_vtbl =
3608 {
3609     fnIMLangFontLink2_QueryInterface,
3610     fnIMLangFontLink2_AddRef,
3611     fnIMLangFontLink2_Release,
3612     fnIMLangFontLink2_GetCharCodePages,
3613     fnIMLangFontLink2_GetStrCodePages,
3614     fnIMLangFontLink2_CodePageToCodePages,
3615     fnIMLangFontLink2_CodePagesToCodePage,
3616     fnIMLangFontLink2_GetFontCodePages,
3617     fnIMLangFontLink2_ReleaseFont,
3618     fnIMLangFontLink2_ResetFontMapping,
3619     fnIMLangFontLink2_MapFont,
3620     fnIMLangFontLink2_GetFontUnicodeRanges,
3621     fnIMLangFontLink2_GetScriptFontInfo,
3622     fnIMLangFontLink2_CodePageToScriptID
3623 };
3624 
3625 /******************************************************************************/
3626 
3627 static inline MLang_impl *impl_from_IMLangLineBreakConsole( IMLangLineBreakConsole *iface )
3628 {
3629     return CONTAINING_RECORD( iface, MLang_impl, IMLangLineBreakConsole_iface );
3630 }
3631 
3632 static HRESULT WINAPI fnIMLangLineBreakConsole_QueryInterface(
3633     IMLangLineBreakConsole* iface,
3634     REFIID riid,
3635     void** ppvObject)
3636 {
3637     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3638     return IMultiLanguage3_QueryInterface( &This->IMultiLanguage3_iface, riid, ppvObject );
3639 }
3640 
3641 static ULONG WINAPI fnIMLangLineBreakConsole_AddRef(
3642     IMLangLineBreakConsole* iface )
3643 {
3644     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3645     return IMultiLanguage3_AddRef( &This->IMultiLanguage3_iface );
3646 }
3647 
3648 static ULONG WINAPI fnIMLangLineBreakConsole_Release(
3649     IMLangLineBreakConsole* iface )
3650 {
3651     MLang_impl *This = impl_from_IMLangLineBreakConsole( iface );
3652     return IMultiLanguage3_Release( &This->IMultiLanguage3_iface );
3653 }
3654 
3655 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineML(
3656     IMLangLineBreakConsole* iface,
3657     IMLangString* pSrcMLStr,
3658     LONG lSrcPos,
3659     LONG lSrcLen,
3660     LONG cMinColumns,
3661     LONG cMaxColumns,
3662     LONG* plLineLen,
3663     LONG* plSkipLen)
3664 {
3665     FIXME("(%p)->%p %i %i %i %i %p %p\n", iface, pSrcMLStr, lSrcPos, lSrcLen, cMinColumns, cMaxColumns, plLineLen, plSkipLen);
3666     return E_NOTIMPL;
3667 }
3668 
3669 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineW(
3670     IMLangLineBreakConsole* iface,
3671     LCID locale,
3672     const WCHAR* pszSrc,
3673     LONG cchSrc,
3674     LONG cMaxColumns,
3675     LONG* pcchLine,
3676     LONG* pcchSkip )
3677 {
3678     FIXME("(%p)->%i %s %i %i %p %p\n", iface, locale, debugstr_wn(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3679 
3680     *pcchLine = cchSrc;
3681     *pcchSkip = 0;
3682     return S_OK;
3683 }
3684 
3685 static HRESULT WINAPI fnIMLangLineBreakConsole_BreakLineA(
3686     IMLangLineBreakConsole* iface,
3687     LCID locale,
3688     UINT uCodePage,
3689     const CHAR* pszSrc,
3690     LONG cchSrc,
3691     LONG cMaxColumns,
3692     LONG* pcchLine,
3693     LONG* pcchSkip)
3694 {
3695     LONG i, line = cchSrc, skip = 0;
3696 
3697     FIXME("(%p)->%i %i %s %i %i %p %p\n", iface, locale, uCodePage, debugstr_an(pszSrc,cchSrc), cchSrc, cMaxColumns, pcchLine, pcchSkip);
3698 
3699     if (uCodePage == CP_USASCII && cchSrc > cMaxColumns)
3700     {
3701         for (line = cMaxColumns, i = cMaxColumns - 1; i >= 0; i--)
3702         {
3703             if (pszSrc[i] == ' ')
3704             {
3705                 while (i >= 0 && pszSrc[i] == ' ')
3706                 {
3707                     i--;
3708                     line--;
3709                     skip++;
3710                 }
3711                 break;
3712             }
3713         }
3714     }
3715     *pcchLine = line;
3716     *pcchSkip = skip;
3717     return S_OK;
3718 }
3719 
3720 static const IMLangLineBreakConsoleVtbl IMLangLineBreakConsole_vtbl =
3721 {
3722     fnIMLangLineBreakConsole_QueryInterface,
3723     fnIMLangLineBreakConsole_AddRef,
3724     fnIMLangLineBreakConsole_Release,
3725     fnIMLangLineBreakConsole_BreakLineML,
3726     fnIMLangLineBreakConsole_BreakLineW,
3727     fnIMLangLineBreakConsole_BreakLineA
3728 };
3729 
3730 struct convert_charset {
3731     IMLangConvertCharset IMLangConvertCharset_iface;
3732     LONG ref;
3733 
3734     UINT src_cp;
3735     UINT dst_cp;
3736 };
3737 
3738 static inline struct convert_charset *impl_from_IMLangConvertCharset(IMLangConvertCharset *iface)
3739 {
3740     return CONTAINING_RECORD(iface, struct convert_charset, IMLangConvertCharset_iface);
3741 }
3742 
3743 static HRESULT WINAPI MLangConvertCharset_QueryInterface(IMLangConvertCharset *iface, REFIID riid, void **obj)
3744 {
3745     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3746 
3747     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3748 
3749     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMLangConvertCharset))
3750     {
3751         *obj = &This->IMLangConvertCharset_iface;
3752         IMLangConvertCharset_AddRef(iface);
3753         return S_OK;
3754     }
3755 
3756     *obj = NULL;
3757     return E_NOINTERFACE;
3758 }
3759 
3760 static ULONG WINAPI MLangConvertCharset_AddRef(IMLangConvertCharset *iface)
3761 {
3762     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3763     ULONG ref = InterlockedIncrement(&This->ref);
3764     TRACE("(%p)->(%u)\n", This, ref);
3765     return ref;
3766 }
3767 
3768 static ULONG WINAPI MLangConvertCharset_Release(IMLangConvertCharset *iface)
3769 {
3770     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3771     ULONG ref = InterlockedDecrement(&This->ref);
3772 
3773     TRACE("(%p)->(%u)\n", This, ref);
3774     if (!ref)
3775     {
3776         HeapFree(GetProcessHeap(), 0, This);
3777         UnlockModule();
3778     }
3779 
3780     return ref;
3781 }
3782 
3783 static HRESULT WINAPI MLangConvertCharset_Initialize(IMLangConvertCharset *iface,
3784     UINT src_cp, UINT dst_cp, DWORD prop)
3785 {
3786     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3787 
3788     TRACE("(%p)->(%u %u 0x%08x)\n", This, src_cp, dst_cp, prop);
3789 
3790     prop &= ~MLCONVCHARF_USEDEFCHAR;
3791     if (prop)
3792         FIXME("property 0x%08x not supported\n", prop);
3793 
3794     This->src_cp = src_cp;
3795     This->dst_cp = dst_cp;
3796 
3797     return S_OK;
3798 }
3799 
3800 static HRESULT WINAPI MLangConvertCharset_GetSourceCodePage(IMLangConvertCharset *iface, UINT *src_cp)
3801 {
3802     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3803 
3804     TRACE("(%p)->(%p)\n", This, src_cp);
3805 
3806     if (!src_cp) return E_INVALIDARG;
3807     *src_cp = This->src_cp;
3808     return S_OK;
3809 }
3810 
3811 static HRESULT WINAPI MLangConvertCharset_GetDestinationCodePage(IMLangConvertCharset *iface, UINT *dst_cp)
3812 {
3813     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3814 
3815     TRACE("(%p)->(%p)\n", This, dst_cp);
3816 
3817     if (!dst_cp) return E_INVALIDARG;
3818     *dst_cp = This->dst_cp;
3819     return S_OK;
3820 }
3821 
3822 static HRESULT WINAPI MLangConvertCharset_GetProperty(IMLangConvertCharset *iface, DWORD *prop)
3823 {
3824     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3825     FIXME("(%p)->(%p): stub\n", This, prop);
3826     return E_NOTIMPL;
3827 }
3828 
3829 static HRESULT WINAPI MLangConvertCharset_DoConversion(IMLangConvertCharset *iface, BYTE *src,
3830     UINT *src_size, BYTE *dest, UINT *dest_size)
3831 {
3832     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3833     FIXME("(%p)->(%p %p %p %p): stub\n", This, src, src_size, dest, dest_size);
3834     return E_NOTIMPL;
3835 }
3836 
3837 static HRESULT WINAPI MLangConvertCharset_DoConversionToUnicode(IMLangConvertCharset *iface, CHAR *src,
3838     UINT *src_size, WCHAR *dest, UINT *dest_size)
3839 {
3840     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3841     TRACE("(%p)->(%p %p %p %p)\n", This, src, src_size, dest, dest_size);
3842     return ConvertINetMultiByteToUnicode(NULL, This->src_cp, src, (INT*)src_size, dest, (INT*)dest_size);
3843 }
3844 
3845 static HRESULT WINAPI MLangConvertCharset_DoConversionFromUnicode(IMLangConvertCharset *iface,
3846     WCHAR *src, UINT *src_size, CHAR *dest, UINT *dest_size)
3847 {
3848     struct convert_charset *This = impl_from_IMLangConvertCharset(iface);
3849     TRACE("(%p)->(%p %p %p %p)\n", This, src, src_size, dest, dest_size);
3850     return ConvertINetUnicodeToMultiByte(NULL, This->dst_cp, src, (INT*)src_size, dest, (INT*)dest_size);
3851 }
3852 
3853 static const IMLangConvertCharsetVtbl MLangConvertCharsetVtbl =
3854 {
3855     MLangConvertCharset_QueryInterface,
3856     MLangConvertCharset_AddRef,
3857     MLangConvertCharset_Release,
3858     MLangConvertCharset_Initialize,
3859     MLangConvertCharset_GetSourceCodePage,
3860     MLangConvertCharset_GetDestinationCodePage,
3861     MLangConvertCharset_GetProperty,
3862     MLangConvertCharset_DoConversion,
3863     MLangConvertCharset_DoConversionToUnicode,
3864     MLangConvertCharset_DoConversionFromUnicode
3865 };
3866 
3867 static HRESULT MultiLanguage_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3868 {
3869     MLang_impl *mlang;
3870     UINT i;
3871 
3872     TRACE("Creating MultiLanguage object\n");
3873 
3874     if( pUnkOuter )
3875         return CLASS_E_NOAGGREGATION;
3876 
3877     mlang = HeapAlloc( GetProcessHeap(), 0, sizeof (MLang_impl) );
3878     mlang->IMLangFontLink_iface.lpVtbl = &IMLangFontLink_vtbl;
3879     mlang->IMultiLanguage_iface.lpVtbl = &IMultiLanguage_vtbl;
3880     mlang->IMultiLanguage3_iface.lpVtbl = &IMultiLanguage3_vtbl;
3881     mlang->IMLangFontLink2_iface.lpVtbl = &IMLangFontLink2_vtbl;
3882     mlang->IMLangLineBreakConsole_iface.lpVtbl = &IMLangLineBreakConsole_vtbl;
3883 
3884     mlang->total_cp = 0;
3885     for (i = 0; i < ARRAY_SIZE(mlang_data); i++)
3886         mlang->total_cp += mlang_data[i].number_of_cp;
3887 
3888     /* do not enumerate unicode flavours */
3889     mlang->total_scripts = ARRAY_SIZE(mlang_data) - 1;
3890 
3891     mlang->ref = 1;
3892     *ppObj = &mlang->IMultiLanguage_iface;
3893     TRACE("returning %p\n", mlang);
3894 
3895     LockModule();
3896 
3897     return S_OK;
3898 }
3899 
3900 static HRESULT MLangConvertCharset_create(IUnknown *outer, void **obj)
3901 {
3902     struct convert_charset *convert;
3903 
3904     if (outer)
3905         return CLASS_E_NOAGGREGATION;
3906 
3907     *obj = NULL;
3908 
3909     convert = HeapAlloc(GetProcessHeap(), 0, sizeof(struct convert_charset));
3910     if (!convert) return E_OUTOFMEMORY;
3911 
3912     convert->IMLangConvertCharset_iface.lpVtbl = &MLangConvertCharsetVtbl;
3913     convert->ref = 1;
3914 
3915     *obj = &convert->IMLangConvertCharset_iface;
3916 
3917     LockModule();
3918 
3919     return S_OK;
3920 }
3921 
3922 /******************************************************************************/
3923 
3924 HRESULT WINAPI DllCanUnloadNow(void)
3925 {
3926     return dll_count == 0 ? S_OK : S_FALSE;
3927 }
3928 
3929 static BOOL register_codepages(void)
3930 {
3931     const struct mlang_data *family;
3932     const MIME_CP_INFO *info;
3933     HKEY db_key, key;
3934     WCHAR buf[32];
3935     LSTATUS status;
3936 
3937     static const WCHAR db_key_nameW[] = {
3938         'M','I','M','E',
3939         '\\','D','a','t','a','b','a','s','e',
3940         '\\','C','o','d','e','p','a','g','e',0};
3941     static const WCHAR familyW[] = {'F','a','m','i','l','y',0};
3942     static const WCHAR formatW[] = {'%','u',0};
3943 
3944     status = RegCreateKeyW(HKEY_CLASSES_ROOT, db_key_nameW, &db_key);
3945     if (status != ERROR_SUCCESS)
3946         return FALSE;
3947 
3948     for (family = mlang_data; family < mlang_data + ARRAY_SIZE(mlang_data); family++)
3949     {
3950         for (info = family->mime_cp_info; info < family->mime_cp_info + family->number_of_cp; info++)
3951         {
3952             swprintf(buf, formatW, info->cp);
3953             status = RegCreateKeyW(db_key, buf, &key);
3954             if (status != ERROR_SUCCESS)
3955                 continue;
3956 
3957             RegSetValueExA(key, "BodyCharset", 0, REG_SZ, (BYTE*)info->body_charset,
3958                            strlen(info->body_charset) + 1);
3959 
3960             if (info->cp == family->family_codepage)
3961             {
3962                 RegSetValueExA(key, "FixedWidthFont", 0, REG_SZ, (BYTE*)family->fixed_font,
3963                                strlen(family->fixed_font) + 1);
3964                 RegSetValueExA(key, "ProportionalFont", 0, REG_SZ, (BYTE*)family->proportional_font,
3965                                strlen(family->proportional_font) + 1);
3966             }
3967             else
3968             {
3969                 RegSetValueExW(key, familyW, 0, REG_DWORD, (BYTE*)&family->family_codepage,
3970                                sizeof(family->family_codepage));
3971             }
3972 
3973             RegCloseKey(key);
3974         }
3975     }
3976 
3977     RegCloseKey(db_key);
3978     return TRUE;
3979 }
3980 
3981 /***********************************************************************
3982  *		DllRegisterServer (MLANG.@)
3983  */
3984 HRESULT WINAPI DllRegisterServer(void)
3985 {
3986     if(!register_codepages())
3987         return E_FAIL;
3988     return __wine_register_resources( instance );
3989 }
3990 
3991 /***********************************************************************
3992  *		DllUnregisterServer (MLANG.@)
3993  */
3994 HRESULT WINAPI DllUnregisterServer(void)
3995 {
3996     return __wine_unregister_resources( instance );
3997 }
3998 
3999 HRESULT WINAPI GetGlobalFontLinkObject(void **unknown)
4000 {
4001     if (!unknown) return E_INVALIDARG;
4002 
4003     FIXME("%p: stub\n", unknown);
4004 
4005     return S_FALSE;
4006 }
4007