Merge from amd64-branch:
[reactos.git] / reactos / dll / win32 / windowscodecs / regsvr.c
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
21 #define COBJMACROS
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "objbase.h"
33 #include "ocidl.h"
34 #include "wincodec.h"
35
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
40
41 /***********************************************************************
42 * interface for self-registering
43 */
44 struct regsvr_coclass
45 {
46 CLSID const *clsid; /* NULL for end of list */
47 LPCSTR name; /* can be NULL to omit */
48 LPCSTR ips; /* can be NULL to omit */
49 LPCSTR ips32; /* can be NULL to omit */
50 LPCSTR ips32_tmodel; /* can be NULL to omit */
51 LPCSTR progid; /* can be NULL to omit */
52 LPCSTR viprogid; /* can be NULL to omit */
53 LPCSTR progid_extra; /* can be NULL to omit */
54 };
55
56 static HRESULT register_coclasses(struct regsvr_coclass const *list);
57 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
58
59 struct decoder_pattern
60 {
61 DWORD length; /* 0 for end of list */
62 DWORD position;
63 const BYTE *pattern;
64 const BYTE *mask;
65 DWORD endofstream;
66 };
67
68 struct regsvr_decoder
69 {
70 CLSID const *clsid; /* NULL for end of list */
71 LPCSTR author;
72 LPCSTR friendlyname;
73 LPCSTR version;
74 GUID const *vendor;
75 LPCSTR mimetypes;
76 LPCSTR extensions;
77 GUID const * const *formats;
78 const struct decoder_pattern *patterns;
79 };
80
81 static HRESULT register_decoders(struct regsvr_decoder const *list);
82 static HRESULT unregister_decoders(struct regsvr_decoder const *list);
83
84 struct regsvr_converter
85 {
86 CLSID const *clsid; /* NULL for end of list */
87 LPCSTR author;
88 LPCSTR friendlyname;
89 LPCSTR version;
90 GUID const *vendor;
91 GUID const * const *formats;
92 };
93
94 static HRESULT register_converters(struct regsvr_converter const *list);
95 static HRESULT unregister_converters(struct regsvr_converter const *list);
96
97 /***********************************************************************
98 * static string constants
99 */
100 static WCHAR const clsid_keyname[6] = {
101 'C', 'L', 'S', 'I', 'D', 0 };
102 static WCHAR const curver_keyname[7] = {
103 'C', 'u', 'r', 'V', 'e', 'r', 0 };
104 static WCHAR const ips_keyname[13] = {
105 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
106 0 };
107 static WCHAR const ips32_keyname[15] = {
108 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
109 '3', '2', 0 };
110 static WCHAR const progid_keyname[7] = {
111 'P', 'r', 'o', 'g', 'I', 'D', 0 };
112 static WCHAR const viprogid_keyname[25] = {
113 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
114 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
115 0 };
116 static char const tmodel_valuename[] = "ThreadingModel";
117 static char const author_valuename[] = "Author";
118 static char const friendlyname_valuename[] = "FriendlyName";
119 static WCHAR const vendor_valuename[] = {'V','e','n','d','o','r',0};
120 static char const version_valuename[] = "Version";
121 static char const mimetypes_valuename[] = "MimeTypes";
122 static char const extensions_valuename[] = "FileExtensions";
123 static WCHAR const formats_keyname[] = {'F','o','r','m','a','t','s',0};
124 static WCHAR const patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
125 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
126 static WCHAR const clsid_valuename[] = {'C','L','S','I','D',0};
127 static char const length_valuename[] = "Length";
128 static char const position_valuename[] = "Position";
129 static char const pattern_valuename[] = "Pattern";
130 static char const mask_valuename[] = "Mask";
131 static char const endofstream_valuename[] = "EndOfStream";
132 static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
133
134 /***********************************************************************
135 * static helper functions
136 */
137 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
138 WCHAR const *value);
139 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
140 char const *value);
141 static LONG register_progid(WCHAR const *clsid,
142 char const *progid, char const *curver_progid,
143 char const *name, char const *extra);
144
145 /***********************************************************************
146 * register_coclasses
147 */
148 static HRESULT register_coclasses(struct regsvr_coclass const *list)
149 {
150 LONG res = ERROR_SUCCESS;
151 HKEY coclass_key;
152
153 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
154 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
155 if (res != ERROR_SUCCESS) goto error_return;
156
157 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
158 WCHAR buf[39];
159 HKEY clsid_key;
160
161 StringFromGUID2(list->clsid, buf, 39);
162 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
163 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
164 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
165
166 if (list->name) {
167 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
168 (CONST BYTE*)(list->name),
169 strlen(list->name) + 1);
170 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
171 }
172
173 if (list->ips) {
174 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
175 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
176 }
177
178 if (list->ips32) {
179 HKEY ips32_key;
180
181 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
182 KEY_READ | KEY_WRITE, NULL,
183 &ips32_key, NULL);
184 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
185
186 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
187 (CONST BYTE*)list->ips32,
188 lstrlenA(list->ips32) + 1);
189 if (res == ERROR_SUCCESS && list->ips32_tmodel)
190 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
191 (CONST BYTE*)list->ips32_tmodel,
192 strlen(list->ips32_tmodel) + 1);
193 RegCloseKey(ips32_key);
194 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
195 }
196
197 if (list->progid) {
198 res = register_key_defvalueA(clsid_key, progid_keyname,
199 list->progid);
200 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
201
202 res = register_progid(buf, list->progid, NULL,
203 list->name, list->progid_extra);
204 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
205 }
206
207 if (list->viprogid) {
208 res = register_key_defvalueA(clsid_key, viprogid_keyname,
209 list->viprogid);
210 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
211
212 res = register_progid(buf, list->viprogid, list->progid,
213 list->name, list->progid_extra);
214 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
215 }
216
217 error_close_clsid_key:
218 RegCloseKey(clsid_key);
219 }
220
221 error_close_coclass_key:
222 RegCloseKey(coclass_key);
223 error_return:
224 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
225 }
226
227 /***********************************************************************
228 * unregister_coclasses
229 */
230 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
231 {
232 LONG res = ERROR_SUCCESS;
233 HKEY coclass_key;
234
235 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
236 KEY_READ | KEY_WRITE, &coclass_key);
237 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
238 if (res != ERROR_SUCCESS) goto error_return;
239
240 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
241 WCHAR buf[39];
242
243 StringFromGUID2(list->clsid, buf, 39);
244 res = RegDeleteTreeW(coclass_key, buf);
245 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
246 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
247
248 if (list->progid) {
249 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
250 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
251 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
252 }
253
254 if (list->viprogid) {
255 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
256 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
257 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
258 }
259 }
260
261 error_close_coclass_key:
262 RegCloseKey(coclass_key);
263 error_return:
264 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
265 }
266
267 /***********************************************************************
268 * register_decoders
269 */
270 static HRESULT register_decoders(struct regsvr_decoder const *list)
271 {
272 LONG res = ERROR_SUCCESS;
273 HKEY coclass_key;
274 WCHAR buf[39];
275 HKEY decoders_key;
276 HKEY instance_key;
277
278 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
279 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
280 if (res == ERROR_SUCCESS) {
281 StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
282 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
283 KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
284 if (res == ERROR_SUCCESS)
285 {
286 res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
287 KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
288 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
289 }
290 if (res != ERROR_SUCCESS)
291 RegCloseKey(coclass_key);
292 }
293 if (res != ERROR_SUCCESS) goto error_return;
294
295 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
296 HKEY clsid_key;
297 HKEY instance_clsid_key;
298
299 StringFromGUID2(list->clsid, buf, 39);
300 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
301 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
302 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
303
304 StringFromGUID2(list->clsid, buf, 39);
305 res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
306 KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
307 if (res == ERROR_SUCCESS) {
308 res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
309 (CONST BYTE*)(buf), 78);
310 RegCloseKey(instance_clsid_key);
311 }
312 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
313
314 if (list->author) {
315 res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
316 (CONST BYTE*)(list->author),
317 strlen(list->author) + 1);
318 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
319 }
320
321 if (list->friendlyname) {
322 res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
323 (CONST BYTE*)(list->friendlyname),
324 strlen(list->friendlyname) + 1);
325 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
326 }
327
328 if (list->vendor) {
329 StringFromGUID2(list->vendor, buf, 39);
330 res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
331 (CONST BYTE*)(buf), 78);
332 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
333 }
334
335 if (list->version) {
336 res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
337 (CONST BYTE*)(list->version),
338 strlen(list->version) + 1);
339 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
340 }
341
342 if (list->mimetypes) {
343 res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
344 (CONST BYTE*)(list->mimetypes),
345 strlen(list->mimetypes) + 1);
346 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
347 }
348
349 if (list->extensions) {
350 res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
351 (CONST BYTE*)(list->extensions),
352 strlen(list->extensions) + 1);
353 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
354 }
355
356 if (list->formats) {
357 HKEY formats_key;
358 GUID const * const *format;
359
360 res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
361 KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
362 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
363 for (format=list->formats; *format; ++format)
364 {
365 HKEY format_key;
366 StringFromGUID2(*format, buf, 39);
367 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
368 KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
369 if (res != ERROR_SUCCESS) break;
370 RegCloseKey(format_key);
371 }
372 RegCloseKey(formats_key);
373 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
374 }
375
376 if (list->patterns) {
377 HKEY patterns_key;
378 int i;
379
380 res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
381 KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
382 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
383 for (i=0; list->patterns[i].length; i++)
384 {
385 HKEY pattern_key;
386 static const WCHAR int_format[] = {'%','i',0};
387 snprintfW(buf, 39, int_format, i);
388 res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
389 KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
390 if (res != ERROR_SUCCESS) break;
391 res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
392 (CONST BYTE*)(&list->patterns[i].length), 4);
393 if (res == ERROR_SUCCESS)
394 res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
395 (CONST BYTE*)(&list->patterns[i].position), 4);
396 if (res == ERROR_SUCCESS)
397 res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
398 list->patterns[i].pattern,
399 list->patterns[i].length);
400 if (res == ERROR_SUCCESS)
401 res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
402 list->patterns[i].mask,
403 list->patterns[i].length);
404 if (res == ERROR_SUCCESS)
405 res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
406 (CONST BYTE*)&(list->patterns[i].endofstream), 4);
407 RegCloseKey(pattern_key);
408 }
409 RegCloseKey(patterns_key);
410 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
411 }
412
413 error_close_clsid_key:
414 RegCloseKey(clsid_key);
415 }
416
417 error_close_coclass_key:
418 RegCloseKey(instance_key);
419 RegCloseKey(decoders_key);
420 RegCloseKey(coclass_key);
421 error_return:
422 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
423 }
424
425 /***********************************************************************
426 * unregister_decoders
427 */
428 static HRESULT unregister_decoders(struct regsvr_decoder const *list)
429 {
430 LONG res = ERROR_SUCCESS;
431 HKEY coclass_key;
432 WCHAR buf[39];
433 HKEY decoders_key;
434 HKEY instance_key;
435
436 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
437 KEY_READ | KEY_WRITE, &coclass_key);
438 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
439
440 if (res == ERROR_SUCCESS) {
441 StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
442 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
443 KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
444 if (res == ERROR_SUCCESS)
445 {
446 res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
447 KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
448 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
449 }
450 if (res != ERROR_SUCCESS)
451 RegCloseKey(coclass_key);
452 }
453 if (res != ERROR_SUCCESS) goto error_return;
454
455 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
456 StringFromGUID2(list->clsid, buf, 39);
457
458 res = RegDeleteTreeW(coclass_key, buf);
459 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
460 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
461
462 res = RegDeleteTreeW(instance_key, buf);
463 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
464 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
465 }
466
467 error_close_coclass_key:
468 RegCloseKey(instance_key);
469 RegCloseKey(decoders_key);
470 RegCloseKey(coclass_key);
471 error_return:
472 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
473 }
474
475 /***********************************************************************
476 * register_converters
477 */
478 static HRESULT register_converters(struct regsvr_converter const *list)
479 {
480 LONG res = ERROR_SUCCESS;
481 HKEY coclass_key;
482 WCHAR buf[39];
483 HKEY converters_key;
484 HKEY instance_key;
485
486 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
487 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
488 if (res == ERROR_SUCCESS) {
489 StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
490 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
491 KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
492 if (res == ERROR_SUCCESS)
493 {
494 res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
495 KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
496 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
497 }
498 if (res != ERROR_SUCCESS)
499 RegCloseKey(coclass_key);
500 }
501 if (res != ERROR_SUCCESS) goto error_return;
502
503 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
504 HKEY clsid_key;
505 HKEY instance_clsid_key;
506
507 StringFromGUID2(list->clsid, buf, 39);
508 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
509 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
510 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
511
512 StringFromGUID2(list->clsid, buf, 39);
513 res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
514 KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
515 if (res == ERROR_SUCCESS) {
516 res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
517 (CONST BYTE*)(buf), 78);
518 RegCloseKey(instance_clsid_key);
519 }
520 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
521
522 if (list->author) {
523 res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
524 (CONST BYTE*)(list->author),
525 strlen(list->author) + 1);
526 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
527 }
528
529 if (list->friendlyname) {
530 res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
531 (CONST BYTE*)(list->friendlyname),
532 strlen(list->friendlyname) + 1);
533 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
534 }
535
536 if (list->vendor) {
537 StringFromGUID2(list->vendor, buf, 39);
538 res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
539 (CONST BYTE*)(buf), 78);
540 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
541 }
542
543 if (list->version) {
544 res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
545 (CONST BYTE*)(list->version),
546 strlen(list->version) + 1);
547 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
548 }
549
550 if (list->formats) {
551 HKEY formats_key;
552 GUID const * const *format;
553
554 res = RegCreateKeyExW(clsid_key, pixelformats_keyname, 0, NULL, 0,
555 KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
556 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
557 for (format=list->formats; *format; ++format)
558 {
559 HKEY format_key;
560 StringFromGUID2(*format, buf, 39);
561 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
562 KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
563 if (res != ERROR_SUCCESS) break;
564 RegCloseKey(format_key);
565 }
566 RegCloseKey(formats_key);
567 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
568 }
569
570 error_close_clsid_key:
571 RegCloseKey(clsid_key);
572 }
573
574 error_close_coclass_key:
575 RegCloseKey(instance_key);
576 RegCloseKey(converters_key);
577 RegCloseKey(coclass_key);
578 error_return:
579 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
580 }
581
582 /***********************************************************************
583 * unregister_converters
584 */
585 static HRESULT unregister_converters(struct regsvr_converter const *list)
586 {
587 LONG res = ERROR_SUCCESS;
588 HKEY coclass_key;
589 WCHAR buf[39];
590 HKEY converters_key;
591 HKEY instance_key;
592
593 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
594 KEY_READ | KEY_WRITE, &coclass_key);
595 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
596
597 if (res == ERROR_SUCCESS) {
598 StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
599 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
600 KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
601 if (res == ERROR_SUCCESS)
602 {
603 res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
604 KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
605 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
606 }
607 if (res != ERROR_SUCCESS)
608 RegCloseKey(coclass_key);
609 }
610 if (res != ERROR_SUCCESS) goto error_return;
611
612 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
613 StringFromGUID2(list->clsid, buf, 39);
614
615 res = RegDeleteTreeW(coclass_key, buf);
616 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
617 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
618
619 res = RegDeleteTreeW(instance_key, buf);
620 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
621 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
622 }
623
624 error_close_coclass_key:
625 RegCloseKey(instance_key);
626 RegCloseKey(converters_key);
627 RegCloseKey(coclass_key);
628 error_return:
629 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
630 }
631
632 /***********************************************************************
633 * register_key_defvalueW
634 */
635 static LONG register_key_defvalueW(
636 HKEY base,
637 WCHAR const *name,
638 WCHAR const *value)
639 {
640 LONG res;
641 HKEY key;
642
643 res = RegCreateKeyExW(base, name, 0, NULL, 0,
644 KEY_READ | KEY_WRITE, NULL, &key, NULL);
645 if (res != ERROR_SUCCESS) return res;
646 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
647 (lstrlenW(value) + 1) * sizeof(WCHAR));
648 RegCloseKey(key);
649 return res;
650 }
651
652 /***********************************************************************
653 * register_key_defvalueA
654 */
655 static LONG register_key_defvalueA(
656 HKEY base,
657 WCHAR const *name,
658 char const *value)
659 {
660 LONG res;
661 HKEY key;
662
663 res = RegCreateKeyExW(base, name, 0, NULL, 0,
664 KEY_READ | KEY_WRITE, NULL, &key, NULL);
665 if (res != ERROR_SUCCESS) return res;
666 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
667 lstrlenA(value) + 1);
668 RegCloseKey(key);
669 return res;
670 }
671
672 /***********************************************************************
673 * register_progid
674 */
675 static LONG register_progid(
676 WCHAR const *clsid,
677 char const *progid,
678 char const *curver_progid,
679 char const *name,
680 char const *extra)
681 {
682 LONG res;
683 HKEY progid_key;
684
685 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
686 NULL, 0, KEY_READ | KEY_WRITE, NULL,
687 &progid_key, NULL);
688 if (res != ERROR_SUCCESS) return res;
689
690 if (name) {
691 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
692 (CONST BYTE*)name, strlen(name) + 1);
693 if (res != ERROR_SUCCESS) goto error_close_progid_key;
694 }
695
696 if (clsid) {
697 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
698 if (res != ERROR_SUCCESS) goto error_close_progid_key;
699 }
700
701 if (curver_progid) {
702 res = register_key_defvalueA(progid_key, curver_keyname,
703 curver_progid);
704 if (res != ERROR_SUCCESS) goto error_close_progid_key;
705 }
706
707 if (extra) {
708 HKEY extra_key;
709
710 res = RegCreateKeyExA(progid_key, extra, 0,
711 NULL, 0, KEY_READ | KEY_WRITE, NULL,
712 &extra_key, NULL);
713 if (res == ERROR_SUCCESS)
714 RegCloseKey(extra_key);
715 }
716
717 error_close_progid_key:
718 RegCloseKey(progid_key);
719 return res;
720 }
721
722 /***********************************************************************
723 * coclass list
724 */
725 static struct regsvr_coclass const coclass_list[] = {
726 { &CLSID_WICImagingFactory,
727 "WIC Imaging Factory",
728 NULL,
729 "windowscodecs.dll",
730 "Apartment"
731 },
732 { &CLSID_WICBmpDecoder,
733 "WIC BMP Decoder",
734 NULL,
735 "windowscodecs.dll",
736 "Apartment"
737 },
738 { &CLSID_WICPngDecoder,
739 "WIC PNG Decoder",
740 NULL,
741 "windowscodecs.dll",
742 "Apartment"
743 },
744 { &CLSID_WICPngEncoder,
745 "WIC PNG Encoder",
746 NULL,
747 "windowscodecs.dll",
748 "Apartment"
749 },
750 { &CLSID_WICBmpEncoder,
751 "WIC BMP Encoder",
752 NULL,
753 "windowscodecs.dll",
754 "Apartment"
755 },
756 { &CLSID_WICGifDecoder,
757 "WIC GIF Decoder",
758 NULL,
759 "windowscodecs.dll",
760 "Apartment"
761 },
762 { &CLSID_WICIcoDecoder,
763 "WIC ICO Decoder",
764 NULL,
765 "windowscodecs.dll",
766 "Apartment"
767 },
768 { &CLSID_WICJpegDecoder,
769 "WIC JPEG Decoder",
770 NULL,
771 "windowscodecs.dll",
772 "Apartment"
773 },
774 { &CLSID_WICDefaultFormatConverter,
775 "WIC Default Format Converter",
776 NULL,
777 "windowscodecs.dll",
778 "Apartment"
779 },
780 { NULL } /* list terminator */
781 };
782
783 /***********************************************************************
784 * decoder list
785 */
786 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
787
788 static const BYTE bmp_magic[] = {0x42,0x4d};
789
790 static GUID const * const bmp_formats[] = {
791 &GUID_WICPixelFormat1bppIndexed,
792 &GUID_WICPixelFormat2bppIndexed,
793 &GUID_WICPixelFormat4bppIndexed,
794 &GUID_WICPixelFormat8bppIndexed,
795 &GUID_WICPixelFormat16bppBGR555,
796 &GUID_WICPixelFormat16bppBGR565,
797 &GUID_WICPixelFormat24bppBGR,
798 &GUID_WICPixelFormat32bppBGR,
799 &GUID_WICPixelFormat32bppBGRA,
800 NULL
801 };
802
803 static struct decoder_pattern const bmp_patterns[] = {
804 {2,0,bmp_magic,mask_all,0},
805 {0}
806 };
807
808 static const BYTE gif87a_magic[6] = "GIF87a";
809 static const BYTE gif89a_magic[6] = "GIF89a";
810
811 static GUID const * const gif_formats[] = {
812 &GUID_WICPixelFormat8bppIndexed,
813 NULL
814 };
815
816 static struct decoder_pattern const gif_patterns[] = {
817 {6,0,gif87a_magic,mask_all,0},
818 {6,0,gif89a_magic,mask_all,0},
819 {0}
820 };
821
822 static const BYTE ico_magic[] = {00,00,01,00};
823
824 static GUID const * const ico_formats[] = {
825 &GUID_WICPixelFormat32bppBGRA,
826 NULL
827 };
828
829 static struct decoder_pattern const ico_patterns[] = {
830 {4,0,ico_magic,mask_all,0},
831 {0}
832 };
833
834 static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
835
836 static GUID const * const jpeg_formats[] = {
837 &GUID_WICPixelFormat24bppBGR,
838 &GUID_WICPixelFormat8bppGray,
839 NULL
840 };
841
842 static struct decoder_pattern const jpeg_patterns[] = {
843 {4,0,jpeg_magic,mask_all,0},
844 {0}
845 };
846
847 static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
848
849 static GUID const * const png_formats[] = {
850 &GUID_WICPixelFormatBlackWhite,
851 &GUID_WICPixelFormat2bppGray,
852 &GUID_WICPixelFormat4bppGray,
853 &GUID_WICPixelFormat8bppGray,
854 &GUID_WICPixelFormat16bppGray,
855 &GUID_WICPixelFormat32bppBGRA,
856 &GUID_WICPixelFormat64bppRGBA,
857 &GUID_WICPixelFormat1bppIndexed,
858 &GUID_WICPixelFormat2bppIndexed,
859 &GUID_WICPixelFormat4bppIndexed,
860 &GUID_WICPixelFormat8bppIndexed,
861 &GUID_WICPixelFormat24bppBGR,
862 &GUID_WICPixelFormat48bppRGB,
863 NULL
864 };
865
866 static struct decoder_pattern const png_patterns[] = {
867 {8,0,png_magic,mask_all,0},
868 {0}
869 };
870
871 static struct regsvr_decoder const decoder_list[] = {
872 { &CLSID_WICBmpDecoder,
873 "The Wine Project",
874 "BMP Decoder",
875 "1.0.0.0",
876 &GUID_VendorMicrosoft,
877 "image/bmp",
878 ".bmp,.dib,.rle",
879 bmp_formats,
880 bmp_patterns
881 },
882 { &CLSID_WICGifDecoder,
883 "The Wine Project",
884 "GIF Decoder",
885 "1.0.0.0",
886 &GUID_VendorMicrosoft,
887 "image/gif",
888 ".gif",
889 gif_formats,
890 gif_patterns
891 },
892 { &CLSID_WICIcoDecoder,
893 "The Wine Project",
894 "ICO Decoder",
895 "1.0.0.0",
896 &GUID_VendorMicrosoft,
897 "image/vnd.microsoft.icon",
898 ".ico",
899 ico_formats,
900 ico_patterns
901 },
902 { &CLSID_WICJpegDecoder,
903 "The Wine Project",
904 "JPEG Decoder",
905 "1.0.0.0",
906 &GUID_VendorMicrosoft,
907 "image/jpeg",
908 ".jpg;.jpeg;.jfif",
909 jpeg_formats,
910 jpeg_patterns
911 },
912 { &CLSID_WICPngDecoder,
913 "The Wine Project",
914 "PNG Decoder",
915 "1.0.0.0",
916 &GUID_VendorMicrosoft,
917 "image/png",
918 ".png",
919 png_formats,
920 png_patterns
921 },
922 { NULL } /* list terminator */
923 };
924
925 static GUID const * const converter_formats[] = {
926 &GUID_WICPixelFormat1bppIndexed,
927 &GUID_WICPixelFormat2bppIndexed,
928 &GUID_WICPixelFormat4bppIndexed,
929 &GUID_WICPixelFormat8bppIndexed,
930 &GUID_WICPixelFormatBlackWhite,
931 &GUID_WICPixelFormat2bppGray,
932 &GUID_WICPixelFormat4bppGray,
933 &GUID_WICPixelFormat8bppGray,
934 &GUID_WICPixelFormat16bppGray,
935 &GUID_WICPixelFormat16bppBGR555,
936 &GUID_WICPixelFormat16bppBGR565,
937 &GUID_WICPixelFormat24bppBGR,
938 &GUID_WICPixelFormat32bppBGR,
939 &GUID_WICPixelFormat32bppBGRA,
940 &GUID_WICPixelFormat48bppRGB,
941 &GUID_WICPixelFormat64bppRGBA,
942 NULL
943 };
944
945 static struct regsvr_converter const converter_list[] = {
946 { &CLSID_WICDefaultFormatConverter,
947 "The Wine Project",
948 "Default Pixel Format Converter",
949 "1.0.0.0",
950 &GUID_VendorMicrosoft,
951 converter_formats
952 },
953 { NULL } /* list terminator */
954 };
955
956 HRESULT WINAPI DllRegisterServer(void)
957 {
958 HRESULT hr;
959
960 TRACE("\n");
961
962 hr = register_coclasses(coclass_list);
963 if (SUCCEEDED(hr))
964 register_decoders(decoder_list);
965 if (SUCCEEDED(hr))
966 register_converters(converter_list);
967 return hr;
968 }
969
970 HRESULT WINAPI DllUnregisterServer(void)
971 {
972 HRESULT hr;
973
974 TRACE("\n");
975
976 hr = unregister_coclasses(coclass_list);
977 if (SUCCEEDED(hr))
978 unregister_decoders(decoder_list);
979 if (SUCCEEDED(hr))
980 unregister_converters(converter_list);
981 return hr;
982 }