xref: /reactos/dll/win32/windowscodecs/regsvr.c (revision b917d826)
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_WICPixelFormat4bppIndexed,
1198     &GUID_WICPixelFormat8bppIndexed,
1199     &GUID_WICPixelFormat24bppBGR,
1200     &GUID_WICPixelFormat32bppBGR,
1201     &GUID_WICPixelFormat32bppBGRA,
1202     &GUID_WICPixelFormat32bppPBGRA,
1203     &GUID_WICPixelFormat48bppRGB,
1204     &GUID_WICPixelFormat64bppRGBA,
1205     &GUID_WICPixelFormat64bppPRGBA,
1206     NULL
1207 };
1208 
1209 static struct decoder_pattern const tiff_patterns[] = {
1210     {4,0,tiff_magic_le,mask_all,0},
1211     {4,0,tiff_magic_be,mask_all,0},
1212     {0}
1213 };
1214 
1215 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
1216 
1217 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};
1218 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};
1219 
1220 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};
1221 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};
1222 
1223 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};
1224 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};
1225 
1226 static GUID const * const tga_formats[] = {
1227     &GUID_WICPixelFormat8bppGray,
1228     &GUID_WICPixelFormat8bppIndexed,
1229     &GUID_WICPixelFormat16bppGray,
1230     &GUID_WICPixelFormat16bppBGR555,
1231     &GUID_WICPixelFormat24bppBGR,
1232     &GUID_WICPixelFormat32bppBGRA,
1233     &GUID_WICPixelFormat32bppPBGRA,
1234     NULL
1235 };
1236 
1237 static struct decoder_pattern const tga_patterns[] = {
1238     {18,18,tga_footer_magic,mask_all,1},
1239     {18,0,tga_indexed_magic,tga_indexed_mask,0},
1240     {18,0,tga_truecolor_magic,tga_truecolor_mask,0},
1241     {18,0,tga_grayscale_magic,tga_grayscale_mask,0},
1242     {0}
1243 };
1244 
1245 static struct regsvr_decoder const decoder_list[] = {
1246     {   &CLSID_WICBmpDecoder,
1247 	"The Wine Project",
1248 	"BMP Decoder",
1249 	"1.0.0.0",
1250 	&GUID_VendorMicrosoft,
1251 	&GUID_ContainerFormatBmp,
1252 	"image/bmp",
1253 	".bmp,.dib,.rle",
1254 	bmp_formats,
1255 	bmp_patterns
1256     },
1257     {   &CLSID_WICGifDecoder,
1258 	"The Wine Project",
1259 	"GIF Decoder",
1260 	"1.0.0.0",
1261 	&GUID_VendorMicrosoft,
1262 	&GUID_ContainerFormatGif,
1263 	"image/gif",
1264 	".gif",
1265 	gif_formats,
1266 	gif_patterns
1267     },
1268     {   &CLSID_WICIcoDecoder,
1269 	"The Wine Project",
1270 	"ICO Decoder",
1271 	"1.0.0.0",
1272 	&GUID_VendorMicrosoft,
1273 	&GUID_ContainerFormatIco,
1274 	"image/vnd.microsoft.icon",
1275 	".ico",
1276 	ico_formats,
1277 	ico_patterns
1278     },
1279     {   &CLSID_WICJpegDecoder,
1280 	"The Wine Project",
1281 	"JPEG Decoder",
1282 	"1.0.0.0",
1283 	&GUID_VendorMicrosoft,
1284 	&GUID_ContainerFormatJpeg,
1285 	"image/jpeg",
1286 	".jpg;.jpeg;.jfif",
1287 	jpeg_formats,
1288 	jpeg_patterns
1289     },
1290     {   &CLSID_WICPngDecoder,
1291 	"The Wine Project",
1292 	"PNG Decoder",
1293 	"1.0.0.0",
1294 	&GUID_VendorMicrosoft,
1295 	&GUID_ContainerFormatPng,
1296 	"image/png",
1297 	".png",
1298 	png_formats,
1299 	png_patterns
1300     },
1301     {   &CLSID_WICTiffDecoder,
1302 	"The Wine Project",
1303 	"TIFF Decoder",
1304 	"1.0.0.0",
1305 	&GUID_VendorMicrosoft,
1306 	&GUID_ContainerFormatTiff,
1307 	"image/tiff",
1308 	".tif;.tiff",
1309 	tiff_decode_formats,
1310 	tiff_patterns
1311     },
1312     {   &CLSID_WineTgaDecoder,
1313 	"The Wine Project",
1314 	"TGA Decoder",
1315 	"1.0.0.0",
1316 	&GUID_VendorWine,
1317 	&GUID_WineContainerFormatTga,
1318 	"image/x-targa",
1319 	".tga;.tpic",
1320 	tga_formats,
1321 	tga_patterns
1322     },
1323     { NULL }			/* list terminator */
1324 };
1325 
1326 static GUID const * const bmp_encode_formats[] = {
1327     &GUID_WICPixelFormat16bppBGR555,
1328     &GUID_WICPixelFormat16bppBGR565,
1329     &GUID_WICPixelFormat24bppBGR,
1330     &GUID_WICPixelFormat32bppBGR,
1331     NULL
1332 };
1333 
1334 static GUID const * const png_encode_formats[] = {
1335     &GUID_WICPixelFormat24bppBGR,
1336     &GUID_WICPixelFormatBlackWhite,
1337     &GUID_WICPixelFormat2bppGray,
1338     &GUID_WICPixelFormat4bppGray,
1339     &GUID_WICPixelFormat8bppGray,
1340     &GUID_WICPixelFormat16bppGray,
1341     &GUID_WICPixelFormat32bppBGR,
1342     &GUID_WICPixelFormat32bppBGRA,
1343     &GUID_WICPixelFormat48bppRGB,
1344     &GUID_WICPixelFormat64bppRGBA,
1345     &GUID_WICPixelFormat1bppIndexed,
1346     &GUID_WICPixelFormat2bppIndexed,
1347     &GUID_WICPixelFormat4bppIndexed,
1348     &GUID_WICPixelFormat8bppIndexed,
1349     NULL
1350 };
1351 
1352 static GUID const * const tiff_encode_formats[] = {
1353     &GUID_WICPixelFormatBlackWhite,
1354     &GUID_WICPixelFormat4bppGray,
1355     &GUID_WICPixelFormat8bppGray,
1356     &GUID_WICPixelFormat24bppBGR,
1357     &GUID_WICPixelFormat32bppBGRA,
1358     &GUID_WICPixelFormat32bppPBGRA,
1359     &GUID_WICPixelFormat48bppRGB,
1360     &GUID_WICPixelFormat64bppRGBA,
1361     &GUID_WICPixelFormat64bppPRGBA,
1362     NULL
1363 };
1364 
1365 static GUID const * const icns_encode_formats[] = {
1366     &GUID_WICPixelFormat32bppBGRA,
1367     NULL
1368 };
1369 
1370 static struct regsvr_encoder const encoder_list[] = {
1371     {   &CLSID_WICBmpEncoder,
1372 	"The Wine Project",
1373 	"BMP Encoder",
1374 	"1.0.0.0",
1375 	&GUID_VendorMicrosoft,
1376 	&GUID_ContainerFormatBmp,
1377 	"image/bmp",
1378 	".bmp,.dib,.rle",
1379 	bmp_encode_formats
1380     },
1381     {   &CLSID_WICJpegEncoder,
1382 	"The Wine Project",
1383 	"JPEG Encoder",
1384 	"1.0.0.0",
1385 	&GUID_VendorMicrosoft,
1386 	&GUID_ContainerFormatJpeg,
1387 	"image/jpeg",
1388 	".jpg;.jpeg;.jfif",
1389 	jpeg_formats
1390     },
1391     {   &CLSID_WICPngEncoder,
1392 	"The Wine Project",
1393 	"PNG Encoder",
1394 	"1.0.0.0",
1395 	&GUID_VendorMicrosoft,
1396 	&GUID_ContainerFormatPng,
1397 	"image/png",
1398 	".png",
1399 	png_encode_formats
1400     },
1401     {   &CLSID_WICTiffEncoder,
1402 	"The Wine Project",
1403 	"TIFF Encoder",
1404 	"1.0.0.0",
1405 	&GUID_VendorMicrosoft,
1406 	&GUID_ContainerFormatTiff,
1407 	"image/tiff",
1408 	".tif;.tiff",
1409 	tiff_encode_formats
1410     },
1411     {   &CLSID_WICIcnsEncoder,
1412 	"The Wine Project",
1413 	"ICNS Encoder",
1414 	"1.0.0.0",
1415 	&GUID_VendorWine,
1416 	NULL, /* no container format guid */
1417 	"image/icns",
1418 	".icns",
1419 	icns_encode_formats
1420     },
1421     { NULL }			/* list terminator */
1422 };
1423 
1424 static GUID const * const converter_formats[] = {
1425     &GUID_WICPixelFormat1bppIndexed,
1426     &GUID_WICPixelFormat2bppIndexed,
1427     &GUID_WICPixelFormat4bppIndexed,
1428     &GUID_WICPixelFormat8bppIndexed,
1429     &GUID_WICPixelFormatBlackWhite,
1430     &GUID_WICPixelFormat2bppGray,
1431     &GUID_WICPixelFormat4bppGray,
1432     &GUID_WICPixelFormat8bppGray,
1433     &GUID_WICPixelFormat16bppGray,
1434     &GUID_WICPixelFormat16bppBGR555,
1435     &GUID_WICPixelFormat16bppBGR565,
1436     &GUID_WICPixelFormat16bppBGRA5551,
1437     &GUID_WICPixelFormat24bppBGR,
1438     &GUID_WICPixelFormat24bppRGB,
1439     &GUID_WICPixelFormat32bppBGR,
1440     &GUID_WICPixelFormat32bppBGRA,
1441     &GUID_WICPixelFormat32bppPBGRA,
1442     &GUID_WICPixelFormat32bppGrayFloat,
1443     &GUID_WICPixelFormat48bppRGB,
1444     &GUID_WICPixelFormat64bppRGBA,
1445     &GUID_WICPixelFormat32bppCMYK,
1446     NULL
1447 };
1448 
1449 static struct regsvr_converter const converter_list[] = {
1450     {   &CLSID_WICDefaultFormatConverter,
1451 	"The Wine Project",
1452 	"Default Pixel Format Converter",
1453 	"1.0.0.0",
1454 	&GUID_VendorMicrosoft,
1455 	converter_formats
1456     },
1457     { NULL }			/* list terminator */
1458 };
1459 
1460 static const BYTE no_magic[1] = { 0 };
1461 static const BYTE no_mask[1] = { 0 };
1462 
1463 static const struct metadata_pattern ifd_metadata_pattern[] = {
1464     { 0, 1, no_magic, no_mask, 0 },
1465     { 0 }
1466 };
1467 
1468 static const struct reader_containers ifd_containers[] = {
1469     {
1470         &GUID_ContainerFormatTiff,
1471         ifd_metadata_pattern
1472     },
1473     { NULL } /* list terminator */
1474 };
1475 
1476 static const BYTE tEXt[] = "tEXt";
1477 
1478 static const struct metadata_pattern pngtext_metadata_pattern[] = {
1479     { 4, 4, tEXt, mask_all, 4 },
1480     { 0 }
1481 };
1482 
1483 static const struct reader_containers pngtext_containers[] = {
1484     {
1485         &GUID_ContainerFormatPng,
1486         pngtext_metadata_pattern
1487     },
1488     { NULL } /* list terminator */
1489 };
1490 
1491 static const BYTE gAMA[] = "gAMA";
1492 
1493 static const struct metadata_pattern pnggama_metadata_pattern[] = {
1494     { 4, 4, gAMA, mask_all, 4 },
1495     { 0 }
1496 };
1497 
1498 static const struct reader_containers pnggama_containers[] = {
1499     {
1500         &GUID_ContainerFormatPng,
1501         pnggama_metadata_pattern
1502     },
1503     { NULL } /* list terminator */
1504 };
1505 
1506 static const BYTE cHRM[] = "cHRM";
1507 
1508 static const struct metadata_pattern pngchrm_metadata_pattern[] = {
1509     { 4, 4, cHRM, mask_all, 4 },
1510     { 0 }
1511 };
1512 
1513 static const struct reader_containers pngchrm_containers[] = {
1514     {
1515         &GUID_ContainerFormatPng,
1516         pngchrm_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_WICPngChrmMetadataReader,
1617         "The Wine Project",
1618         "Chunk cHRM Reader",
1619         "1.0.0.0",
1620         "1.0.0.0",
1621         &GUID_VendorMicrosoft,
1622         &GUID_MetadataFormatChunkcHRM,
1623         0, 0, 0,
1624         pngchrm_containers
1625     },
1626     {   &CLSID_WICPngGamaMetadataReader,
1627         "The Wine Project",
1628         "Chunk gAMA Reader",
1629         "1.0.0.0",
1630         "1.0.0.0",
1631         &GUID_VendorMicrosoft,
1632         &GUID_MetadataFormatChunkgAMA,
1633         0, 0, 0,
1634         pnggama_containers
1635     },
1636     {   &CLSID_WICPngTextMetadataReader,
1637         "The Wine Project",
1638         "Chunk tEXt Reader",
1639         "1.0.0.0",
1640         "1.0.0.0",
1641         &GUID_VendorMicrosoft,
1642         &GUID_MetadataFormatChunktEXt,
1643         0, 0, 0,
1644         pngtext_containers
1645     },
1646     {   &CLSID_WICLSDMetadataReader,
1647         "The Wine Project",
1648         "Logical Screen Descriptor Reader",
1649         "1.0.0.0",
1650         "1.0.0.0",
1651         &GUID_VendorMicrosoft,
1652         &GUID_MetadataFormatLSD,
1653         0, 0, 0,
1654         lsd_containers
1655     },
1656     {   &CLSID_WICIMDMetadataReader,
1657         "The Wine Project",
1658         "Image Descriptor Reader",
1659         "1.0.0.0",
1660         "1.0.0.0",
1661         &GUID_VendorMicrosoft,
1662         &GUID_MetadataFormatIMD,
1663         0, 0, 0,
1664         imd_containers
1665     },
1666     {   &CLSID_WICGCEMetadataReader,
1667         "The Wine Project",
1668         "Graphic Control Extension Reader",
1669         "1.0.0.0",
1670         "1.0.0.0",
1671         &GUID_VendorMicrosoft,
1672         &GUID_MetadataFormatGCE,
1673         0, 0, 0,
1674         gce_containers
1675     },
1676     {   &CLSID_WICAPEMetadataReader,
1677         "The Wine Project",
1678         "Application Extension Reader",
1679         "1.0.0.0",
1680         "1.0.0.0",
1681         &GUID_VendorMicrosoft,
1682         &GUID_MetadataFormatAPE,
1683         0, 0, 0,
1684         ape_containers
1685     },
1686     {   &CLSID_WICGifCommentMetadataReader,
1687         "The Wine Project",
1688         "Comment Extension Reader",
1689         "1.0.0.0",
1690         "1.0.0.0",
1691         &GUID_VendorMicrosoft,
1692         &GUID_MetadataFormatGifComment,
1693         0, 0, 0,
1694         gif_comment_containers
1695     },
1696     { NULL }			/* list terminator */
1697 };
1698 
1699 static BYTE const channel_mask_1bit[] = { 0x01 };
1700 static BYTE const channel_mask_2bit[] = { 0x03 };
1701 static BYTE const channel_mask_4bit[] = { 0x0f };
1702 
1703 static BYTE const channel_mask_8bit[] = { 0xff, 0x00, 0x00, 0x00 };
1704 static BYTE const channel_mask_8bit2[] = { 0x00, 0xff, 0x00, 0x00 };
1705 static BYTE const channel_mask_8bit3[] = { 0x00, 0x00, 0xff, 0x00 };
1706 static BYTE const channel_mask_8bit4[] = { 0x00, 0x00, 0x00, 0xff };
1707 
1708 static BYTE const channel_mask_16bit[] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1709 static BYTE const channel_mask_16bit2[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
1710 static BYTE const channel_mask_16bit3[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 };
1711 static BYTE const channel_mask_16bit4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1712 
1713 static BYTE const channel_mask_5bit[] = { 0x1f, 0x00 };
1714 static BYTE const channel_mask_5bit2[] = { 0xe0, 0x03 };
1715 static BYTE const channel_mask_5bit3[] = { 0x00, 0x7c };
1716 static BYTE const channel_mask_5bit4[] = { 0x00, 0x80 };
1717 
1718 static BYTE const channel_mask_BGR565_2[] = { 0xe0, 0x07 };
1719 static BYTE const channel_mask_BGR565_3[] = { 0x00, 0xf8 };
1720 
1721 static BYTE const * const channel_masks_1bit[] = { channel_mask_1bit };
1722 static BYTE const * const channel_masks_2bit[] = { channel_mask_2bit };
1723 static BYTE const * const channel_masks_4bit[] = { channel_mask_4bit };
1724 static BYTE const * const channel_masks_8bit[] = { channel_mask_8bit,
1725     channel_mask_8bit2, channel_mask_8bit3, channel_mask_8bit4 };
1726 static BYTE const * const channel_masks_16bit[] = { channel_mask_16bit,
1727     channel_mask_16bit2, channel_mask_16bit3, channel_mask_16bit4};
1728 
1729 static BYTE const * const channel_masks_BGRA5551[] = { channel_mask_5bit,
1730     channel_mask_5bit2, channel_mask_5bit3, channel_mask_5bit4 };
1731 
1732 static BYTE const * const channel_masks_BGR565[] = { channel_mask_5bit,
1733     channel_mask_BGR565_2, channel_mask_BGR565_3 };
1734 
1735 static struct regsvr_pixelformat const pixelformat_list[] = {
1736     {   &GUID_WICPixelFormat1bppIndexed,
1737         "The Wine Project",
1738         "1bpp Indexed",
1739         NULL, /* no version */
1740         &GUID_VendorMicrosoft,
1741         1, /* bitsperpixel */
1742         1, /* channel count */
1743         channel_masks_1bit,
1744         WICPixelFormatNumericRepresentationIndexed,
1745         1
1746     },
1747     {   &GUID_WICPixelFormat2bppIndexed,
1748         "The Wine Project",
1749         "2bpp Indexed",
1750         NULL, /* no version */
1751         &GUID_VendorMicrosoft,
1752         2, /* bitsperpixel */
1753         1, /* channel count */
1754         channel_masks_2bit,
1755         WICPixelFormatNumericRepresentationIndexed,
1756         1
1757     },
1758     {   &GUID_WICPixelFormat4bppIndexed,
1759         "The Wine Project",
1760         "4bpp Indexed",
1761         NULL, /* no version */
1762         &GUID_VendorMicrosoft,
1763         4, /* bitsperpixel */
1764         1, /* channel count */
1765         channel_masks_4bit,
1766         WICPixelFormatNumericRepresentationIndexed,
1767         1
1768     },
1769     {   &GUID_WICPixelFormat8bppIndexed,
1770         "The Wine Project",
1771         "8bpp Indexed",
1772         NULL, /* no version */
1773         &GUID_VendorMicrosoft,
1774         8, /* bitsperpixel */
1775         1, /* channel count */
1776         channel_masks_8bit,
1777         WICPixelFormatNumericRepresentationIndexed,
1778         1
1779     },
1780     {   &GUID_WICPixelFormatBlackWhite,
1781         "The Wine Project",
1782         "Black and White",
1783         NULL, /* no version */
1784         &GUID_VendorMicrosoft,
1785         1, /* bitsperpixel */
1786         1, /* channel count */
1787         channel_masks_1bit,
1788         WICPixelFormatNumericRepresentationUnsignedInteger,
1789         0
1790     },
1791     {   &GUID_WICPixelFormat2bppGray,
1792         "The Wine Project",
1793         "2bpp Grayscale",
1794         NULL, /* no version */
1795         &GUID_VendorMicrosoft,
1796         2, /* bitsperpixel */
1797         1, /* channel count */
1798         channel_masks_2bit,
1799         WICPixelFormatNumericRepresentationUnsignedInteger,
1800         0
1801     },
1802     {   &GUID_WICPixelFormat4bppGray,
1803         "The Wine Project",
1804         "4bpp Grayscale",
1805         NULL, /* no version */
1806         &GUID_VendorMicrosoft,
1807         4, /* bitsperpixel */
1808         1, /* channel count */
1809         channel_masks_4bit,
1810         WICPixelFormatNumericRepresentationUnsignedInteger,
1811         0
1812     },
1813     {   &GUID_WICPixelFormat8bppGray,
1814         "The Wine Project",
1815         "8bpp Grayscale",
1816         NULL, /* no version */
1817         &GUID_VendorMicrosoft,
1818         8, /* bitsperpixel */
1819         1, /* channel count */
1820         channel_masks_8bit,
1821         WICPixelFormatNumericRepresentationUnsignedInteger,
1822         0
1823     },
1824     {   &GUID_WICPixelFormat16bppGray,
1825         "The Wine Project",
1826         "16bpp Grayscale",
1827         NULL, /* no version */
1828         &GUID_VendorMicrosoft,
1829         16, /* bitsperpixel */
1830         1, /* channel count */
1831         channel_masks_16bit,
1832         WICPixelFormatNumericRepresentationUnsignedInteger,
1833         0
1834     },
1835     {   &GUID_WICPixelFormat16bppBGR555,
1836         "The Wine Project",
1837         "16bpp BGR555",
1838         NULL, /* no version */
1839         &GUID_VendorMicrosoft,
1840         16, /* bitsperpixel */
1841         3, /* channel count */
1842         channel_masks_BGRA5551,
1843         WICPixelFormatNumericRepresentationUnsignedInteger,
1844         0
1845     },
1846     {   &GUID_WICPixelFormat16bppBGR565,
1847         "The Wine Project",
1848         "16bpp BGR565",
1849         NULL, /* no version */
1850         &GUID_VendorMicrosoft,
1851         16, /* bitsperpixel */
1852         3, /* channel count */
1853         channel_masks_BGR565,
1854         WICPixelFormatNumericRepresentationUnsignedInteger,
1855         0
1856     },
1857     {   &GUID_WICPixelFormat16bppBGRA5551,
1858         "The Wine Project",
1859         "16bpp BGRA5551",
1860         NULL, /* no version */
1861         &GUID_VendorMicrosoft,
1862         16, /* bitsperpixel */
1863         4, /* channel count */
1864         channel_masks_BGRA5551,
1865         WICPixelFormatNumericRepresentationUnsignedInteger,
1866         1
1867     },
1868     {   &GUID_WICPixelFormat24bppBGR,
1869         "The Wine Project",
1870         "24bpp BGR",
1871         NULL, /* no version */
1872         &GUID_VendorMicrosoft,
1873         24, /* bitsperpixel */
1874         3, /* channel count */
1875         channel_masks_8bit,
1876         WICPixelFormatNumericRepresentationUnsignedInteger,
1877         0
1878     },
1879     {   &GUID_WICPixelFormat24bppRGB,
1880         "The Wine Project",
1881         "24bpp RGB",
1882         NULL, /* no version */
1883         &GUID_VendorMicrosoft,
1884         24, /* bitsperpixel */
1885         3, /* channel count */
1886         channel_masks_8bit,
1887         WICPixelFormatNumericRepresentationUnsignedInteger,
1888         0
1889     },
1890     {   &GUID_WICPixelFormat32bppBGR,
1891         "The Wine Project",
1892         "32bpp BGR",
1893         NULL, /* no version */
1894         &GUID_VendorMicrosoft,
1895         32, /* bitsperpixel */
1896         3, /* channel count */
1897         channel_masks_8bit,
1898         WICPixelFormatNumericRepresentationUnsignedInteger,
1899         0
1900     },
1901     {   &GUID_WICPixelFormat32bppBGRA,
1902         "The Wine Project",
1903         "32bpp BGRA",
1904         NULL, /* no version */
1905         &GUID_VendorMicrosoft,
1906         32, /* bitsperpixel */
1907         4, /* channel count */
1908         channel_masks_8bit,
1909         WICPixelFormatNumericRepresentationUnsignedInteger,
1910         1
1911     },
1912     {   &GUID_WICPixelFormat32bppPBGRA,
1913         "The Wine Project",
1914         "32bpp PBGRA",
1915         NULL, /* no version */
1916         &GUID_VendorMicrosoft,
1917         32, /* bitsperpixel */
1918         4, /* channel count */
1919         channel_masks_8bit,
1920         WICPixelFormatNumericRepresentationUnsignedInteger,
1921         1
1922     },
1923     {   &GUID_WICPixelFormat48bppRGB,
1924         "The Wine Project",
1925         "48bpp RGB",
1926         NULL, /* no version */
1927         &GUID_VendorMicrosoft,
1928         48, /* bitsperpixel */
1929         3, /* channel count */
1930         channel_masks_16bit,
1931         WICPixelFormatNumericRepresentationUnsignedInteger,
1932         0
1933     },
1934     {   &GUID_WICPixelFormat64bppRGBA,
1935         "The Wine Project",
1936         "64bpp RGBA",
1937         NULL, /* no version */
1938         &GUID_VendorMicrosoft,
1939         64, /* bitsperpixel */
1940         4, /* channel count */
1941         channel_masks_16bit,
1942         WICPixelFormatNumericRepresentationUnsignedInteger,
1943         1
1944     },
1945     {   &GUID_WICPixelFormat64bppPRGBA,
1946         "The Wine Project",
1947         "64bpp PRGBA",
1948         NULL, /* no version */
1949         &GUID_VendorMicrosoft,
1950         64, /* bitsperpixel */
1951         4, /* channel count */
1952         channel_masks_16bit,
1953         WICPixelFormatNumericRepresentationUnsignedInteger,
1954         1
1955     },
1956     {   &GUID_WICPixelFormat32bppCMYK,
1957         "The Wine Project",
1958         "32bpp CMYK",
1959         NULL, /* no version */
1960         &GUID_VendorMicrosoft,
1961         32, /* bitsperpixel */
1962         4, /* channel count */
1963         channel_masks_8bit,
1964         WICPixelFormatNumericRepresentationUnsignedInteger,
1965         0
1966     },
1967     { NULL }			/* list terminator */
1968 };
1969 
1970 struct regsvr_category
1971 {
1972     const CLSID *clsid; /* NULL for end of list */
1973 };
1974 
1975 static const struct regsvr_category category_list[] = {
1976     { &CATID_WICBitmapDecoders },
1977     { &CATID_WICBitmapEncoders },
1978     { &CATID_WICFormatConverters },
1979     { &CATID_WICMetadataReader },
1980     { &CATID_WICPixelFormats },
1981     { NULL }
1982 };
1983 
1984 static HRESULT register_categories(const struct regsvr_category *list)
1985 {
1986     LONG res;
1987     WCHAR buf[39];
1988     HKEY coclass_key, categories_key, instance_key;
1989 
1990     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
1991                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
1992     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
1993 
1994     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
1995     res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
1996                           KEY_READ | KEY_WRITE, NULL, &categories_key, NULL);
1997     if (res != ERROR_SUCCESS)
1998     {
1999         RegCloseKey(coclass_key);
2000         return HRESULT_FROM_WIN32(res);
2001     }
2002 
2003     res = RegCreateKeyExW(categories_key, instance_keyname, 0, NULL, 0,
2004                           KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
2005 
2006     for (; res == ERROR_SUCCESS && list->clsid; list++)
2007     {
2008         HKEY instance_clsid_key;
2009 
2010         StringFromGUID2(list->clsid, buf, 39);
2011         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
2012                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
2013         if (res == ERROR_SUCCESS)
2014         {
2015             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
2016                                  (const BYTE *)buf, 78);
2017             RegCloseKey(instance_clsid_key);
2018         }
2019     }
2020 
2021     RegCloseKey(instance_key);
2022     RegCloseKey(categories_key);
2023     RegCloseKey(coclass_key);
2024 
2025     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
2026 }
2027 
2028 static HRESULT unregister_categories(const struct regsvr_category *list)
2029 {
2030     LONG res;
2031     WCHAR buf[39];
2032     HKEY coclass_key, categories_key, instance_key;
2033 
2034     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
2035                         KEY_READ | KEY_WRITE, &coclass_key);
2036     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
2037 
2038     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
2039     res = RegOpenKeyExW(coclass_key, buf, 0,
2040                         KEY_READ | KEY_WRITE, &categories_key);
2041     if (res != ERROR_SUCCESS)
2042     {
2043         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
2044         RegCloseKey(coclass_key);
2045         return HRESULT_FROM_WIN32(res);
2046     }
2047 
2048     res = RegOpenKeyExW(categories_key, instance_keyname, 0,
2049                           KEY_READ | KEY_WRITE, &instance_key);
2050 
2051     for (; res == ERROR_SUCCESS && list->clsid; list++)
2052     {
2053         StringFromGUID2(list->clsid, buf, 39);
2054         res = RegDeleteTreeW(instance_key, buf);
2055     }
2056 
2057     RegCloseKey(instance_key);
2058     RegCloseKey(categories_key);
2059 
2060     StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
2061     res = RegDeleteTreeW(coclass_key, buf);
2062 
2063     RegCloseKey(coclass_key);
2064 
2065     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
2066 }
2067 
2068 extern HRESULT WINAPI WIC_DllRegisterServer(void) DECLSPEC_HIDDEN;
2069 extern HRESULT WINAPI WIC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
2070 
2071 HRESULT WINAPI DllRegisterServer(void)
2072 {
2073     HRESULT hr;
2074 
2075     TRACE("\n");
2076 
2077     hr = WIC_DllRegisterServer();
2078     if (SUCCEEDED(hr))
2079         hr = register_categories(category_list);
2080     if (SUCCEEDED(hr))
2081         hr = register_decoders(decoder_list);
2082     if (SUCCEEDED(hr))
2083         hr = register_encoders(encoder_list);
2084     if (SUCCEEDED(hr))
2085         hr = register_converters(converter_list);
2086     if (SUCCEEDED(hr))
2087         hr = register_metadatareaders(metadatareader_list);
2088     if (SUCCEEDED(hr))
2089         hr = register_pixelformats(pixelformat_list);
2090     return hr;
2091 }
2092 
2093 HRESULT WINAPI DllUnregisterServer(void)
2094 {
2095     HRESULT hr;
2096 
2097     TRACE("\n");
2098 
2099     hr = WIC_DllUnregisterServer();
2100     if (SUCCEEDED(hr))
2101         hr = unregister_categories(category_list);
2102     if (SUCCEEDED(hr))
2103         hr = unregister_decoders(decoder_list);
2104     if (SUCCEEDED(hr))
2105         hr = unregister_encoders(encoder_list);
2106     if (SUCCEEDED(hr))
2107         hr = unregister_converters(converter_list);
2108     if (SUCCEEDED(hr))
2109         hr = unregister_metadatareaders(metadatareader_list);
2110     if (SUCCEEDED(hr))
2111         hr = unregister_pixelformats(pixelformat_list);
2112     return hr;
2113 }
2114