* Sync up to trunk r55544.
[reactos.git] / 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 "Both"
731 },
732 { &CLSID_WICBmpDecoder,
733 "WIC BMP Decoder",
734 NULL,
735 "windowscodecs.dll",
736 "Both"
737 },
738 { &CLSID_WICPngDecoder,
739 "WIC PNG Decoder",
740 NULL,
741 "windowscodecs.dll",
742 "Both"
743 },
744 { &CLSID_WICPngEncoder,
745 "WIC PNG Encoder",
746 NULL,
747 "windowscodecs.dll",
748 "Both"
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 "Both"
761 },
762 { &CLSID_WICIcoDecoder,
763 "WIC ICO Decoder",
764 NULL,
765 "windowscodecs.dll",
766 "Both"
767 },
768 { &CLSID_WICJpegDecoder,
769 "WIC JPEG Decoder",
770 NULL,
771 "windowscodecs.dll",
772 "Both"
773 },
774 { &CLSID_WICTiffDecoder,
775 "WIC TIFF Decoder",
776 NULL,
777 "windowscodecs.dll",
778 "Both"
779 },
780 { &CLSID_WICDefaultFormatConverter,
781 "WIC Default Format Converter",
782 NULL,
783 "windowscodecs.dll",
784 "Both"
785 },
786 { NULL } /* list terminator */
787 };
788
789 /***********************************************************************
790 * decoder list
791 */
792 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
793
794 static const BYTE bmp_magic[] = {0x42,0x4d};
795
796 static GUID const * const bmp_formats[] = {
797 &GUID_WICPixelFormat1bppIndexed,
798 &GUID_WICPixelFormat2bppIndexed,
799 &GUID_WICPixelFormat4bppIndexed,
800 &GUID_WICPixelFormat8bppIndexed,
801 &GUID_WICPixelFormat16bppBGR555,
802 &GUID_WICPixelFormat16bppBGR565,
803 &GUID_WICPixelFormat24bppBGR,
804 &GUID_WICPixelFormat32bppBGR,
805 &GUID_WICPixelFormat32bppBGRA,
806 NULL
807 };
808
809 static struct decoder_pattern const bmp_patterns[] = {
810 {2,0,bmp_magic,mask_all,0},
811 {0}
812 };
813
814 static const BYTE gif87a_magic[6] = "GIF87a";
815 static const BYTE gif89a_magic[6] = "GIF89a";
816
817 static GUID const * const gif_formats[] = {
818 &GUID_WICPixelFormat8bppIndexed,
819 NULL
820 };
821
822 static struct decoder_pattern const gif_patterns[] = {
823 {6,0,gif87a_magic,mask_all,0},
824 {6,0,gif89a_magic,mask_all,0},
825 {0}
826 };
827
828 static const BYTE ico_magic[] = {00,00,01,00};
829
830 static GUID const * const ico_formats[] = {
831 &GUID_WICPixelFormat32bppBGRA,
832 NULL
833 };
834
835 static struct decoder_pattern const ico_patterns[] = {
836 {4,0,ico_magic,mask_all,0},
837 {0}
838 };
839
840 static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
841
842 static GUID const * const jpeg_formats[] = {
843 &GUID_WICPixelFormat24bppBGR,
844 &GUID_WICPixelFormat8bppGray,
845 NULL
846 };
847
848 static struct decoder_pattern const jpeg_patterns[] = {
849 {4,0,jpeg_magic,mask_all,0},
850 {0}
851 };
852
853 static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
854
855 static GUID const * const png_formats[] = {
856 &GUID_WICPixelFormatBlackWhite,
857 &GUID_WICPixelFormat2bppGray,
858 &GUID_WICPixelFormat4bppGray,
859 &GUID_WICPixelFormat8bppGray,
860 &GUID_WICPixelFormat16bppGray,
861 &GUID_WICPixelFormat32bppBGRA,
862 &GUID_WICPixelFormat64bppRGBA,
863 &GUID_WICPixelFormat1bppIndexed,
864 &GUID_WICPixelFormat2bppIndexed,
865 &GUID_WICPixelFormat4bppIndexed,
866 &GUID_WICPixelFormat8bppIndexed,
867 &GUID_WICPixelFormat24bppBGR,
868 &GUID_WICPixelFormat48bppRGB,
869 NULL
870 };
871
872 static struct decoder_pattern const png_patterns[] = {
873 {8,0,png_magic,mask_all,0},
874 {0}
875 };
876
877 static const BYTE tiff_magic_le[] = {0x49,0x49,42,0};
878 static const BYTE tiff_magic_be[] = {0x4d,0x4d,0,42};
879
880 static GUID const * const tiff_formats[] = {
881 &GUID_WICPixelFormatBlackWhite,
882 &GUID_WICPixelFormat4bppGray,
883 &GUID_WICPixelFormat8bppGray,
884 &GUID_WICPixelFormat4bppIndexed,
885 &GUID_WICPixelFormat8bppIndexed,
886 &GUID_WICPixelFormat32bppBGR,
887 &GUID_WICPixelFormat32bppBGRA,
888 &GUID_WICPixelFormat32bppPBGRA,
889 NULL
890 };
891
892 static struct decoder_pattern const tiff_patterns[] = {
893 {4,0,tiff_magic_le,mask_all,0},
894 {4,0,tiff_magic_be,mask_all,0},
895 {0}
896 };
897
898 static struct regsvr_decoder const decoder_list[] = {
899 { &CLSID_WICBmpDecoder,
900 "The Wine Project",
901 "BMP Decoder",
902 "1.0.0.0",
903 &GUID_VendorMicrosoft,
904 "image/bmp",
905 ".bmp,.dib,.rle",
906 bmp_formats,
907 bmp_patterns
908 },
909 { &CLSID_WICGifDecoder,
910 "The Wine Project",
911 "GIF Decoder",
912 "1.0.0.0",
913 &GUID_VendorMicrosoft,
914 "image/gif",
915 ".gif",
916 gif_formats,
917 gif_patterns
918 },
919 { &CLSID_WICIcoDecoder,
920 "The Wine Project",
921 "ICO Decoder",
922 "1.0.0.0",
923 &GUID_VendorMicrosoft,
924 "image/vnd.microsoft.icon",
925 ".ico",
926 ico_formats,
927 ico_patterns
928 },
929 { &CLSID_WICJpegDecoder,
930 "The Wine Project",
931 "JPEG Decoder",
932 "1.0.0.0",
933 &GUID_VendorMicrosoft,
934 "image/jpeg",
935 ".jpg;.jpeg;.jfif",
936 jpeg_formats,
937 jpeg_patterns
938 },
939 { &CLSID_WICPngDecoder,
940 "The Wine Project",
941 "PNG Decoder",
942 "1.0.0.0",
943 &GUID_VendorMicrosoft,
944 "image/png",
945 ".png",
946 png_formats,
947 png_patterns
948 },
949 { &CLSID_WICTiffDecoder,
950 "The Wine Project",
951 "TIFF Decoder",
952 "1.0.0.0",
953 &GUID_VendorMicrosoft,
954 "image/tiff",
955 ".tif;.tiff",
956 tiff_formats,
957 tiff_patterns
958 },
959 { NULL } /* list terminator */
960 };
961
962 static GUID const * const converter_formats[] = {
963 &GUID_WICPixelFormat1bppIndexed,
964 &GUID_WICPixelFormat2bppIndexed,
965 &GUID_WICPixelFormat4bppIndexed,
966 &GUID_WICPixelFormat8bppIndexed,
967 &GUID_WICPixelFormatBlackWhite,
968 &GUID_WICPixelFormat2bppGray,
969 &GUID_WICPixelFormat4bppGray,
970 &GUID_WICPixelFormat8bppGray,
971 &GUID_WICPixelFormat16bppGray,
972 &GUID_WICPixelFormat16bppBGR555,
973 &GUID_WICPixelFormat16bppBGR565,
974 &GUID_WICPixelFormat24bppBGR,
975 &GUID_WICPixelFormat32bppBGR,
976 &GUID_WICPixelFormat32bppBGRA,
977 &GUID_WICPixelFormat48bppRGB,
978 &GUID_WICPixelFormat64bppRGBA,
979 NULL
980 };
981
982 static struct regsvr_converter const converter_list[] = {
983 { &CLSID_WICDefaultFormatConverter,
984 "The Wine Project",
985 "Default Pixel Format Converter",
986 "1.0.0.0",
987 &GUID_VendorMicrosoft,
988 converter_formats
989 },
990 { NULL } /* list terminator */
991 };
992
993 HRESULT WINAPI DllRegisterServer(void)
994 {
995 HRESULT hr;
996
997 TRACE("\n");
998
999 hr = register_coclasses(coclass_list);
1000 if (SUCCEEDED(hr))
1001 register_decoders(decoder_list);
1002 if (SUCCEEDED(hr))
1003 register_converters(converter_list);
1004 return hr;
1005 }
1006
1007 HRESULT WINAPI DllUnregisterServer(void)
1008 {
1009 HRESULT hr;
1010
1011 TRACE("\n");
1012
1013 hr = unregister_coclasses(coclass_list);
1014 if (SUCCEEDED(hr))
1015 unregister_decoders(decoder_list);
1016 if (SUCCEEDED(hr))
1017 unregister_converters(converter_list);
1018 return hr;
1019 }