windowscodecs: Support conversion of 8bppGray to 32bppBGRA.
[wine] / dlls / 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_WICBmpEncoder,
739         "WIC BMP Encoder",
740         NULL,
741         "windowscodecs.dll",
742         "Apartment"
743     },
744     {   &CLSID_WICGifDecoder,
745         "WIC GIF Decoder",
746         NULL,
747         "windowscodecs.dll",
748         "Apartment"
749     },
750     {   &CLSID_WICIcoDecoder,
751         "WIC ICO Decoder",
752         NULL,
753         "windowscodecs.dll",
754         "Apartment"
755     },
756     {   &CLSID_WICJpegDecoder,
757         "WIC JPEG Decoder",
758         NULL,
759         "windowscodecs.dll",
760         "Apartment"
761     },
762     {   &CLSID_WICDefaultFormatConverter,
763         "WIC Default Format Converter",
764         NULL,
765         "windowscodecs.dll",
766         "Apartment"
767     },
768     { NULL }                    /* list terminator */
769 };
770
771 /***********************************************************************
772  *              decoder list
773  */
774 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff};
775
776 static const BYTE bmp_magic[] = {0x42,0x4d};
777
778 static GUID const * const bmp_formats[] = {
779     &GUID_WICPixelFormat1bppIndexed,
780     &GUID_WICPixelFormat2bppIndexed,
781     &GUID_WICPixelFormat4bppIndexed,
782     &GUID_WICPixelFormat8bppIndexed,
783     &GUID_WICPixelFormat16bppBGR555,
784     &GUID_WICPixelFormat16bppBGR565,
785     &GUID_WICPixelFormat24bppBGR,
786     &GUID_WICPixelFormat32bppBGR,
787     &GUID_WICPixelFormat32bppBGRA,
788     NULL
789 };
790
791 static struct decoder_pattern const bmp_patterns[] = {
792     {2,0,bmp_magic,mask_all,0},
793     {0}
794 };
795
796 static const BYTE gif87a_magic[6] = "GIF87a";
797 static const BYTE gif89a_magic[6] = "GIF89a";
798
799 static GUID const * const gif_formats[] = {
800     &GUID_WICPixelFormat8bppIndexed,
801     NULL
802 };
803
804 static struct decoder_pattern const gif_patterns[] = {
805     {6,0,gif87a_magic,mask_all,0},
806     {6,0,gif89a_magic,mask_all,0},
807     {0}
808 };
809
810 static const BYTE ico_magic[] = {00,00,01,00};
811
812 static GUID const * const ico_formats[] = {
813     &GUID_WICPixelFormat32bppBGRA,
814     NULL
815 };
816
817 static struct decoder_pattern const ico_patterns[] = {
818     {4,0,ico_magic,mask_all,0},
819     {0}
820 };
821
822 static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
823
824 static GUID const * const jpeg_formats[] = {
825     &GUID_WICPixelFormat24bppBGR,
826     &GUID_WICPixelFormat8bppGray,
827     NULL
828 };
829
830 static struct decoder_pattern const jpeg_patterns[] = {
831     {4,0,jpeg_magic,mask_all,0},
832     {0}
833 };
834
835 static struct regsvr_decoder const decoder_list[] = {
836     {   &CLSID_WICBmpDecoder,
837         "The Wine Project",
838         "BMP Decoder",
839         "1.0.0.0",
840         &GUID_VendorMicrosoft,
841         "image/bmp",
842         ".bmp,.dib,.rle",
843         bmp_formats,
844         bmp_patterns
845     },
846     {   &CLSID_WICGifDecoder,
847         "The Wine Project",
848         "GIF Decoder",
849         "1.0.0.0",
850         &GUID_VendorMicrosoft,
851         "image/gif",
852         ".gif",
853         gif_formats,
854         gif_patterns
855     },
856     {   &CLSID_WICIcoDecoder,
857         "The Wine Project",
858         "ICO Decoder",
859         "1.0.0.0",
860         &GUID_VendorMicrosoft,
861         "image/vnd.microsoft.icon",
862         ".ico",
863         ico_formats,
864         ico_patterns
865     },
866     {   &CLSID_WICJpegDecoder,
867         "The Wine Project",
868         "JPEG Decoder",
869         "1.0.0.0",
870         &GUID_VendorMicrosoft,
871         "image/jpeg",
872         ".jpg;.jpeg;.jfif",
873         jpeg_formats,
874         jpeg_patterns
875     },
876     { NULL }                    /* list terminator */
877 };
878
879 static GUID const * const converter_formats[] = {
880     &GUID_WICPixelFormat1bppIndexed,
881     &GUID_WICPixelFormat4bppIndexed,
882     &GUID_WICPixelFormat8bppIndexed,
883     &GUID_WICPixelFormat8bppGray,
884     &GUID_WICPixelFormat16bppBGR555,
885     &GUID_WICPixelFormat16bppBGR565,
886     &GUID_WICPixelFormat24bppBGR,
887     &GUID_WICPixelFormat32bppBGR,
888     &GUID_WICPixelFormat32bppBGRA,
889     NULL
890 };
891
892 static struct regsvr_converter const converter_list[] = {
893     {   &CLSID_WICDefaultFormatConverter,
894         "The Wine Project",
895         "Default Pixel Format Converter",
896         "1.0.0.0",
897         &GUID_VendorMicrosoft,
898         converter_formats
899     },
900     { NULL }                    /* list terminator */
901 };
902
903 HRESULT WINAPI DllRegisterServer(void)
904 {
905     HRESULT hr;
906
907     TRACE("\n");
908
909     hr = register_coclasses(coclass_list);
910     if (SUCCEEDED(hr))
911         register_decoders(decoder_list);
912     if (SUCCEEDED(hr))
913         register_converters(converter_list);
914     return hr;
915 }
916
917 HRESULT WINAPI DllUnregisterServer(void)
918 {
919     HRESULT hr;
920
921     TRACE("\n");
922
923     hr = unregister_coclasses(coclass_list);
924     if (SUCCEEDED(hr))
925         unregister_decoders(decoder_list);
926     if (SUCCEEDED(hr))
927         unregister_converters(converter_list);
928     return hr;
929 }