shell32/tests: Fix test_one_cmdline() and add a few more tests.
[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 #include "wincodecsdk.h"
36
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39
40 #include "wincodecs_private.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
43
44 /***********************************************************************
45  *              interface for self-registering
46  */
47 struct decoder_pattern
48 {
49     DWORD length;    /* 0 for end of list */
50     DWORD position;
51     const BYTE *pattern;
52     const BYTE *mask;
53     DWORD endofstream;
54 };
55
56 struct regsvr_decoder
57 {
58     CLSID const *clsid;         /* NULL for end of list */
59     LPCSTR author;
60     LPCSTR friendlyname;
61     LPCSTR version;
62     GUID const *vendor;
63     GUID const *container_format;
64     LPCSTR mimetypes;
65     LPCSTR extensions;
66     GUID const * const *formats;
67     const struct decoder_pattern *patterns;
68 };
69
70 static HRESULT register_decoders(struct regsvr_decoder const *list);
71 static HRESULT unregister_decoders(struct regsvr_decoder const *list);
72
73 struct regsvr_encoder
74 {
75     CLSID const *clsid;         /* NULL for end of list */
76     LPCSTR author;
77     LPCSTR friendlyname;
78     LPCSTR version;
79     GUID const *vendor;
80     GUID const *container_format;
81     LPCSTR mimetypes;
82     LPCSTR extensions;
83     GUID const * const *formats;
84 };
85
86 static HRESULT register_encoders(struct regsvr_encoder const *list);
87 static HRESULT unregister_encoders(struct regsvr_encoder const *list);
88
89 struct regsvr_converter
90 {
91     CLSID const *clsid;         /* NULL for end of list */
92     LPCSTR author;
93     LPCSTR friendlyname;
94     LPCSTR version;
95     GUID const *vendor;
96     GUID const * const *formats;
97 };
98
99 static HRESULT register_converters(struct regsvr_converter const *list);
100 static HRESULT unregister_converters(struct regsvr_converter const *list);
101
102 struct metadata_pattern
103 {
104     DWORD position;
105     DWORD length;
106     const BYTE *pattern;
107     const BYTE *mask;
108     DWORD data_offset;
109 };
110
111 struct reader_containers
112 {
113     GUID const *format;
114     const struct metadata_pattern *patterns;
115 };
116
117 struct regsvr_metadatareader
118 {
119     CLSID const *clsid;         /* NULL for end of list */
120     LPCSTR author;
121     LPCSTR friendlyname;
122     LPCSTR version;
123     LPCSTR specversion;
124     GUID const *vendor;
125     GUID const *metadata_format;
126     DWORD requires_fullstream;
127     DWORD supports_padding;
128     DWORD requires_fixedsize;
129     const struct reader_containers *containers;
130 };
131
132 static HRESULT register_metadatareaders(struct regsvr_metadatareader const *list);
133 static HRESULT unregister_metadatareaders(struct regsvr_metadatareader const *list);
134
135 struct regsvr_pixelformat
136 {
137     CLSID const *clsid;         /* NULL for end of list */
138     LPCSTR author;
139     LPCSTR friendlyname;
140     LPCSTR version;
141     GUID const *vendor;
142     UINT bitsperpixel;
143     UINT channelcount;
144     BYTE const * const *channelmasks;
145     WICPixelFormatNumericRepresentation numericrepresentation;
146     UINT supportsalpha;
147 };
148
149 static HRESULT register_pixelformats(struct regsvr_pixelformat const *list);
150 static HRESULT unregister_pixelformats(struct regsvr_pixelformat const *list);
151
152 /***********************************************************************
153  *              static string constants
154  */
155 static const WCHAR clsid_keyname[] = {
156     'C', 'L', 'S', 'I', 'D', 0 };
157 static const WCHAR curver_keyname[] = {
158     'C', 'u', 'r', 'V', 'e', 'r', 0 };
159 static const WCHAR ips_keyname[] = {
160     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
161     0 };
162 static const WCHAR ips32_keyname[] = {
163     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
164     '3', '2', 0 };
165 static const WCHAR progid_keyname[] = {
166     'P', 'r', 'o', 'g', 'I', 'D', 0 };
167 static const WCHAR viprogid_keyname[] = {
168     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
169     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
170     0 };
171 static const char tmodel_valuename[] = "ThreadingModel";
172 static const char author_valuename[] = "Author";
173 static const char friendlyname_valuename[] = "FriendlyName";
174 static const WCHAR vendor_valuename[] = {'V','e','n','d','o','r',0};
175 static const WCHAR containerformat_valuename[] = {'C','o','n','t','a','i','n','e','r','F','o','r','m','a','t',0};
176 static const char version_valuename[] = "Version";
177 static const char mimetypes_valuename[] = "MimeTypes";
178 static const char extensions_valuename[] = "FileExtensions";
179 static const WCHAR formats_keyname[] = {'F','o','r','m','a','t','s',0};
180 static const WCHAR patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
181 static const WCHAR instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
182 static const WCHAR clsid_valuename[] = {'C','L','S','I','D',0};
183 static const char length_valuename[] = "Length";
184 static const char position_valuename[] = "Position";
185 static const char pattern_valuename[] = "Pattern";
186 static const char mask_valuename[] = "Mask";
187 static const char endofstream_valuename[] = "EndOfStream";
188 static const WCHAR pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
189 static const WCHAR metadataformat_valuename[] = {'M','e','t','a','d','a','t','a','F','o','r','m','a','t',0};
190 static const char specversion_valuename[] = "SpecVersion";
191 static const char requiresfullstream_valuename[] = "RequiresFullStream";
192 static const char supportspadding_valuename[] = "SupportsPadding";
193 static const char requiresfixedsize_valuename[] = "FixedSize";
194 static const WCHAR containers_keyname[] = {'C','o','n','t','a','i','n','e','r','s',0};
195 static const char dataoffset_valuename[] = "DataOffset";
196 static const char bitsperpixel_valuename[] = "BitLength";
197 static const char channelcount_valuename[] = "ChannelCount";
198 static const char numericrepresentation_valuename[] = "NumericRepresentation";
199 static const char supportstransparency_valuename[] = "SupportsTransparency";
200 static const WCHAR channelmasks_keyname[] = {'C','h','a','n','n','e','l','M','a','s','k','s',0};
201
202 /***********************************************************************
203  *              register_decoders
204  */
205 static HRESULT register_decoders(struct regsvr_decoder const *list)
206 {
207     LONG res = ERROR_SUCCESS;
208     HKEY coclass_key;
209     WCHAR buf[39];
210     HKEY decoders_key;
211     HKEY instance_key;
212
213     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
214                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
215     if (res == ERROR_SUCCESS)  {
216         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
217         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
218                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
219         if (res == ERROR_SUCCESS)
220         {
221             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
222                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
223             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
224         }
225         if (res != ERROR_SUCCESS)
226             RegCloseKey(coclass_key);
227     }
228     if (res != ERROR_SUCCESS) goto error_return;
229
230     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
231         HKEY clsid_key;
232         HKEY instance_clsid_key;
233
234         StringFromGUID2(list->clsid, buf, 39);
235         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
236                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
237         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
238
239         StringFromGUID2(list->clsid, buf, 39);
240         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
241                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
242         if (res == ERROR_SUCCESS) {
243             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
244                                  (CONST BYTE*)(buf), 78);
245             RegCloseKey(instance_clsid_key);
246         }
247         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
248
249         if (list->author) {
250             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
251                                  (CONST BYTE*)(list->author),
252                                  strlen(list->author) + 1);
253             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
254         }
255
256         if (list->friendlyname) {
257             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
258                                  (CONST BYTE*)(list->friendlyname),
259                                  strlen(list->friendlyname) + 1);
260             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
261         }
262
263         if (list->vendor) {
264             StringFromGUID2(list->vendor, buf, 39);
265             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
266                                  (CONST BYTE*)(buf), 78);
267             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
268         }
269
270         if (list->container_format) {
271             StringFromGUID2(list->container_format, buf, 39);
272             res = RegSetValueExW(clsid_key, containerformat_valuename, 0, REG_SZ,
273                                  (CONST BYTE*)(buf), 78);
274             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
275         }
276
277         if (list->version) {
278             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
279                                  (CONST BYTE*)(list->version),
280                                  strlen(list->version) + 1);
281             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282         }
283
284         if (list->mimetypes) {
285             res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
286                                  (CONST BYTE*)(list->mimetypes),
287                                  strlen(list->mimetypes) + 1);
288             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
289         }
290
291         if (list->extensions) {
292             res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
293                                  (CONST BYTE*)(list->extensions),
294                                  strlen(list->extensions) + 1);
295             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
296         }
297
298         if (list->formats) {
299             HKEY formats_key;
300             GUID const * const *format;
301
302             res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
303                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
304             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
305             for (format=list->formats; *format; ++format)
306             {
307                 HKEY format_key;
308                 StringFromGUID2(*format, buf, 39);
309                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
310                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
311                 if (res != ERROR_SUCCESS) break;
312                 RegCloseKey(format_key);
313             }
314             RegCloseKey(formats_key);
315             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
316         }
317
318         if (list->patterns) {
319             HKEY patterns_key;
320             int i;
321
322             res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
323                                   KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
324             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
325             for (i=0; list->patterns[i].length; i++)
326             {
327                 HKEY pattern_key;
328                 static const WCHAR int_format[] = {'%','i',0};
329                 snprintfW(buf, 39, int_format, i);
330                 res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
331                                       KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
332                 if (res != ERROR_SUCCESS) break;
333                 res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
334                                      (CONST BYTE*)(&list->patterns[i].length), 4);
335                 if (res == ERROR_SUCCESS)
336                     res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
337                                          (CONST BYTE*)(&list->patterns[i].position), 4);
338                 if (res == ERROR_SUCCESS)
339                     res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
340                                          list->patterns[i].pattern,
341                                          list->patterns[i].length);
342                 if (res == ERROR_SUCCESS)
343                     res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
344                                          list->patterns[i].mask,
345                                          list->patterns[i].length);
346                 if (res == ERROR_SUCCESS)
347                     res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
348                                          (CONST BYTE*)&(list->patterns[i].endofstream), 4);
349                 RegCloseKey(pattern_key);
350             }
351             RegCloseKey(patterns_key);
352             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
353         }
354
355     error_close_clsid_key:
356         RegCloseKey(clsid_key);
357     }
358
359 error_close_coclass_key:
360     RegCloseKey(instance_key);
361     RegCloseKey(decoders_key);
362     RegCloseKey(coclass_key);
363 error_return:
364     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
365 }
366
367 /***********************************************************************
368  *              unregister_decoders
369  */
370 static HRESULT unregister_decoders(struct regsvr_decoder const *list)
371 {
372     LONG res = ERROR_SUCCESS;
373     HKEY coclass_key;
374     WCHAR buf[39];
375     HKEY decoders_key;
376     HKEY instance_key;
377
378     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
379                         KEY_READ | KEY_WRITE, &coclass_key);
380     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
381
382     if (res == ERROR_SUCCESS)  {
383         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
384         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
385                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
386         if (res == ERROR_SUCCESS)
387         {
388             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
389                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
390             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
391         }
392         if (res != ERROR_SUCCESS)
393             RegCloseKey(coclass_key);
394     }
395     if (res != ERROR_SUCCESS) goto error_return;
396
397     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
398         StringFromGUID2(list->clsid, buf, 39);
399
400         res = RegDeleteTreeW(coclass_key, buf);
401         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
402         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
403
404         res = RegDeleteTreeW(instance_key, buf);
405         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
406         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
407     }
408
409 error_close_coclass_key:
410     RegCloseKey(instance_key);
411     RegCloseKey(decoders_key);
412     RegCloseKey(coclass_key);
413 error_return:
414     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
415 }
416
417 /***********************************************************************
418  *              register_encoders
419  */
420 static HRESULT register_encoders(struct regsvr_encoder const *list)
421 {
422     LONG res = ERROR_SUCCESS;
423     HKEY coclass_key;
424     WCHAR buf[39];
425     HKEY encoders_key;
426     HKEY instance_key;
427
428     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
429                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
430     if (res == ERROR_SUCCESS)  {
431         StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
432         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
433                               KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
434         if (res == ERROR_SUCCESS)
435         {
436             res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
437                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
438             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
439         }
440         if (res != ERROR_SUCCESS)
441             RegCloseKey(coclass_key);
442     }
443     if (res != ERROR_SUCCESS) goto error_return;
444
445     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
446         HKEY clsid_key;
447         HKEY instance_clsid_key;
448
449         StringFromGUID2(list->clsid, buf, 39);
450         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
451                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
452         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
453
454         StringFromGUID2(list->clsid, buf, 39);
455         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
456                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
457         if (res == ERROR_SUCCESS) {
458             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
459                                  (CONST BYTE*)(buf), 78);
460             RegCloseKey(instance_clsid_key);
461         }
462         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
463
464         if (list->author) {
465             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
466                                  (CONST BYTE*)(list->author),
467                                  strlen(list->author) + 1);
468             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
469         }
470
471         if (list->friendlyname) {
472             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
473                                  (CONST BYTE*)(list->friendlyname),
474                                  strlen(list->friendlyname) + 1);
475             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
476         }
477
478         if (list->vendor) {
479             StringFromGUID2(list->vendor, buf, 39);
480             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
481                                  (CONST BYTE*)(buf), 78);
482             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
483         }
484
485         if (list->container_format) {
486             StringFromGUID2(list->container_format, buf, 39);
487             res = RegSetValueExW(clsid_key, containerformat_valuename, 0, REG_SZ,
488                                  (CONST BYTE*)(buf), 78);
489             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
490         }
491
492         if (list->version) {
493             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
494                                  (CONST BYTE*)(list->version),
495                                  strlen(list->version) + 1);
496             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
497         }
498
499         if (list->mimetypes) {
500             res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
501                                  (CONST BYTE*)(list->mimetypes),
502                                  strlen(list->mimetypes) + 1);
503             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
504         }
505
506         if (list->extensions) {
507             res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
508                                  (CONST BYTE*)(list->extensions),
509                                  strlen(list->extensions) + 1);
510             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
511         }
512
513         if (list->formats) {
514             HKEY formats_key;
515             GUID const * const *format;
516
517             res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
518                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
519             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
520             for (format=list->formats; *format; ++format)
521             {
522                 HKEY format_key;
523                 StringFromGUID2(*format, buf, 39);
524                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
525                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
526                 if (res != ERROR_SUCCESS) break;
527                 RegCloseKey(format_key);
528             }
529             RegCloseKey(formats_key);
530             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
531         }
532
533     error_close_clsid_key:
534         RegCloseKey(clsid_key);
535     }
536
537 error_close_coclass_key:
538     RegCloseKey(instance_key);
539     RegCloseKey(encoders_key);
540     RegCloseKey(coclass_key);
541 error_return:
542     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
543 }
544
545 /***********************************************************************
546  *              unregister_encoders
547  */
548 static HRESULT unregister_encoders(struct regsvr_encoder const *list)
549 {
550     LONG res = ERROR_SUCCESS;
551     HKEY coclass_key;
552     WCHAR buf[39];
553     HKEY encoders_key;
554     HKEY instance_key;
555
556     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
557                         KEY_READ | KEY_WRITE, &coclass_key);
558     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
559
560     if (res == ERROR_SUCCESS)  {
561         StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
562         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
563                               KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
564         if (res == ERROR_SUCCESS)
565         {
566             res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
567                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
568             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
569         }
570         if (res != ERROR_SUCCESS)
571             RegCloseKey(coclass_key);
572     }
573     if (res != ERROR_SUCCESS) goto error_return;
574
575     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
576         StringFromGUID2(list->clsid, buf, 39);
577
578         res = RegDeleteTreeW(coclass_key, buf);
579         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
580         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
581
582         res = RegDeleteTreeW(instance_key, buf);
583         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
584         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
585     }
586
587 error_close_coclass_key:
588     RegCloseKey(instance_key);
589     RegCloseKey(encoders_key);
590     RegCloseKey(coclass_key);
591 error_return:
592     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
593 }
594
595 /***********************************************************************
596  *              register_converters
597  */
598 static HRESULT register_converters(struct regsvr_converter const *list)
599 {
600     LONG res = ERROR_SUCCESS;
601     HKEY coclass_key;
602     WCHAR buf[39];
603     HKEY converters_key;
604     HKEY instance_key;
605
606     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
607                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
608     if (res == ERROR_SUCCESS)  {
609         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
610         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
611                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
612         if (res == ERROR_SUCCESS)
613         {
614             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
615                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
616             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
617         }
618         if (res != ERROR_SUCCESS)
619             RegCloseKey(coclass_key);
620     }
621     if (res != ERROR_SUCCESS) goto error_return;
622
623     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
624         HKEY clsid_key;
625         HKEY instance_clsid_key;
626
627         StringFromGUID2(list->clsid, buf, 39);
628         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
629                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
630         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
631
632         StringFromGUID2(list->clsid, buf, 39);
633         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
634                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
635         if (res == ERROR_SUCCESS) {
636             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
637                                  (CONST BYTE*)(buf), 78);
638             RegCloseKey(instance_clsid_key);
639         }
640         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
641
642         if (list->author) {
643             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
644                                  (CONST BYTE*)(list->author),
645                                  strlen(list->author) + 1);
646             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
647         }
648
649         if (list->friendlyname) {
650             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
651                                  (CONST BYTE*)(list->friendlyname),
652                                  strlen(list->friendlyname) + 1);
653             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
654         }
655
656         if (list->vendor) {
657             StringFromGUID2(list->vendor, buf, 39);
658             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
659                                  (CONST BYTE*)(buf), 78);
660             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
661         }
662
663         if (list->version) {
664             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
665                                  (CONST BYTE*)(list->version),
666                                  strlen(list->version) + 1);
667             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
668         }
669
670         if (list->formats) {
671             HKEY formats_key;
672             GUID const * const *format;
673
674             res = RegCreateKeyExW(clsid_key, pixelformats_keyname, 0, NULL, 0,
675                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
676             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
677             for (format=list->formats; *format; ++format)
678             {
679                 HKEY format_key;
680                 StringFromGUID2(*format, buf, 39);
681                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
682                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
683                 if (res != ERROR_SUCCESS) break;
684                 RegCloseKey(format_key);
685             }
686             RegCloseKey(formats_key);
687             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
688         }
689
690     error_close_clsid_key:
691         RegCloseKey(clsid_key);
692     }
693
694 error_close_coclass_key:
695     RegCloseKey(instance_key);
696     RegCloseKey(converters_key);
697     RegCloseKey(coclass_key);
698 error_return:
699     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
700 }
701
702 /***********************************************************************
703  *              unregister_converters
704  */
705 static HRESULT unregister_converters(struct regsvr_converter const *list)
706 {
707     LONG res = ERROR_SUCCESS;
708     HKEY coclass_key;
709     WCHAR buf[39];
710     HKEY converters_key;
711     HKEY instance_key;
712
713     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
714                         KEY_READ | KEY_WRITE, &coclass_key);
715     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
716
717     if (res == ERROR_SUCCESS)  {
718         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
719         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
720                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
721         if (res == ERROR_SUCCESS)
722         {
723             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
724                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
725             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
726         }
727         if (res != ERROR_SUCCESS)
728             RegCloseKey(coclass_key);
729     }
730     if (res != ERROR_SUCCESS) goto error_return;
731
732     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
733         StringFromGUID2(list->clsid, buf, 39);
734
735         res = RegDeleteTreeW(coclass_key, buf);
736         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
737         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
738
739         res = RegDeleteTreeW(instance_key, buf);
740         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
741         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
742     }
743
744 error_close_coclass_key:
745     RegCloseKey(instance_key);
746     RegCloseKey(converters_key);
747     RegCloseKey(coclass_key);
748 error_return:
749     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
750 }
751
752 /***********************************************************************
753  *              register_metadatareaders
754  */
755 static HRESULT register_metadatareaders(struct regsvr_metadatareader const *list)
756 {
757     LONG res = ERROR_SUCCESS;
758     HKEY coclass_key;
759     WCHAR buf[39];
760     HKEY readers_key;
761     HKEY instance_key;
762
763     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
764                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
765     if (res == ERROR_SUCCESS)  {
766         StringFromGUID2(&CATID_WICMetadataReader, buf, 39);
767         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
768                               KEY_READ | KEY_WRITE, NULL, &readers_key, NULL);
769         if (res == ERROR_SUCCESS)
770         {
771             res = RegCreateKeyExW(readers_key, instance_keyname, 0, NULL, 0,
772                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
773             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
774         }
775         if (res != ERROR_SUCCESS)
776             RegCloseKey(coclass_key);
777     }
778     if (res != ERROR_SUCCESS) goto error_return;
779
780     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
781         HKEY clsid_key;
782         HKEY instance_clsid_key;
783
784         StringFromGUID2(list->clsid, buf, 39);
785         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
786                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
787         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
788
789         StringFromGUID2(list->clsid, buf, 39);
790         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
791                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
792         if (res == ERROR_SUCCESS) {
793             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
794                                  (CONST BYTE*)(buf), 78);
795             RegCloseKey(instance_clsid_key);
796         }
797         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
798
799         if (list->author) {
800             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
801                                  (CONST BYTE*)(list->author),
802                                  strlen(list->author) + 1);
803             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
804         }
805
806         if (list->friendlyname) {
807             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
808                                  (CONST BYTE*)(list->friendlyname),
809                                  strlen(list->friendlyname) + 1);
810             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
811         }
812
813         if (list->vendor) {
814             StringFromGUID2(list->vendor, buf, 39);
815             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
816                                  (CONST BYTE*)(buf), 78);
817             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
818         }
819
820         if (list->vendor) {
821             StringFromGUID2(list->metadata_format, buf, 39);
822             res = RegSetValueExW(clsid_key, metadataformat_valuename, 0, REG_SZ,
823                                  (CONST BYTE*)(buf), 78);
824             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
825         }
826
827         if (list->version) {
828             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
829                                  (CONST BYTE*)(list->version),
830                                  strlen(list->version) + 1);
831             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
832         }
833
834         if (list->specversion) {
835             res = RegSetValueExA(clsid_key, specversion_valuename, 0, REG_SZ,
836                                  (CONST BYTE*)(list->version),
837                                  strlen(list->version) + 1);
838             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
839         }
840
841         res = RegSetValueExA(clsid_key, requiresfullstream_valuename, 0, REG_DWORD,
842                              (CONST BYTE*)(&list->requires_fullstream), 4);
843         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
844
845         res = RegSetValueExA(clsid_key, supportspadding_valuename, 0, REG_DWORD,
846                              (CONST BYTE*)(&list->supports_padding), 4);
847         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
848
849         if (list->requires_fixedsize) {
850             res = RegSetValueExA(clsid_key, requiresfixedsize_valuename, 0, REG_DWORD,
851                                  (CONST BYTE*)(&list->requires_fixedsize), 4);
852             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
853         }
854
855         if (list->containers) {
856             HKEY containers_key;
857             const struct reader_containers *container;
858
859             res = RegCreateKeyExW(clsid_key, containers_keyname, 0, NULL, 0,
860                                   KEY_READ | KEY_WRITE, NULL, &containers_key, NULL);
861             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
862             for (container=list->containers; container->format; ++container)
863             {
864                 HKEY format_key;
865                 int i;
866                 StringFromGUID2(container->format, buf, 39);
867                 res = RegCreateKeyExW(containers_key, buf, 0, NULL, 0,
868                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
869                 if (res != ERROR_SUCCESS) break;
870
871                 for (i=0; container->patterns[i].length; i++)
872                 {
873                     HKEY pattern_key;
874                     static const WCHAR int_format[] = {'%','i',0};
875                     snprintfW(buf, 39, int_format, i);
876                     res = RegCreateKeyExW(format_key, buf, 0, NULL, 0,
877                                           KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
878                     if (res != ERROR_SUCCESS) break;
879                     res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
880                                          (CONST BYTE*)(&container->patterns[i].position), 4);
881                     if (res == ERROR_SUCCESS)
882                         res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
883                                              container->patterns[i].pattern,
884                                              container->patterns[i].length);
885                     if (res == ERROR_SUCCESS)
886                         res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
887                                              container->patterns[i].mask,
888                                              container->patterns[i].length);
889                     if (res == ERROR_SUCCESS && container->patterns[i].data_offset)
890                         res = RegSetValueExA(pattern_key, dataoffset_valuename, 0, REG_DWORD,
891                                              (CONST BYTE*)&(container->patterns[i].data_offset), 4);
892                     RegCloseKey(pattern_key);
893                 }
894
895                 RegCloseKey(format_key);
896             }
897             RegCloseKey(containers_key);
898         }
899
900     error_close_clsid_key:
901         RegCloseKey(clsid_key);
902     }
903
904 error_close_coclass_key:
905     RegCloseKey(instance_key);
906     RegCloseKey(readers_key);
907     RegCloseKey(coclass_key);
908 error_return:
909     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
910 }
911
912 /***********************************************************************
913  *              unregister_metadatareaders
914  */
915 static HRESULT unregister_metadatareaders(struct regsvr_metadatareader const *list)
916 {
917     LONG res = ERROR_SUCCESS;
918     HKEY coclass_key;
919     WCHAR buf[39];
920     HKEY readers_key;
921     HKEY instance_key;
922
923     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
924                         KEY_READ | KEY_WRITE, &coclass_key);
925     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
926
927     if (res == ERROR_SUCCESS)  {
928         StringFromGUID2(&CATID_WICMetadataReader, buf, 39);
929         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
930                               KEY_READ | KEY_WRITE, NULL, &readers_key, NULL);
931         if (res == ERROR_SUCCESS)
932         {
933             res = RegCreateKeyExW(readers_key, instance_keyname, 0, NULL, 0,
934                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
935             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
936         }
937         if (res != ERROR_SUCCESS)
938             RegCloseKey(coclass_key);
939     }
940     if (res != ERROR_SUCCESS) goto error_return;
941
942     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
943         StringFromGUID2(list->clsid, buf, 39);
944
945         res = RegDeleteTreeW(coclass_key, buf);
946         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
947         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
948
949         res = RegDeleteTreeW(instance_key, buf);
950         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
951         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
952     }
953
954 error_close_coclass_key:
955     RegCloseKey(instance_key);
956     RegCloseKey(readers_key);
957     RegCloseKey(coclass_key);
958 error_return:
959     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
960 }
961
962 /***********************************************************************
963  *                register_pixelformats
964  */
965 static HRESULT register_pixelformats(struct regsvr_pixelformat const *list)
966 {
967     LONG res = ERROR_SUCCESS;
968     HKEY coclass_key;
969     WCHAR buf[39];
970     HKEY formats_key;
971     HKEY instance_key;
972
973     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
974                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
975     if (res == ERROR_SUCCESS)  {
976         StringFromGUID2(&CATID_WICPixelFormats, buf, 39);
977         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
978                               KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
979         if (res == ERROR_SUCCESS)
980         {
981             res = RegCreateKeyExW(formats_key, instance_keyname, 0, NULL, 0,
982                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
983             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
984         }
985         if (res != ERROR_SUCCESS)
986             RegCloseKey(coclass_key);
987     }
988     if (res != ERROR_SUCCESS) goto error_return;
989
990     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
991         HKEY clsid_key;
992         HKEY instance_clsid_key;
993
994         StringFromGUID2(list->clsid, buf, 39);
995         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
996                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
997         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
998
999         StringFromGUID2(list->clsid, buf, 39);
1000         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
1001                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
1002         if (res == ERROR_SUCCESS) {
1003             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
1004                                  (CONST BYTE*)(buf), 78);
1005             RegCloseKey(instance_clsid_key);
1006         }
1007         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1008
1009         if (list->author) {
1010             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
1011                                  (CONST BYTE*)(list->author),
1012                                  strlen(list->author) + 1);
1013             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1014         }
1015
1016         if (list->friendlyname) {
1017             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
1018                                  (CONST BYTE*)(list->friendlyname),
1019                                  strlen(list->friendlyname) + 1);
1020             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1021         }
1022
1023         if (list->vendor) {
1024             StringFromGUID2(list->vendor, buf, 39);
1025             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
1026                                  (CONST BYTE*)(buf), 78);
1027             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1028         }
1029
1030         if (list->version) {
1031             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
1032                                  (CONST BYTE*)(list->version),
1033                                  strlen(list->version) + 1);
1034             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1035         }
1036
1037         res = RegSetValueExA(clsid_key, bitsperpixel_valuename, 0, REG_DWORD,
1038                              (CONST BYTE*)(&list->bitsperpixel), 4);
1039         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1040
1041         res = RegSetValueExA(clsid_key, channelcount_valuename, 0, REG_DWORD,
1042                              (CONST BYTE*)(&list->channelcount), 4);
1043         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1044
1045         res = RegSetValueExA(clsid_key, numericrepresentation_valuename, 0, REG_DWORD,
1046                              (CONST BYTE*)(&list->numericrepresentation), 4);
1047         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1048
1049         res = RegSetValueExA(clsid_key, supportstransparency_valuename, 0, REG_DWORD,
1050                              (CONST BYTE*)(&list->supportsalpha), 4);
1051         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1052
1053         if (list->channelmasks) {
1054             HKEY masks_key;
1055             UINT i, mask_size;
1056             WCHAR mask_valuename[11];
1057             const WCHAR valuename_format[] = {'%','d',0};
1058
1059             mask_size = (list->bitsperpixel + 7)/8;
1060
1061             res = RegCreateKeyExW(clsid_key, channelmasks_keyname, 0, NULL, 0,
1062                                   KEY_READ | KEY_WRITE, NULL, &masks_key, NULL);
1063             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1064             for (i=0; i < list->channelcount; i++)
1065             {
1066                 sprintfW(mask_valuename, valuename_format, i);
1067                 res = RegSetValueExW(masks_key, mask_valuename, 0, REG_BINARY,
1068                                      list->channelmasks[i], mask_size);
1069                 if (res != ERROR_SUCCESS) break;
1070             }
1071             RegCloseKey(masks_key);
1072             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
1073         }
1074
1075     error_close_clsid_key:
1076         RegCloseKey(clsid_key);
1077     }
1078
1079 error_close_coclass_key:
1080     RegCloseKey(instance_key);
1081     RegCloseKey(formats_key);
1082     RegCloseKey(coclass_key);
1083 error_return:
1084     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
1085 }
1086
1087 /***********************************************************************
1088  *                unregister_pixelformats
1089  */
1090 static HRESULT unregister_pixelformats(struct regsvr_pixelformat const *list)
1091 {
1092     LONG res = ERROR_SUCCESS;
1093     HKEY coclass_key;
1094     WCHAR buf[39];
1095     HKEY formats_key;
1096     HKEY instance_key;
1097
1098     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
1099                         KEY_READ | KEY_WRITE, &coclass_key);
1100     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
1101
1102     if (res == ERROR_SUCCESS)  {
1103         StringFromGUID2(&CATID_WICPixelFormats, buf, 39);
1104         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
1105                               KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
1106         if (res == ERROR_SUCCESS)
1107         {
1108             res = RegCreateKeyExW(formats_key, instance_keyname, 0, NULL, 0,
1109                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
1110             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
1111         }
1112         if (res != ERROR_SUCCESS)
1113             RegCloseKey(coclass_key);
1114     }
1115     if (res != ERROR_SUCCESS) goto error_return;
1116
1117     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
1118         StringFromGUID2(list->clsid, buf, 39);
1119
1120         res = RegDeleteTreeW(coclass_key, buf);
1121         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
1122         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
1123
1124         res = RegDeleteTreeW(instance_key, buf);
1125         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
1126         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
1127     }
1128
1129 error_close_coclass_key:
1130     RegCloseKey(instance_key);
1131     RegCloseKey(formats_key);
1132     RegCloseKey(coclass_key);
1133 error_return:
1134     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
1135 }
1136
1137 /***********************************************************************
1138  *              decoder list
1139  */
1140 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
1141
1142 static const BYTE bmp_magic[] = {0x42,0x4d};
1143
1144 static GUID const * const bmp_formats[] = {
1145     &GUID_WICPixelFormat1bppIndexed,
1146     &GUID_WICPixelFormat2bppIndexed,
1147     &GUID_WICPixelFormat4bppIndexed,
1148     &GUID_WICPixelFormat8bppIndexed,
1149     &GUID_WICPixelFormat16bppBGR555,
1150     &GUID_WICPixelFormat16bppBGR565,
1151     &GUID_WICPixelFormat24bppBGR,
1152     &GUID_WICPixelFormat32bppBGR,
1153     &GUID_WICPixelFormat32bppBGRA,
1154     NULL
1155 };
1156
1157 static struct decoder_pattern const bmp_patterns[] = {
1158     {2,0,bmp_magic,mask_all,0},
1159     {0}
1160 };
1161
1162 static const BYTE gif87a_magic[6] = "GIF87a";
1163 static const BYTE gif89a_magic[6] = "GIF89a";
1164
1165 static GUID const * const gif_formats[] = {
1166     &GUID_WICPixelFormat8bppIndexed,
1167     NULL
1168 };
1169
1170 static struct decoder_pattern const gif_patterns[] = {
1171     {6,0,gif87a_magic,mask_all,0},
1172     {6,0,gif89a_magic,mask_all,0},
1173     {0}
1174 };
1175
1176 static const BYTE ico_magic[] = {00,00,01,00};
1177
1178 static GUID const * const ico_formats[] = {
1179     &GUID_WICPixelFormat32bppBGRA,
1180     NULL
1181 };
1182
1183 static struct decoder_pattern const ico_patterns[] = {
1184     {4,0,ico_magic,mask_all,0},
1185     {0}
1186 };
1187
1188 static const BYTE jpeg_magic[] = {0xff, 0xd8};
1189
1190 static GUID const * const jpeg_formats[] = {
1191     &GUID_WICPixelFormat24bppBGR,
1192     &GUID_WICPixelFormat32bppCMYK,
1193     &GUID_WICPixelFormat8bppGray,
1194     NULL
1195 };
1196
1197 static struct decoder_pattern const jpeg_patterns[] = {
1198     {2,0,jpeg_magic,mask_all,0},
1199     {0}
1200 };
1201
1202 static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
1203
1204 static GUID const * const png_formats[] = {
1205     &GUID_WICPixelFormatBlackWhite,
1206     &GUID_WICPixelFormat2bppGray,
1207     &GUID_WICPixelFormat4bppGray,
1208     &GUID_WICPixelFormat8bppGray,
1209     &GUID_WICPixelFormat16bppGray,
1210     &GUID_WICPixelFormat32bppBGRA,
1211     &GUID_WICPixelFormat64bppRGBA,
1212     &GUID_WICPixelFormat1bppIndexed,
1213     &GUID_WICPixelFormat2bppIndexed,
1214     &GUID_WICPixelFormat4bppIndexed,
1215     &GUID_WICPixelFormat8bppIndexed,
1216     &GUID_WICPixelFormat24bppBGR,
1217     &GUID_WICPixelFormat48bppRGB,
1218     NULL
1219 };
1220
1221 static struct decoder_pattern const png_patterns[] = {
1222     {8,0,png_magic,mask_all,0},
1223     {0}
1224 };
1225
1226 static const BYTE tiff_magic_le[] = {0x49,0x49,42,0};
1227 static const BYTE tiff_magic_be[] = {0x4d,0x4d,0,42};
1228
1229 static GUID const * const tiff_decode_formats[] = {
1230     &GUID_WICPixelFormatBlackWhite,
1231     &GUID_WICPixelFormat4bppGray,
1232     &GUID_WICPixelFormat8bppGray,
1233     &GUID_WICPixelFormat4bppIndexed,
1234     &GUID_WICPixelFormat8bppIndexed,
1235     &GUID_WICPixelFormat24bppBGR,
1236     &GUID_WICPixelFormat32bppBGR,
1237     &GUID_WICPixelFormat32bppBGRA,
1238     &GUID_WICPixelFormat32bppPBGRA,
1239     &GUID_WICPixelFormat48bppRGB,
1240     &GUID_WICPixelFormat64bppRGBA,
1241     &GUID_WICPixelFormat64bppPRGBA,
1242     NULL
1243 };
1244
1245 static struct decoder_pattern const tiff_patterns[] = {
1246     {4,0,tiff_magic_le,mask_all,0},
1247     {4,0,tiff_magic_be,mask_all,0},
1248     {0}
1249 };
1250
1251 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
1252
1253 static const BYTE tga_indexed_magic[18] = {0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0};
1254 static const BYTE tga_indexed_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff,0xcf};
1255
1256 static const BYTE tga_truecolor_magic[18] = {0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1257 static const BYTE tga_truecolor_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0x87,0xc0};
1258
1259 static const BYTE tga_grayscale_magic[18] = {0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0};
1260 static const BYTE tga_grayscale_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff,0xcf};
1261
1262 static GUID const * const tga_formats[] = {
1263     &GUID_WICPixelFormat8bppGray,
1264     &GUID_WICPixelFormat8bppIndexed,
1265     &GUID_WICPixelFormat16bppGray,
1266     &GUID_WICPixelFormat16bppBGR555,
1267     &GUID_WICPixelFormat24bppBGR,
1268     &GUID_WICPixelFormat32bppBGRA,
1269     &GUID_WICPixelFormat32bppPBGRA,
1270     NULL
1271 };
1272
1273 static struct decoder_pattern const tga_patterns[] = {
1274     {18,18,tga_footer_magic,mask_all,1},
1275     {18,0,tga_indexed_magic,tga_indexed_mask,0},
1276     {18,0,tga_truecolor_magic,tga_truecolor_mask,0},
1277     {18,0,tga_grayscale_magic,tga_grayscale_mask,0},
1278     {0}
1279 };
1280
1281 static struct regsvr_decoder const decoder_list[] = {
1282     {   &CLSID_WICBmpDecoder,
1283         "The Wine Project",
1284         "BMP Decoder",
1285         "1.0.0.0",
1286         &GUID_VendorMicrosoft,
1287         &GUID_ContainerFormatBmp,
1288         "image/bmp",
1289         ".bmp,.dib,.rle",
1290         bmp_formats,
1291         bmp_patterns
1292     },
1293     {   &CLSID_WICGifDecoder,
1294         "The Wine Project",
1295         "GIF Decoder",
1296         "1.0.0.0",
1297         &GUID_VendorMicrosoft,
1298         &GUID_ContainerFormatGif,
1299         "image/gif",
1300         ".gif",
1301         gif_formats,
1302         gif_patterns
1303     },
1304     {   &CLSID_WICIcoDecoder,
1305         "The Wine Project",
1306         "ICO Decoder",
1307         "1.0.0.0",
1308         &GUID_VendorMicrosoft,
1309         &GUID_ContainerFormatIco,
1310         "image/vnd.microsoft.icon",
1311         ".ico",
1312         ico_formats,
1313         ico_patterns
1314     },
1315     {   &CLSID_WICJpegDecoder,
1316         "The Wine Project",
1317         "JPEG Decoder",
1318         "1.0.0.0",
1319         &GUID_VendorMicrosoft,
1320         &GUID_ContainerFormatJpeg,
1321         "image/jpeg",
1322         ".jpg;.jpeg;.jfif",
1323         jpeg_formats,
1324         jpeg_patterns
1325     },
1326     {   &CLSID_WICPngDecoder,
1327         "The Wine Project",
1328         "PNG Decoder",
1329         "1.0.0.0",
1330         &GUID_VendorMicrosoft,
1331         &GUID_ContainerFormatPng,
1332         "image/png",
1333         ".png",
1334         png_formats,
1335         png_patterns
1336     },
1337     {   &CLSID_WICTiffDecoder,
1338         "The Wine Project",
1339         "TIFF Decoder",
1340         "1.0.0.0",
1341         &GUID_VendorMicrosoft,
1342         &GUID_ContainerFormatTiff,
1343         "image/tiff",
1344         ".tif;.tiff",
1345         tiff_decode_formats,
1346         tiff_patterns
1347     },
1348     {   &CLSID_WineTgaDecoder,
1349         "The Wine Project",
1350         "TGA Decoder",
1351         "1.0.0.0",
1352         &GUID_VendorWine,
1353         &GUID_WineContainerFormatTga,
1354         "image/x-targa",
1355         ".tga;.tpic",
1356         tga_formats,
1357         tga_patterns
1358     },
1359     { NULL }                    /* list terminator */
1360 };
1361
1362 static GUID const * const bmp_encode_formats[] = {
1363     &GUID_WICPixelFormat16bppBGR555,
1364     &GUID_WICPixelFormat16bppBGR565,
1365     &GUID_WICPixelFormat24bppBGR,
1366     &GUID_WICPixelFormat32bppBGR,
1367     NULL
1368 };
1369
1370 static GUID const * const png_encode_formats[] = {
1371     &GUID_WICPixelFormat24bppBGR,
1372     &GUID_WICPixelFormatBlackWhite,
1373     &GUID_WICPixelFormat2bppGray,
1374     &GUID_WICPixelFormat4bppGray,
1375     &GUID_WICPixelFormat8bppGray,
1376     &GUID_WICPixelFormat16bppGray,
1377     &GUID_WICPixelFormat32bppBGR,
1378     &GUID_WICPixelFormat32bppBGRA,
1379     &GUID_WICPixelFormat48bppRGB,
1380     &GUID_WICPixelFormat64bppRGBA,
1381     NULL
1382 };
1383
1384 static GUID const * const tiff_encode_formats[] = {
1385     &GUID_WICPixelFormatBlackWhite,
1386     &GUID_WICPixelFormat4bppGray,
1387     &GUID_WICPixelFormat8bppGray,
1388     &GUID_WICPixelFormat24bppBGR,
1389     &GUID_WICPixelFormat32bppBGRA,
1390     &GUID_WICPixelFormat32bppPBGRA,
1391     &GUID_WICPixelFormat48bppRGB,
1392     &GUID_WICPixelFormat64bppRGBA,
1393     &GUID_WICPixelFormat64bppPRGBA,
1394     NULL
1395 };
1396
1397 static GUID const * const icns_encode_formats[] = {
1398     &GUID_WICPixelFormat32bppBGRA,
1399     NULL
1400 };
1401
1402 static struct regsvr_encoder const encoder_list[] = {
1403     {   &CLSID_WICBmpEncoder,
1404         "The Wine Project",
1405         "BMP Encoder",
1406         "1.0.0.0",
1407         &GUID_VendorMicrosoft,
1408         &GUID_ContainerFormatBmp,
1409         "image/bmp",
1410         ".bmp,.dib,.rle",
1411         bmp_encode_formats
1412     },
1413     {   &CLSID_WICJpegEncoder,
1414         "The Wine Project",
1415         "JPEG Encoder",
1416         "1.0.0.0",
1417         &GUID_VendorMicrosoft,
1418         &GUID_ContainerFormatJpeg,
1419         "image/jpeg",
1420         ".jpg;.jpeg;.jfif",
1421         jpeg_formats
1422     },
1423     {   &CLSID_WICPngEncoder,
1424         "The Wine Project",
1425         "PNG Encoder",
1426         "1.0.0.0",
1427         &GUID_VendorMicrosoft,
1428         &GUID_ContainerFormatPng,
1429         "image/png",
1430         ".png",
1431         png_encode_formats
1432     },
1433     {   &CLSID_WICTiffEncoder,
1434         "The Wine Project",
1435         "TIFF Encoder",
1436         "1.0.0.0",
1437         &GUID_VendorMicrosoft,
1438         &GUID_ContainerFormatTiff,
1439         "image/tiff",
1440         ".tif;.tiff",
1441         tiff_encode_formats
1442     },
1443     {   &CLSID_WICIcnsEncoder,
1444         "The Wine Project",
1445         "ICNS Encoder",
1446         "1.0.0.0",
1447         &GUID_VendorWine,
1448         NULL, /* no container format guid */
1449         "image/icns",
1450         ".icns",
1451         icns_encode_formats
1452     },
1453     { NULL }                    /* list terminator */
1454 };
1455
1456 static GUID const * const converter_formats[] = {
1457     &GUID_WICPixelFormat1bppIndexed,
1458     &GUID_WICPixelFormat2bppIndexed,
1459     &GUID_WICPixelFormat4bppIndexed,
1460     &GUID_WICPixelFormat8bppIndexed,
1461     &GUID_WICPixelFormatBlackWhite,
1462     &GUID_WICPixelFormat2bppGray,
1463     &GUID_WICPixelFormat4bppGray,
1464     &GUID_WICPixelFormat8bppGray,
1465     &GUID_WICPixelFormat16bppGray,
1466     &GUID_WICPixelFormat16bppBGR555,
1467     &GUID_WICPixelFormat16bppBGR565,
1468     &GUID_WICPixelFormat16bppBGRA5551,
1469     &GUID_WICPixelFormat24bppBGR,
1470     &GUID_WICPixelFormat32bppBGR,
1471     &GUID_WICPixelFormat32bppBGRA,
1472     &GUID_WICPixelFormat32bppPBGRA,
1473     &GUID_WICPixelFormat48bppRGB,
1474     &GUID_WICPixelFormat64bppRGBA,
1475     &GUID_WICPixelFormat32bppCMYK,
1476     NULL
1477 };
1478
1479 static struct regsvr_converter const converter_list[] = {
1480     {   &CLSID_WICDefaultFormatConverter,
1481         "The Wine Project",
1482         "Default Pixel Format Converter",
1483         "1.0.0.0",
1484         &GUID_VendorMicrosoft,
1485         converter_formats
1486     },
1487     { NULL }                    /* list terminator */
1488 };
1489
1490 static const BYTE no_magic[1] = { 0 };
1491 static const BYTE no_mask[1] = { 0 };
1492
1493 static const struct metadata_pattern ifd_metadata_pattern[] = {
1494     { 0, 1, no_magic, no_mask, 0 },
1495     { 0 }
1496 };
1497
1498 static const struct reader_containers ifd_containers[] = {
1499     {
1500         &GUID_ContainerFormatTiff,
1501         ifd_metadata_pattern
1502     },
1503     { NULL } /* list terminator */
1504 };
1505
1506 static const BYTE tEXt[] = "tEXt";
1507
1508 static const struct metadata_pattern pngtext_metadata_pattern[] = {
1509     { 4, 4, tEXt, mask_all, 4 },
1510     { 0 }
1511 };
1512
1513 static const struct reader_containers pngtext_containers[] = {
1514     {
1515         &GUID_ContainerFormatPng,
1516         pngtext_metadata_pattern
1517     },
1518     { NULL } /* list terminator */
1519 };
1520
1521 static const struct metadata_pattern lsd_metadata_patterns[] = {
1522     { 0, 6, gif87a_magic, mask_all, 0 },
1523     { 0, 6, gif89a_magic, mask_all, 0 },
1524     { 0 }
1525 };
1526
1527 static const struct reader_containers lsd_containers[] = {
1528     {
1529         &GUID_ContainerFormatGif,
1530         lsd_metadata_patterns
1531     },
1532     { NULL } /* list terminator */
1533 };
1534
1535 static const BYTE imd_magic[] = { 0x2c };
1536
1537 static const struct metadata_pattern imd_metadata_pattern[] = {
1538     { 0, 1, imd_magic, mask_all, 1 },
1539     { 0 }
1540 };
1541
1542 static const struct reader_containers imd_containers[] = {
1543     {
1544         &GUID_ContainerFormatGif,
1545         imd_metadata_pattern
1546     },
1547     { NULL } /* list terminator */
1548 };
1549
1550 static const BYTE gce_magic[] = { 0x21, 0xf9, 0x04 };
1551
1552 static const struct metadata_pattern gce_metadata_pattern[] = {
1553     { 0, 3, gce_magic, mask_all, 3 },
1554     { 0 }
1555 };
1556
1557 static const struct reader_containers gce_containers[] = {
1558     {
1559         &GUID_ContainerFormatGif,
1560         gce_metadata_pattern
1561     },
1562     { NULL } /* list terminator */
1563 };
1564
1565 static const BYTE ape_magic[] = { 0x21, 0xff, 0x0b };
1566
1567 static const struct metadata_pattern ape_metadata_pattern[] = {
1568     { 0, 3, ape_magic, mask_all, 0 },
1569     { 0 }
1570 };
1571
1572 static const struct reader_containers ape_containers[] = {
1573     {
1574         &GUID_ContainerFormatGif,
1575         ape_metadata_pattern
1576     },
1577     { NULL } /* list terminator */
1578 };
1579
1580 static const BYTE gif_comment_magic[] = { 0x21, 0xfe };
1581
1582 static const struct metadata_pattern gif_comment_metadata_pattern[] = {
1583     { 0, 2, gif_comment_magic, mask_all, 0 },
1584     { 0 }
1585 };
1586
1587 static const struct reader_containers gif_comment_containers[] = {
1588     {
1589         &GUID_ContainerFormatGif,
1590         gif_comment_metadata_pattern
1591     },
1592     { NULL } /* list terminator */
1593 };
1594
1595 static struct regsvr_metadatareader const metadatareader_list[] = {
1596     {   &CLSID_WICUnknownMetadataReader,
1597         "The Wine Project",
1598         "Unknown Metadata Reader",
1599         "1.0.0.0",
1600         "1.0.0.0",
1601         &GUID_VendorMicrosoft,
1602         &GUID_MetadataFormatUnknown,
1603         0, 0, 0,
1604         NULL
1605     },
1606     {   &CLSID_WICIfdMetadataReader,
1607         "The Wine Project",
1608         "Ifd Reader",
1609         "1.0.0.0",
1610         "1.0.0.0",
1611         &GUID_VendorMicrosoft,
1612         &GUID_MetadataFormatIfd,
1613         1, 1, 0,
1614         ifd_containers
1615     },
1616     {   &CLSID_WICPngTextMetadataReader,
1617         "The Wine Project",
1618         "Chunk tEXt Reader",
1619         "1.0.0.0",
1620         "1.0.0.0",
1621         &GUID_VendorMicrosoft,
1622         &GUID_MetadataFormatChunktEXt,
1623         0, 0, 0,
1624         pngtext_containers
1625     },
1626     {   &CLSID_WICLSDMetadataReader,
1627         "The Wine Project",
1628         "Logical Screen Descriptor Reader",
1629         "1.0.0.0",
1630         "1.0.0.0",
1631         &GUID_VendorMicrosoft,
1632         &GUID_MetadataFormatLSD,
1633         0, 0, 0,
1634         lsd_containers
1635     },
1636     {   &CLSID_WICIMDMetadataReader,
1637         "The Wine Project",
1638         "Image Descriptor Reader",
1639         "1.0.0.0",
1640         "1.0.0.0",
1641         &GUID_VendorMicrosoft,
1642         &GUID_MetadataFormatIMD,
1643         0, 0, 0,
1644         imd_containers
1645     },
1646     {   &CLSID_WICGCEMetadataReader,
1647         "The Wine Project",
1648         "Graphic Control Extension Reader",
1649         "1.0.0.0",
1650         "1.0.0.0",
1651         &GUID_VendorMicrosoft,
1652         &GUID_MetadataFormatGCE,
1653         0, 0, 0,
1654         gce_containers
1655     },
1656     {   &CLSID_WICAPEMetadataReader,
1657         "The Wine Project",
1658         "Application Extension Reader",
1659         "1.0.0.0",
1660         "1.0.0.0",
1661         &GUID_VendorMicrosoft,
1662         &GUID_MetadataFormatAPE,
1663         0, 0, 0,
1664         ape_containers
1665     },
1666     {   &CLSID_WICGifCommentMetadataReader,
1667         "The Wine Project",
1668         "Comment Extension Reader",
1669         "1.0.0.0",
1670         "1.0.0.0",
1671         &GUID_VendorMicrosoft,
1672         &GUID_MetadataFormatGifComment,
1673         0, 0, 0,
1674         gif_comment_containers
1675     },
1676     { NULL }                    /* list terminator */
1677 };
1678
1679 static BYTE const channel_mask_1bit[] = { 0x01 };
1680 static BYTE const channel_mask_2bit[] = { 0x03 };
1681 static BYTE const channel_mask_4bit[] = { 0x0f };
1682
1683 static BYTE const channel_mask_8bit[] = { 0xff, 0x00, 0x00, 0x00 };
1684 static BYTE const channel_mask_8bit2[] = { 0x00, 0xff, 0x00, 0x00 };
1685 static BYTE const channel_mask_8bit3[] = { 0x00, 0x00, 0xff, 0x00 };
1686 static BYTE const channel_mask_8bit4[] = { 0x00, 0x00, 0x00, 0xff };
1687
1688 static BYTE const channel_mask_16bit[] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1689 static BYTE const channel_mask_16bit2[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
1690 static BYTE const channel_mask_16bit3[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 };
1691 static BYTE const channel_mask_16bit4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1692
1693 static BYTE const channel_mask_5bit[] = { 0x1f, 0x00 };
1694 static BYTE const channel_mask_5bit2[] = { 0xe0, 0x03 };
1695 static BYTE const channel_mask_5bit3[] = { 0x00, 0x7c };
1696 static BYTE const channel_mask_5bit4[] = { 0x00, 0x80 };
1697
1698 static BYTE const channel_mask_BGR565_2[] = { 0xe0, 0x07 };
1699 static BYTE const channel_mask_BGR565_3[] = { 0x00, 0xf8 };
1700
1701 static BYTE const * const channel_masks_1bit[] = { channel_mask_1bit };
1702 static BYTE const * const channel_masks_2bit[] = { channel_mask_2bit };
1703 static BYTE const * const channel_masks_4bit[] = { channel_mask_4bit };
1704 static BYTE const * const channel_masks_8bit[] = { channel_mask_8bit,
1705     channel_mask_8bit2, channel_mask_8bit3, channel_mask_8bit4 };
1706 static BYTE const * const channel_masks_16bit[] = { channel_mask_16bit,
1707     channel_mask_16bit2, channel_mask_16bit3, channel_mask_16bit4};
1708
1709 static BYTE const * const channel_masks_BGRA5551[] = { channel_mask_5bit,
1710     channel_mask_5bit2, channel_mask_5bit3, channel_mask_5bit4 };
1711
1712 static BYTE const * const channel_masks_BGR565[] = { channel_mask_5bit,
1713     channel_mask_BGR565_2, channel_mask_BGR565_3 };
1714
1715 static struct regsvr_pixelformat const pixelformat_list[] = {
1716     {   &GUID_WICPixelFormat1bppIndexed,
1717         "The Wine Project",
1718         "1bpp Indexed",
1719         NULL, /* no version */
1720         &GUID_VendorMicrosoft,
1721         1, /* bitsperpixel */
1722         1, /* channel count */
1723         channel_masks_1bit,
1724         WICPixelFormatNumericRepresentationIndexed,
1725         1
1726     },
1727     {   &GUID_WICPixelFormat2bppIndexed,
1728         "The Wine Project",
1729         "2bpp Indexed",
1730         NULL, /* no version */
1731         &GUID_VendorMicrosoft,
1732         2, /* bitsperpixel */
1733         1, /* channel count */
1734         channel_masks_2bit,
1735         WICPixelFormatNumericRepresentationIndexed,
1736         1
1737     },
1738     {   &GUID_WICPixelFormat4bppIndexed,
1739         "The Wine Project",
1740         "4bpp Indexed",
1741         NULL, /* no version */
1742         &GUID_VendorMicrosoft,
1743         4, /* bitsperpixel */
1744         1, /* channel count */
1745         channel_masks_4bit,
1746         WICPixelFormatNumericRepresentationIndexed,
1747         1
1748     },
1749     {   &GUID_WICPixelFormat8bppIndexed,
1750         "The Wine Project",
1751         "8bpp Indexed",
1752         NULL, /* no version */
1753         &GUID_VendorMicrosoft,
1754         8, /* bitsperpixel */
1755         1, /* channel count */
1756         channel_masks_8bit,
1757         WICPixelFormatNumericRepresentationIndexed,
1758         1
1759     },
1760     {   &GUID_WICPixelFormatBlackWhite,
1761         "The Wine Project",
1762         "Black and White",
1763         NULL, /* no version */
1764         &GUID_VendorMicrosoft,
1765         1, /* bitsperpixel */
1766         1, /* channel count */
1767         channel_masks_1bit,
1768         WICPixelFormatNumericRepresentationUnsignedInteger,
1769         0
1770     },
1771     {   &GUID_WICPixelFormat2bppGray,
1772         "The Wine Project",
1773         "2bpp Grayscale",
1774         NULL, /* no version */
1775         &GUID_VendorMicrosoft,
1776         2, /* bitsperpixel */
1777         1, /* channel count */
1778         channel_masks_2bit,
1779         WICPixelFormatNumericRepresentationUnsignedInteger,
1780         0
1781     },
1782     {   &GUID_WICPixelFormat4bppGray,
1783         "The Wine Project",
1784         "4bpp Grayscale",
1785         NULL, /* no version */
1786         &GUID_VendorMicrosoft,
1787         4, /* bitsperpixel */
1788         1, /* channel count */
1789         channel_masks_4bit,
1790         WICPixelFormatNumericRepresentationUnsignedInteger,
1791         0
1792     },
1793     {   &GUID_WICPixelFormat8bppGray,
1794         "The Wine Project",
1795         "8bpp Grayscale",
1796         NULL, /* no version */
1797         &GUID_VendorMicrosoft,
1798         8, /* bitsperpixel */
1799         1, /* channel count */
1800         channel_masks_8bit,
1801         WICPixelFormatNumericRepresentationUnsignedInteger,
1802         0
1803     },
1804     {   &GUID_WICPixelFormat16bppGray,
1805         "The Wine Project",
1806         "16bpp Grayscale",
1807         NULL, /* no version */
1808         &GUID_VendorMicrosoft,
1809         16, /* bitsperpixel */
1810         1, /* channel count */
1811         channel_masks_16bit,
1812         WICPixelFormatNumericRepresentationUnsignedInteger,
1813         0
1814     },
1815     {   &GUID_WICPixelFormat16bppBGR555,
1816         "The Wine Project",
1817         "16bpp BGR555",
1818         NULL, /* no version */
1819         &GUID_VendorMicrosoft,
1820         16, /* bitsperpixel */
1821         3, /* channel count */
1822         channel_masks_BGRA5551,
1823         WICPixelFormatNumericRepresentationUnsignedInteger,
1824         0
1825     },
1826     {   &GUID_WICPixelFormat16bppBGR565,
1827         "The Wine Project",
1828         "16bpp BGR565",
1829         NULL, /* no version */
1830         &GUID_VendorMicrosoft,
1831         16, /* bitsperpixel */
1832         3, /* channel count */
1833         channel_masks_BGR565,
1834         WICPixelFormatNumericRepresentationUnsignedInteger,
1835         0
1836     },
1837     {   &GUID_WICPixelFormat16bppBGRA5551,
1838         "The Wine Project",
1839         "16bpp BGRA5551",
1840         NULL, /* no version */
1841         &GUID_VendorMicrosoft,
1842         16, /* bitsperpixel */
1843         4, /* channel count */
1844         channel_masks_BGRA5551,
1845         WICPixelFormatNumericRepresentationUnsignedInteger,
1846         1
1847     },
1848     {   &GUID_WICPixelFormat24bppBGR,
1849         "The Wine Project",
1850         "24bpp BGR",
1851         NULL, /* no version */
1852         &GUID_VendorMicrosoft,
1853         24, /* bitsperpixel */
1854         3, /* channel count */
1855         channel_masks_8bit,
1856         WICPixelFormatNumericRepresentationUnsignedInteger,
1857         0
1858     },
1859     {   &GUID_WICPixelFormat32bppBGR,
1860         "The Wine Project",
1861         "32bpp BGR",
1862         NULL, /* no version */
1863         &GUID_VendorMicrosoft,
1864         32, /* bitsperpixel */
1865         3, /* channel count */
1866         channel_masks_8bit,
1867         WICPixelFormatNumericRepresentationUnsignedInteger,
1868         0
1869     },
1870     {   &GUID_WICPixelFormat32bppBGRA,
1871         "The Wine Project",
1872         "32bpp BGRA",
1873         NULL, /* no version */
1874         &GUID_VendorMicrosoft,
1875         32, /* bitsperpixel */
1876         4, /* channel count */
1877         channel_masks_8bit,
1878         WICPixelFormatNumericRepresentationUnsignedInteger,
1879         1
1880     },
1881     {   &GUID_WICPixelFormat32bppPBGRA,
1882         "The Wine Project",
1883         "32bpp PBGRA",
1884         NULL, /* no version */
1885         &GUID_VendorMicrosoft,
1886         32, /* bitsperpixel */
1887         4, /* channel count */
1888         channel_masks_8bit,
1889         WICPixelFormatNumericRepresentationUnsignedInteger,
1890         1
1891     },
1892     {   &GUID_WICPixelFormat48bppRGB,
1893         "The Wine Project",
1894         "48bpp RGB",
1895         NULL, /* no version */
1896         &GUID_VendorMicrosoft,
1897         48, /* bitsperpixel */
1898         3, /* channel count */
1899         channel_masks_16bit,
1900         WICPixelFormatNumericRepresentationUnsignedInteger,
1901         0
1902     },
1903     {   &GUID_WICPixelFormat64bppRGBA,
1904         "The Wine Project",
1905         "64bpp RGBA",
1906         NULL, /* no version */
1907         &GUID_VendorMicrosoft,
1908         64, /* bitsperpixel */
1909         4, /* channel count */
1910         channel_masks_16bit,
1911         WICPixelFormatNumericRepresentationUnsignedInteger,
1912         1
1913     },
1914     {   &GUID_WICPixelFormat64bppPRGBA,
1915         "The Wine Project",
1916         "64bpp PRGBA",
1917         NULL, /* no version */
1918         &GUID_VendorMicrosoft,
1919         64, /* bitsperpixel */
1920         4, /* channel count */
1921         channel_masks_16bit,
1922         WICPixelFormatNumericRepresentationUnsignedInteger,
1923         1
1924     },
1925     {   &GUID_WICPixelFormat32bppCMYK,
1926         "The Wine Project",
1927         "32bpp CMYK",
1928         NULL, /* no version */
1929         &GUID_VendorMicrosoft,
1930         32, /* bitsperpixel */
1931         4, /* channel count */
1932         channel_masks_8bit,
1933         WICPixelFormatNumericRepresentationUnsignedInteger,
1934         0
1935     },
1936     { NULL }                    /* list terminator */
1937 };
1938
1939 struct regsvr_category
1940 {
1941     const CLSID *clsid; /* NULL for end of list */
1942 };
1943
1944 static const struct regsvr_category category_list[] = {
1945     { &CATID_WICBitmapDecoders },
1946     { &CATID_WICBitmapEncoders },
1947     { &CATID_WICFormatConverters },
1948     { &CATID_WICMetadataReader },
1949     { &CATID_WICPixelFormats },
1950     { NULL }
1951 };
1952
1953 static HRESULT register_categories(const struct regsvr_category *list)
1954 {
1955     LONG res;
1956     WCHAR buf[39];
1957     HKEY coclass_key, categories_key, instance_key;
1958
1959     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
1960                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
1961     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
1962
1963     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
1964     res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
1965                           KEY_READ | KEY_WRITE, NULL, &categories_key, NULL);
1966     if (res != ERROR_SUCCESS)
1967     {
1968         RegCloseKey(coclass_key);
1969         return HRESULT_FROM_WIN32(res);
1970     }
1971
1972     res = RegCreateKeyExW(categories_key, instance_keyname, 0, NULL, 0,
1973                           KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
1974
1975     for (; res == ERROR_SUCCESS && list->clsid; list++)
1976     {
1977         HKEY instance_clsid_key;
1978
1979         StringFromGUID2(list->clsid, buf, 39);
1980         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
1981                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
1982         if (res == ERROR_SUCCESS)
1983         {
1984             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
1985                                  (const BYTE *)buf, 78);
1986             RegCloseKey(instance_clsid_key);
1987         }
1988     }
1989
1990     RegCloseKey(instance_key);
1991     RegCloseKey(categories_key);
1992     RegCloseKey(coclass_key);
1993
1994     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
1995 }
1996
1997 static HRESULT unregister_categories(const struct regsvr_category *list)
1998 {
1999     LONG res;
2000     WCHAR buf[39];
2001     HKEY coclass_key, categories_key, instance_key;
2002
2003     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
2004                         KEY_READ | KEY_WRITE, &coclass_key);
2005     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
2006
2007     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
2008     res = RegOpenKeyExW(coclass_key, buf, 0,
2009                         KEY_READ | KEY_WRITE, &categories_key);
2010     if (res != ERROR_SUCCESS)
2011     {
2012         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
2013         RegCloseKey(coclass_key);
2014         return HRESULT_FROM_WIN32(res);
2015     }
2016
2017     res = RegOpenKeyExW(categories_key, instance_keyname, 0,
2018                           KEY_READ | KEY_WRITE, &instance_key);
2019
2020     for (; res == ERROR_SUCCESS && list->clsid; list++)
2021     {
2022         StringFromGUID2(list->clsid, buf, 39);
2023         res = RegDeleteTreeW(instance_key, buf);
2024     }
2025
2026     RegCloseKey(instance_key);
2027     RegCloseKey(categories_key);
2028
2029     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
2030     res = RegDeleteTreeW(coclass_key, buf);
2031
2032     RegCloseKey(coclass_key);
2033
2034     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
2035 }
2036
2037 extern HRESULT WINAPI WIC_DllRegisterServer(void) DECLSPEC_HIDDEN;
2038 extern HRESULT WINAPI WIC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
2039
2040 HRESULT WINAPI DllRegisterServer(void)
2041 {
2042     HRESULT hr;
2043
2044     TRACE("\n");
2045
2046     hr = WIC_DllRegisterServer();
2047     if (SUCCEEDED(hr))
2048         hr = register_categories(category_list);
2049     if (SUCCEEDED(hr))
2050         hr = register_decoders(decoder_list);
2051     if (SUCCEEDED(hr))
2052         hr = register_encoders(encoder_list);
2053     if (SUCCEEDED(hr))
2054         hr = register_converters(converter_list);
2055     if (SUCCEEDED(hr))
2056         hr = register_metadatareaders(metadatareader_list);
2057     if (SUCCEEDED(hr))
2058         hr = register_pixelformats(pixelformat_list);
2059     return hr;
2060 }
2061
2062 HRESULT WINAPI DllUnregisterServer(void)
2063 {
2064     HRESULT hr;
2065
2066     TRACE("\n");
2067
2068     hr = WIC_DllUnregisterServer();
2069     if (SUCCEEDED(hr))
2070         hr = unregister_categories(category_list);
2071     if (SUCCEEDED(hr))
2072         hr = unregister_decoders(decoder_list);
2073     if (SUCCEEDED(hr))
2074         hr = unregister_encoders(encoder_list);
2075     if (SUCCEEDED(hr))
2076         hr = unregister_converters(converter_list);
2077     if (SUCCEEDED(hr))
2078         hr = unregister_metadatareaders(metadatareader_list);
2079     if (SUCCEEDED(hr))
2080         hr = unregister_pixelformats(pixelformat_list);
2081     return hr;
2082 }