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