mshtml: Correctly handle NULL nsdoc in IHTMLDocument2::get_body.
[wine] / dlls / windowscodecs / regsvr.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
21 #define COBJMACROS
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "objbase.h"
33 #include "ocidl.h"
34 #include "wincodec.h"
35
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 #include "wincodecs_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
42
43 /***********************************************************************
44  *              interface for self-registering
45  */
46 struct regsvr_coclass
47 {
48     CLSID const *clsid;         /* NULL for end of list */
49     LPCSTR name;                /* can be NULL to omit */
50     LPCSTR ips;                 /* can be NULL to omit */
51     LPCSTR ips32;               /* can be NULL to omit */
52     LPCSTR ips32_tmodel;        /* can be NULL to omit */
53     LPCSTR progid;              /* can be NULL to omit */
54     LPCSTR viprogid;            /* can be NULL to omit */
55     LPCSTR progid_extra;        /* can be NULL to omit */
56 };
57
58 static HRESULT register_coclasses(struct regsvr_coclass const *list);
59 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
60
61 struct decoder_pattern
62 {
63     DWORD length;    /* 0 for end of list */
64     DWORD position;
65     const BYTE *pattern;
66     const BYTE *mask;
67     DWORD endofstream;
68 };
69
70 struct regsvr_decoder
71 {
72     CLSID const *clsid;         /* NULL for end of list */
73     LPCSTR author;
74     LPCSTR friendlyname;
75     LPCSTR version;
76     GUID const *vendor;
77     LPCSTR mimetypes;
78     LPCSTR extensions;
79     GUID const * const *formats;
80     const struct decoder_pattern *patterns;
81 };
82
83 static HRESULT register_decoders(struct regsvr_decoder const *list);
84 static HRESULT unregister_decoders(struct regsvr_decoder const *list);
85
86 struct regsvr_encoder
87 {
88     CLSID const *clsid;         /* NULL for end of list */
89     LPCSTR author;
90     LPCSTR friendlyname;
91     LPCSTR version;
92     GUID const *vendor;
93     LPCSTR mimetypes;
94     LPCSTR extensions;
95     GUID const * const *formats;
96 };
97
98 static HRESULT register_encoders(struct regsvr_encoder const *list);
99 static HRESULT unregister_encoders(struct regsvr_encoder const *list);
100
101 struct regsvr_converter
102 {
103     CLSID const *clsid;         /* NULL for end of list */
104     LPCSTR author;
105     LPCSTR friendlyname;
106     LPCSTR version;
107     GUID const *vendor;
108     GUID const * const *formats;
109 };
110
111 static HRESULT register_converters(struct regsvr_converter const *list);
112 static HRESULT unregister_converters(struct regsvr_converter const *list);
113
114 /***********************************************************************
115  *              static string constants
116  */
117 static WCHAR const clsid_keyname[6] = {
118     'C', 'L', 'S', 'I', 'D', 0 };
119 static WCHAR const curver_keyname[7] = {
120     'C', 'u', 'r', 'V', 'e', 'r', 0 };
121 static WCHAR const ips_keyname[13] = {
122     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
123     0 };
124 static WCHAR const ips32_keyname[15] = {
125     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
126     '3', '2', 0 };
127 static WCHAR const progid_keyname[7] = {
128     'P', 'r', 'o', 'g', 'I', 'D', 0 };
129 static WCHAR const viprogid_keyname[25] = {
130     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
131     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
132     0 };
133 static char const tmodel_valuename[] = "ThreadingModel";
134 static char const author_valuename[] = "Author";
135 static char const friendlyname_valuename[] = "FriendlyName";
136 static WCHAR const vendor_valuename[] = {'V','e','n','d','o','r',0};
137 static char const version_valuename[] = "Version";
138 static char const mimetypes_valuename[] = "MimeTypes";
139 static char const extensions_valuename[] = "FileExtensions";
140 static WCHAR const formats_keyname[] = {'F','o','r','m','a','t','s',0};
141 static WCHAR const patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
142 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
143 static WCHAR const clsid_valuename[] = {'C','L','S','I','D',0};
144 static char const length_valuename[] = "Length";
145 static char const position_valuename[] = "Position";
146 static char const pattern_valuename[] = "Pattern";
147 static char const mask_valuename[] = "Mask";
148 static char const endofstream_valuename[] = "EndOfStream";
149 static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
150
151 /***********************************************************************
152  *              static helper functions
153  */
154 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
155                                    WCHAR const *value);
156 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
157                                    char const *value);
158 static LONG register_progid(WCHAR const *clsid,
159                             char const *progid, char const *curver_progid,
160                             char const *name, char const *extra);
161
162 /***********************************************************************
163  *              register_coclasses
164  */
165 static HRESULT register_coclasses(struct regsvr_coclass const *list)
166 {
167     LONG res = ERROR_SUCCESS;
168     HKEY coclass_key;
169
170     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
171                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
172     if (res != ERROR_SUCCESS) goto error_return;
173
174     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
175         WCHAR buf[39];
176         HKEY clsid_key;
177
178         StringFromGUID2(list->clsid, buf, 39);
179         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
180                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
181         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
182
183         if (list->name) {
184             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
185                                  (CONST BYTE*)(list->name),
186                                  strlen(list->name) + 1);
187             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
188         }
189
190         if (list->ips) {
191             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
192             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
193         }
194
195         if (list->ips32) {
196             HKEY ips32_key;
197
198             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
199                                   KEY_READ | KEY_WRITE, NULL,
200                                   &ips32_key, NULL);
201             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
202
203             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
204                                  (CONST BYTE*)list->ips32,
205                                  lstrlenA(list->ips32) + 1);
206             if (res == ERROR_SUCCESS && list->ips32_tmodel)
207                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
208                                      (CONST BYTE*)list->ips32_tmodel,
209                                      strlen(list->ips32_tmodel) + 1);
210             RegCloseKey(ips32_key);
211             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
212         }
213
214         if (list->progid) {
215             res = register_key_defvalueA(clsid_key, progid_keyname,
216                                          list->progid);
217             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
218
219             res = register_progid(buf, list->progid, NULL,
220                                   list->name, list->progid_extra);
221             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
222         }
223
224         if (list->viprogid) {
225             res = register_key_defvalueA(clsid_key, viprogid_keyname,
226                                          list->viprogid);
227             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
228
229             res = register_progid(buf, list->viprogid, list->progid,
230                                   list->name, list->progid_extra);
231             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
232         }
233
234     error_close_clsid_key:
235         RegCloseKey(clsid_key);
236     }
237
238 error_close_coclass_key:
239     RegCloseKey(coclass_key);
240 error_return:
241     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
242 }
243
244 /***********************************************************************
245  *              unregister_coclasses
246  */
247 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
248 {
249     LONG res = ERROR_SUCCESS;
250     HKEY coclass_key;
251
252     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
253                         KEY_READ | KEY_WRITE, &coclass_key);
254     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
255     if (res != ERROR_SUCCESS) goto error_return;
256
257     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
258         WCHAR buf[39];
259
260         StringFromGUID2(list->clsid, buf, 39);
261         res = RegDeleteTreeW(coclass_key, buf);
262         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
263         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
264
265         if (list->progid) {
266             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
267             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
268             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
269         }
270
271         if (list->viprogid) {
272             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
273             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
274             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
275         }
276     }
277
278 error_close_coclass_key:
279     RegCloseKey(coclass_key);
280 error_return:
281     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
282 }
283
284 /***********************************************************************
285  *              register_decoders
286  */
287 static HRESULT register_decoders(struct regsvr_decoder const *list)
288 {
289     LONG res = ERROR_SUCCESS;
290     HKEY coclass_key;
291     WCHAR buf[39];
292     HKEY decoders_key;
293     HKEY instance_key;
294
295     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
296                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
297     if (res == ERROR_SUCCESS)  {
298         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
299         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
300                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
301         if (res == ERROR_SUCCESS)
302         {
303             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
304                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
305             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
306         }
307         if (res != ERROR_SUCCESS)
308             RegCloseKey(coclass_key);
309     }
310     if (res != ERROR_SUCCESS) goto error_return;
311
312     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
313         HKEY clsid_key;
314         HKEY instance_clsid_key;
315
316         StringFromGUID2(list->clsid, buf, 39);
317         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
318                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
319         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
320
321         StringFromGUID2(list->clsid, buf, 39);
322         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
323                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
324         if (res == ERROR_SUCCESS) {
325             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
326                                  (CONST BYTE*)(buf), 78);
327             RegCloseKey(instance_clsid_key);
328         }
329         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
330
331         if (list->author) {
332             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
333                                  (CONST BYTE*)(list->author),
334                                  strlen(list->author) + 1);
335             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
336         }
337
338         if (list->friendlyname) {
339             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
340                                  (CONST BYTE*)(list->friendlyname),
341                                  strlen(list->friendlyname) + 1);
342             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
343         }
344
345         if (list->vendor) {
346             StringFromGUID2(list->vendor, buf, 39);
347             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
348                                  (CONST BYTE*)(buf), 78);
349             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
350         }
351
352         if (list->version) {
353             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
354                                  (CONST BYTE*)(list->version),
355                                  strlen(list->version) + 1);
356             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
357         }
358
359         if (list->mimetypes) {
360             res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
361                                  (CONST BYTE*)(list->mimetypes),
362                                  strlen(list->mimetypes) + 1);
363             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
364         }
365
366         if (list->extensions) {
367             res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
368                                  (CONST BYTE*)(list->extensions),
369                                  strlen(list->extensions) + 1);
370             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
371         }
372
373         if (list->formats) {
374             HKEY formats_key;
375             GUID const * const *format;
376
377             res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
378                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
379             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
380             for (format=list->formats; *format; ++format)
381             {
382                 HKEY format_key;
383                 StringFromGUID2(*format, buf, 39);
384                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
385                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
386                 if (res != ERROR_SUCCESS) break;
387                 RegCloseKey(format_key);
388             }
389             RegCloseKey(formats_key);
390             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
391         }
392
393         if (list->patterns) {
394             HKEY patterns_key;
395             int i;
396
397             res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
398                                   KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
399             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
400             for (i=0; list->patterns[i].length; i++)
401             {
402                 HKEY pattern_key;
403                 static const WCHAR int_format[] = {'%','i',0};
404                 snprintfW(buf, 39, int_format, i);
405                 res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
406                                       KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
407                 if (res != ERROR_SUCCESS) break;
408                 res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
409                                      (CONST BYTE*)(&list->patterns[i].length), 4);
410                 if (res == ERROR_SUCCESS)
411                     res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
412                                          (CONST BYTE*)(&list->patterns[i].position), 4);
413                 if (res == ERROR_SUCCESS)
414                     res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
415                                          list->patterns[i].pattern,
416                                          list->patterns[i].length);
417                 if (res == ERROR_SUCCESS)
418                     res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
419                                          list->patterns[i].mask,
420                                          list->patterns[i].length);
421                 if (res == ERROR_SUCCESS)
422                     res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
423                                          (CONST BYTE*)&(list->patterns[i].endofstream), 4);
424                 RegCloseKey(pattern_key);
425             }
426             RegCloseKey(patterns_key);
427             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
428         }
429
430     error_close_clsid_key:
431         RegCloseKey(clsid_key);
432     }
433
434 error_close_coclass_key:
435     RegCloseKey(instance_key);
436     RegCloseKey(decoders_key);
437     RegCloseKey(coclass_key);
438 error_return:
439     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
440 }
441
442 /***********************************************************************
443  *              unregister_decoders
444  */
445 static HRESULT unregister_decoders(struct regsvr_decoder const *list)
446 {
447     LONG res = ERROR_SUCCESS;
448     HKEY coclass_key;
449     WCHAR buf[39];
450     HKEY decoders_key;
451     HKEY instance_key;
452
453     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
454                         KEY_READ | KEY_WRITE, &coclass_key);
455     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
456
457     if (res == ERROR_SUCCESS)  {
458         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
459         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
460                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
461         if (res == ERROR_SUCCESS)
462         {
463             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
464                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
465             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
466         }
467         if (res != ERROR_SUCCESS)
468             RegCloseKey(coclass_key);
469     }
470     if (res != ERROR_SUCCESS) goto error_return;
471
472     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
473         StringFromGUID2(list->clsid, buf, 39);
474
475         res = RegDeleteTreeW(coclass_key, buf);
476         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
477         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
478
479         res = RegDeleteTreeW(instance_key, buf);
480         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
481         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
482     }
483
484 error_close_coclass_key:
485     RegCloseKey(instance_key);
486     RegCloseKey(decoders_key);
487     RegCloseKey(coclass_key);
488 error_return:
489     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
490 }
491
492 /***********************************************************************
493  *              register_encoders
494  */
495 static HRESULT register_encoders(struct regsvr_encoder const *list)
496 {
497     LONG res = ERROR_SUCCESS;
498     HKEY coclass_key;
499     WCHAR buf[39];
500     HKEY encoders_key;
501     HKEY instance_key;
502
503     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
504                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
505     if (res == ERROR_SUCCESS)  {
506         StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
507         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
508                               KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
509         if (res == ERROR_SUCCESS)
510         {
511             res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
512                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
513             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
514         }
515         if (res != ERROR_SUCCESS)
516             RegCloseKey(coclass_key);
517     }
518     if (res != ERROR_SUCCESS) goto error_return;
519
520     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
521         HKEY clsid_key;
522         HKEY instance_clsid_key;
523
524         StringFromGUID2(list->clsid, buf, 39);
525         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
526                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
527         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
528
529         StringFromGUID2(list->clsid, buf, 39);
530         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
531                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
532         if (res == ERROR_SUCCESS) {
533             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
534                                  (CONST BYTE*)(buf), 78);
535             RegCloseKey(instance_clsid_key);
536         }
537         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
538
539         if (list->author) {
540             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
541                                  (CONST BYTE*)(list->author),
542                                  strlen(list->author) + 1);
543             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
544         }
545
546         if (list->friendlyname) {
547             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
548                                  (CONST BYTE*)(list->friendlyname),
549                                  strlen(list->friendlyname) + 1);
550             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
551         }
552
553         if (list->vendor) {
554             StringFromGUID2(list->vendor, buf, 39);
555             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
556                                  (CONST BYTE*)(buf), 78);
557             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
558         }
559
560         if (list->version) {
561             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
562                                  (CONST BYTE*)(list->version),
563                                  strlen(list->version) + 1);
564             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
565         }
566
567         if (list->mimetypes) {
568             res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
569                                  (CONST BYTE*)(list->mimetypes),
570                                  strlen(list->mimetypes) + 1);
571             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
572         }
573
574         if (list->extensions) {
575             res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
576                                  (CONST BYTE*)(list->extensions),
577                                  strlen(list->extensions) + 1);
578             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
579         }
580
581         if (list->formats) {
582             HKEY formats_key;
583             GUID const * const *format;
584
585             res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
586                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
587             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
588             for (format=list->formats; *format; ++format)
589             {
590                 HKEY format_key;
591                 StringFromGUID2(*format, buf, 39);
592                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
593                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
594                 if (res != ERROR_SUCCESS) break;
595                 RegCloseKey(format_key);
596             }
597             RegCloseKey(formats_key);
598             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
599         }
600
601     error_close_clsid_key:
602         RegCloseKey(clsid_key);
603     }
604
605 error_close_coclass_key:
606     RegCloseKey(instance_key);
607     RegCloseKey(encoders_key);
608     RegCloseKey(coclass_key);
609 error_return:
610     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
611 }
612
613 /***********************************************************************
614  *              unregister_encoders
615  */
616 static HRESULT unregister_encoders(struct regsvr_encoder const *list)
617 {
618     LONG res = ERROR_SUCCESS;
619     HKEY coclass_key;
620     WCHAR buf[39];
621     HKEY encoders_key;
622     HKEY instance_key;
623
624     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
625                         KEY_READ | KEY_WRITE, &coclass_key);
626     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
627
628     if (res == ERROR_SUCCESS)  {
629         StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
630         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
631                               KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
632         if (res == ERROR_SUCCESS)
633         {
634             res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
635                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
636             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
637         }
638         if (res != ERROR_SUCCESS)
639             RegCloseKey(coclass_key);
640     }
641     if (res != ERROR_SUCCESS) goto error_return;
642
643     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
644         StringFromGUID2(list->clsid, buf, 39);
645
646         res = RegDeleteTreeW(coclass_key, buf);
647         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
648         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
649
650         res = RegDeleteTreeW(instance_key, buf);
651         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
652         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
653     }
654
655 error_close_coclass_key:
656     RegCloseKey(instance_key);
657     RegCloseKey(encoders_key);
658     RegCloseKey(coclass_key);
659 error_return:
660     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
661 }
662
663 /***********************************************************************
664  *              register_converters
665  */
666 static HRESULT register_converters(struct regsvr_converter const *list)
667 {
668     LONG res = ERROR_SUCCESS;
669     HKEY coclass_key;
670     WCHAR buf[39];
671     HKEY converters_key;
672     HKEY instance_key;
673
674     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
675                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
676     if (res == ERROR_SUCCESS)  {
677         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
678         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
679                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
680         if (res == ERROR_SUCCESS)
681         {
682             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
683                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
684             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
685         }
686         if (res != ERROR_SUCCESS)
687             RegCloseKey(coclass_key);
688     }
689     if (res != ERROR_SUCCESS) goto error_return;
690
691     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
692         HKEY clsid_key;
693         HKEY instance_clsid_key;
694
695         StringFromGUID2(list->clsid, buf, 39);
696         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
697                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
698         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
699
700         StringFromGUID2(list->clsid, buf, 39);
701         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
702                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
703         if (res == ERROR_SUCCESS) {
704             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
705                                  (CONST BYTE*)(buf), 78);
706             RegCloseKey(instance_clsid_key);
707         }
708         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
709
710         if (list->author) {
711             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
712                                  (CONST BYTE*)(list->author),
713                                  strlen(list->author) + 1);
714             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
715         }
716
717         if (list->friendlyname) {
718             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
719                                  (CONST BYTE*)(list->friendlyname),
720                                  strlen(list->friendlyname) + 1);
721             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
722         }
723
724         if (list->vendor) {
725             StringFromGUID2(list->vendor, buf, 39);
726             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
727                                  (CONST BYTE*)(buf), 78);
728             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
729         }
730
731         if (list->version) {
732             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
733                                  (CONST BYTE*)(list->version),
734                                  strlen(list->version) + 1);
735             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
736         }
737
738         if (list->formats) {
739             HKEY formats_key;
740             GUID const * const *format;
741
742             res = RegCreateKeyExW(clsid_key, pixelformats_keyname, 0, NULL, 0,
743                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
744             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
745             for (format=list->formats; *format; ++format)
746             {
747                 HKEY format_key;
748                 StringFromGUID2(*format, buf, 39);
749                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
750                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
751                 if (res != ERROR_SUCCESS) break;
752                 RegCloseKey(format_key);
753             }
754             RegCloseKey(formats_key);
755             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
756         }
757
758     error_close_clsid_key:
759         RegCloseKey(clsid_key);
760     }
761
762 error_close_coclass_key:
763     RegCloseKey(instance_key);
764     RegCloseKey(converters_key);
765     RegCloseKey(coclass_key);
766 error_return:
767     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
768 }
769
770 /***********************************************************************
771  *              unregister_converters
772  */
773 static HRESULT unregister_converters(struct regsvr_converter const *list)
774 {
775     LONG res = ERROR_SUCCESS;
776     HKEY coclass_key;
777     WCHAR buf[39];
778     HKEY converters_key;
779     HKEY instance_key;
780
781     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
782                         KEY_READ | KEY_WRITE, &coclass_key);
783     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
784
785     if (res == ERROR_SUCCESS)  {
786         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
787         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
788                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
789         if (res == ERROR_SUCCESS)
790         {
791             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
792                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
793             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
794         }
795         if (res != ERROR_SUCCESS)
796             RegCloseKey(coclass_key);
797     }
798     if (res != ERROR_SUCCESS) goto error_return;
799
800     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
801         StringFromGUID2(list->clsid, buf, 39);
802
803         res = RegDeleteTreeW(coclass_key, buf);
804         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
805         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
806
807         res = RegDeleteTreeW(instance_key, buf);
808         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
809         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
810     }
811
812 error_close_coclass_key:
813     RegCloseKey(instance_key);
814     RegCloseKey(converters_key);
815     RegCloseKey(coclass_key);
816 error_return:
817     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
818 }
819
820 /***********************************************************************
821  *              register_key_defvalueW
822  */
823 static LONG register_key_defvalueW(
824     HKEY base,
825     WCHAR const *name,
826     WCHAR const *value)
827 {
828     LONG res;
829     HKEY key;
830
831     res = RegCreateKeyExW(base, name, 0, NULL, 0,
832                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
833     if (res != ERROR_SUCCESS) return res;
834     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
835                          (lstrlenW(value) + 1) * sizeof(WCHAR));
836     RegCloseKey(key);
837     return res;
838 }
839
840 /***********************************************************************
841  *              register_key_defvalueA
842  */
843 static LONG register_key_defvalueA(
844     HKEY base,
845     WCHAR const *name,
846     char const *value)
847 {
848     LONG res;
849     HKEY key;
850
851     res = RegCreateKeyExW(base, name, 0, NULL, 0,
852                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
853     if (res != ERROR_SUCCESS) return res;
854     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
855                          lstrlenA(value) + 1);
856     RegCloseKey(key);
857     return res;
858 }
859
860 /***********************************************************************
861  *              register_progid
862  */
863 static LONG register_progid(
864     WCHAR const *clsid,
865     char const *progid,
866     char const *curver_progid,
867     char const *name,
868     char const *extra)
869 {
870     LONG res;
871     HKEY progid_key;
872
873     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
874                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
875                           &progid_key, NULL);
876     if (res != ERROR_SUCCESS) return res;
877
878     if (name) {
879         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
880                              (CONST BYTE*)name, strlen(name) + 1);
881         if (res != ERROR_SUCCESS) goto error_close_progid_key;
882     }
883
884     if (clsid) {
885         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
886         if (res != ERROR_SUCCESS) goto error_close_progid_key;
887     }
888
889     if (curver_progid) {
890         res = register_key_defvalueA(progid_key, curver_keyname,
891                                      curver_progid);
892         if (res != ERROR_SUCCESS) goto error_close_progid_key;
893     }
894
895     if (extra) {
896         HKEY extra_key;
897
898         res = RegCreateKeyExA(progid_key, extra, 0,
899                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
900                               &extra_key, NULL);
901         if (res == ERROR_SUCCESS)
902             RegCloseKey(extra_key);
903     }
904
905 error_close_progid_key:
906     RegCloseKey(progid_key);
907     return res;
908 }
909
910 /***********************************************************************
911  *              coclass list
912  */
913 static struct regsvr_coclass const coclass_list[] = {
914     {   &CLSID_WICImagingFactory,
915         "WIC Imaging Factory",
916         NULL,
917         "windowscodecs.dll",
918         "Both"
919     },
920     {   &CLSID_WICBmpDecoder,
921         "WIC BMP Decoder",
922         NULL,
923         "windowscodecs.dll",
924         "Both"
925     },
926     {   &CLSID_WICPngDecoder,
927         "WIC PNG Decoder",
928         NULL,
929         "windowscodecs.dll",
930         "Both"
931     },
932     {   &CLSID_WICPngEncoder,
933         "WIC PNG Encoder",
934         NULL,
935         "windowscodecs.dll",
936         "Both"
937     },
938     {   &CLSID_WICBmpEncoder,
939         "WIC BMP Encoder",
940         NULL,
941         "windowscodecs.dll",
942         "Apartment"
943     },
944     {   &CLSID_WICGifDecoder,
945         "WIC GIF Decoder",
946         NULL,
947         "windowscodecs.dll",
948         "Both"
949     },
950     {   &CLSID_WICIcoDecoder,
951         "WIC ICO Decoder",
952         NULL,
953         "windowscodecs.dll",
954         "Both"
955     },
956     {   &CLSID_WICJpegDecoder,
957         "WIC JPEG Decoder",
958         NULL,
959         "windowscodecs.dll",
960         "Both"
961     },
962     {   &CLSID_WICTiffDecoder,
963         "WIC TIFF Decoder",
964         NULL,
965         "windowscodecs.dll",
966         "Both"
967     },
968     {
969         &CLSID_WICIcnsEncoder,
970         "WIC ICNS Encoder",
971         NULL,
972         "windowscodecs.dll",
973         "Both"
974     },
975     {   &CLSID_WICDefaultFormatConverter,
976         "WIC Default Format Converter",
977         NULL,
978         "windowscodecs.dll",
979         "Both"
980     },
981     {   &CLSID_WineTgaDecoder,
982         "WIC TGA Decoder",
983         NULL,
984         "windowscodecs.dll",
985         "Both"
986     },
987     { NULL }                    /* list terminator */
988 };
989
990 /***********************************************************************
991  *              decoder list
992  */
993 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
994
995 static const BYTE bmp_magic[] = {0x42,0x4d};
996
997 static GUID const * const bmp_formats[] = {
998     &GUID_WICPixelFormat1bppIndexed,
999     &GUID_WICPixelFormat2bppIndexed,
1000     &GUID_WICPixelFormat4bppIndexed,
1001     &GUID_WICPixelFormat8bppIndexed,
1002     &GUID_WICPixelFormat16bppBGR555,
1003     &GUID_WICPixelFormat16bppBGR565,
1004     &GUID_WICPixelFormat24bppBGR,
1005     &GUID_WICPixelFormat32bppBGR,
1006     &GUID_WICPixelFormat32bppBGRA,
1007     NULL
1008 };
1009
1010 static struct decoder_pattern const bmp_patterns[] = {
1011     {2,0,bmp_magic,mask_all,0},
1012     {0}
1013 };
1014
1015 static const BYTE gif87a_magic[6] = "GIF87a";
1016 static const BYTE gif89a_magic[6] = "GIF89a";
1017
1018 static GUID const * const gif_formats[] = {
1019     &GUID_WICPixelFormat8bppIndexed,
1020     NULL
1021 };
1022
1023 static struct decoder_pattern const gif_patterns[] = {
1024     {6,0,gif87a_magic,mask_all,0},
1025     {6,0,gif89a_magic,mask_all,0},
1026     {0}
1027 };
1028
1029 static const BYTE ico_magic[] = {00,00,01,00};
1030
1031 static GUID const * const ico_formats[] = {
1032     &GUID_WICPixelFormat32bppBGRA,
1033     NULL
1034 };
1035
1036 static struct decoder_pattern const ico_patterns[] = {
1037     {4,0,ico_magic,mask_all,0},
1038     {0}
1039 };
1040
1041 static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
1042
1043 static GUID const * const jpeg_formats[] = {
1044     &GUID_WICPixelFormat24bppBGR,
1045     &GUID_WICPixelFormat32bppCMYK,
1046     &GUID_WICPixelFormat8bppGray,
1047     NULL
1048 };
1049
1050 static struct decoder_pattern const jpeg_patterns[] = {
1051     {4,0,jpeg_magic,mask_all,0},
1052     {0}
1053 };
1054
1055 static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
1056
1057 static GUID const * const png_formats[] = {
1058     &GUID_WICPixelFormatBlackWhite,
1059     &GUID_WICPixelFormat2bppGray,
1060     &GUID_WICPixelFormat4bppGray,
1061     &GUID_WICPixelFormat8bppGray,
1062     &GUID_WICPixelFormat16bppGray,
1063     &GUID_WICPixelFormat32bppBGRA,
1064     &GUID_WICPixelFormat64bppRGBA,
1065     &GUID_WICPixelFormat1bppIndexed,
1066     &GUID_WICPixelFormat2bppIndexed,
1067     &GUID_WICPixelFormat4bppIndexed,
1068     &GUID_WICPixelFormat8bppIndexed,
1069     &GUID_WICPixelFormat24bppBGR,
1070     &GUID_WICPixelFormat48bppRGB,
1071     NULL
1072 };
1073
1074 static struct decoder_pattern const png_patterns[] = {
1075     {8,0,png_magic,mask_all,0},
1076     {0}
1077 };
1078
1079 static const BYTE tiff_magic_le[] = {0x49,0x49,42,0};
1080 static const BYTE tiff_magic_be[] = {0x4d,0x4d,0,42};
1081
1082 static GUID const * const tiff_formats[] = {
1083     &GUID_WICPixelFormatBlackWhite,
1084     &GUID_WICPixelFormat4bppGray,
1085     &GUID_WICPixelFormat8bppGray,
1086     &GUID_WICPixelFormat4bppIndexed,
1087     &GUID_WICPixelFormat8bppIndexed,
1088     &GUID_WICPixelFormat32bppBGR,
1089     &GUID_WICPixelFormat32bppBGRA,
1090     &GUID_WICPixelFormat32bppPBGRA,
1091     &GUID_WICPixelFormat48bppRGB,
1092     &GUID_WICPixelFormat64bppRGBA,
1093     &GUID_WICPixelFormat64bppPRGBA,
1094     NULL
1095 };
1096
1097 static struct decoder_pattern const tiff_patterns[] = {
1098     {4,0,tiff_magic_le,mask_all,0},
1099     {4,0,tiff_magic_be,mask_all,0},
1100     {0}
1101 };
1102
1103 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
1104
1105 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};
1106 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};
1107
1108 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};
1109 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};
1110
1111 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};
1112 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};
1113
1114 static GUID const * const tga_formats[] = {
1115     &GUID_WICPixelFormat8bppGray,
1116     &GUID_WICPixelFormat8bppIndexed,
1117     &GUID_WICPixelFormat16bppGray,
1118     &GUID_WICPixelFormat16bppBGR555,
1119     &GUID_WICPixelFormat24bppBGR,
1120     &GUID_WICPixelFormat32bppBGRA,
1121     &GUID_WICPixelFormat32bppPBGRA,
1122     NULL
1123 };
1124
1125 static struct decoder_pattern const tga_patterns[] = {
1126     {18,18,tga_footer_magic,mask_all,1},
1127     {18,0,tga_indexed_magic,tga_indexed_mask,0},
1128     {18,0,tga_truecolor_magic,tga_truecolor_mask,0},
1129     {18,0,tga_grayscale_magic,tga_grayscale_mask,0},
1130     {0}
1131 };
1132
1133 static struct regsvr_decoder const decoder_list[] = {
1134     {   &CLSID_WICBmpDecoder,
1135         "The Wine Project",
1136         "BMP Decoder",
1137         "1.0.0.0",
1138         &GUID_VendorMicrosoft,
1139         "image/bmp",
1140         ".bmp,.dib,.rle",
1141         bmp_formats,
1142         bmp_patterns
1143     },
1144     {   &CLSID_WICGifDecoder,
1145         "The Wine Project",
1146         "GIF Decoder",
1147         "1.0.0.0",
1148         &GUID_VendorMicrosoft,
1149         "image/gif",
1150         ".gif",
1151         gif_formats,
1152         gif_patterns
1153     },
1154     {   &CLSID_WICIcoDecoder,
1155         "The Wine Project",
1156         "ICO Decoder",
1157         "1.0.0.0",
1158         &GUID_VendorMicrosoft,
1159         "image/vnd.microsoft.icon",
1160         ".ico",
1161         ico_formats,
1162         ico_patterns
1163     },
1164     {   &CLSID_WICJpegDecoder,
1165         "The Wine Project",
1166         "JPEG Decoder",
1167         "1.0.0.0",
1168         &GUID_VendorMicrosoft,
1169         "image/jpeg",
1170         ".jpg;.jpeg;.jfif",
1171         jpeg_formats,
1172         jpeg_patterns
1173     },
1174     {   &CLSID_WICPngDecoder,
1175         "The Wine Project",
1176         "PNG Decoder",
1177         "1.0.0.0",
1178         &GUID_VendorMicrosoft,
1179         "image/png",
1180         ".png",
1181         png_formats,
1182         png_patterns
1183     },
1184     {   &CLSID_WICTiffDecoder,
1185         "The Wine Project",
1186         "TIFF Decoder",
1187         "1.0.0.0",
1188         &GUID_VendorMicrosoft,
1189         "image/tiff",
1190         ".tif;.tiff",
1191         tiff_formats,
1192         tiff_patterns
1193     },
1194     {   &CLSID_WineTgaDecoder,
1195         "The Wine Project",
1196         "TGA Decoder",
1197         "1.0.0.0",
1198         &GUID_VendorWine,
1199         "image/x-targa",
1200         ".tga;.tpic",
1201         tga_formats,
1202         tga_patterns
1203     },
1204     { NULL }                    /* list terminator */
1205 };
1206
1207 static GUID const * const bmp_encode_formats[] = {
1208     &GUID_WICPixelFormat16bppBGR555,
1209     &GUID_WICPixelFormat16bppBGR565,
1210     &GUID_WICPixelFormat24bppBGR,
1211     &GUID_WICPixelFormat32bppBGR,
1212     NULL
1213 };
1214
1215 static GUID const * const png_encode_formats[] = {
1216     &GUID_WICPixelFormat24bppBGR,
1217     &GUID_WICPixelFormatBlackWhite,
1218     &GUID_WICPixelFormat2bppGray,
1219     &GUID_WICPixelFormat4bppGray,
1220     &GUID_WICPixelFormat8bppGray,
1221     &GUID_WICPixelFormat16bppGray,
1222     &GUID_WICPixelFormat32bppBGR,
1223     &GUID_WICPixelFormat32bppBGRA,
1224     &GUID_WICPixelFormat48bppRGB,
1225     &GUID_WICPixelFormat64bppRGBA,
1226     NULL
1227 };
1228
1229 static GUID const * const icns_encode_formats[] = {
1230     &GUID_WICPixelFormat32bppBGRA,
1231     NULL
1232 };
1233
1234 static struct regsvr_encoder const encoder_list[] = {
1235     {   &CLSID_WICBmpEncoder,
1236         "The Wine Project",
1237         "BMP Encoder",
1238         "1.0.0.0",
1239         &GUID_VendorMicrosoft,
1240         "image/bmp",
1241         ".bmp,.dib,.rle",
1242         bmp_encode_formats
1243     },
1244     {   &CLSID_WICPngEncoder,
1245         "The Wine Project",
1246         "PNG Encoder",
1247         "1.0.0.0",
1248         &GUID_VendorMicrosoft,
1249         "image/png",
1250         ".png",
1251         png_encode_formats
1252     },
1253     {   &CLSID_WICIcnsEncoder,
1254         "The Wine Project",
1255         "ICNS Encoder",
1256         "1.0.0.0",
1257         &GUID_VendorWine,
1258         "image/icns",
1259         ".icns",
1260         icns_encode_formats
1261     },
1262     { NULL }                    /* list terminator */
1263 };
1264
1265 static GUID const * const converter_formats[] = {
1266     &GUID_WICPixelFormat1bppIndexed,
1267     &GUID_WICPixelFormat2bppIndexed,
1268     &GUID_WICPixelFormat4bppIndexed,
1269     &GUID_WICPixelFormat8bppIndexed,
1270     &GUID_WICPixelFormatBlackWhite,
1271     &GUID_WICPixelFormat2bppGray,
1272     &GUID_WICPixelFormat4bppGray,
1273     &GUID_WICPixelFormat8bppGray,
1274     &GUID_WICPixelFormat16bppGray,
1275     &GUID_WICPixelFormat16bppBGR555,
1276     &GUID_WICPixelFormat16bppBGR565,
1277     &GUID_WICPixelFormat16bppBGRA5551,
1278     &GUID_WICPixelFormat24bppBGR,
1279     &GUID_WICPixelFormat32bppBGR,
1280     &GUID_WICPixelFormat32bppBGRA,
1281     &GUID_WICPixelFormat48bppRGB,
1282     &GUID_WICPixelFormat64bppRGBA,
1283     &GUID_WICPixelFormat32bppCMYK,
1284     NULL
1285 };
1286
1287 static struct regsvr_converter const converter_list[] = {
1288     {   &CLSID_WICDefaultFormatConverter,
1289         "The Wine Project",
1290         "Default Pixel Format Converter",
1291         "1.0.0.0",
1292         &GUID_VendorMicrosoft,
1293         converter_formats
1294     },
1295     { NULL }                    /* list terminator */
1296 };
1297
1298 extern HRESULT WINAPI WIC_DllRegisterServer(void) DECLSPEC_HIDDEN;
1299 extern HRESULT WINAPI WIC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
1300
1301 HRESULT WINAPI DllRegisterServer(void)
1302 {
1303     HRESULT hr;
1304
1305     TRACE("\n");
1306
1307     hr = WIC_DllRegisterServer();
1308     if (SUCCEEDED(hr))
1309         hr = register_coclasses(coclass_list);
1310     if (SUCCEEDED(hr))
1311         register_decoders(decoder_list);
1312     if (SUCCEEDED(hr))
1313         register_encoders(encoder_list);
1314     if (SUCCEEDED(hr))
1315         register_converters(converter_list);
1316     return hr;
1317 }
1318
1319 HRESULT WINAPI DllUnregisterServer(void)
1320 {
1321     HRESULT hr;
1322
1323     TRACE("\n");
1324
1325     hr = WIC_DllUnregisterServer();
1326     if (SUCCEEDED(hr))
1327         hr = unregister_coclasses(coclass_list);
1328     if (SUCCEEDED(hr))
1329         unregister_decoders(decoder_list);
1330     if (SUCCEEDED(hr))
1331         unregister_encoders(encoder_list);
1332     if (SUCCEEDED(hr))
1333         unregister_converters(converter_list);
1334     return hr;
1335 }