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