shell32/tests: Add some tests related to the shellview created by ExplorerBrowser.
[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_converter
87 {
88     CLSID const *clsid;         /* NULL for end of list */
89     LPCSTR author;
90     LPCSTR friendlyname;
91     LPCSTR version;
92     GUID const *vendor;
93     GUID const * const *formats;
94 };
95
96 static HRESULT register_converters(struct regsvr_converter const *list);
97 static HRESULT unregister_converters(struct regsvr_converter const *list);
98
99 /***********************************************************************
100  *              static string constants
101  */
102 static WCHAR const clsid_keyname[6] = {
103     'C', 'L', 'S', 'I', 'D', 0 };
104 static WCHAR const curver_keyname[7] = {
105     'C', 'u', 'r', 'V', 'e', 'r', 0 };
106 static WCHAR const ips_keyname[13] = {
107     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
108     0 };
109 static WCHAR const ips32_keyname[15] = {
110     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
111     '3', '2', 0 };
112 static WCHAR const progid_keyname[7] = {
113     'P', 'r', 'o', 'g', 'I', 'D', 0 };
114 static WCHAR const viprogid_keyname[25] = {
115     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
116     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
117     0 };
118 static char const tmodel_valuename[] = "ThreadingModel";
119 static char const author_valuename[] = "Author";
120 static char const friendlyname_valuename[] = "FriendlyName";
121 static WCHAR const vendor_valuename[] = {'V','e','n','d','o','r',0};
122 static char const version_valuename[] = "Version";
123 static char const mimetypes_valuename[] = "MimeTypes";
124 static char const extensions_valuename[] = "FileExtensions";
125 static WCHAR const formats_keyname[] = {'F','o','r','m','a','t','s',0};
126 static WCHAR const patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
127 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
128 static WCHAR const clsid_valuename[] = {'C','L','S','I','D',0};
129 static char const length_valuename[] = "Length";
130 static char const position_valuename[] = "Position";
131 static char const pattern_valuename[] = "Pattern";
132 static char const mask_valuename[] = "Mask";
133 static char const endofstream_valuename[] = "EndOfStream";
134 static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
135
136 /***********************************************************************
137  *              static helper functions
138  */
139 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
140                                    WCHAR const *value);
141 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
142                                    char const *value);
143 static LONG register_progid(WCHAR const *clsid,
144                             char const *progid, char const *curver_progid,
145                             char const *name, char const *extra);
146
147 /***********************************************************************
148  *              register_coclasses
149  */
150 static HRESULT register_coclasses(struct regsvr_coclass const *list)
151 {
152     LONG res = ERROR_SUCCESS;
153     HKEY coclass_key;
154
155     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
156                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
157     if (res != ERROR_SUCCESS) goto error_return;
158
159     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
160         WCHAR buf[39];
161         HKEY clsid_key;
162
163         StringFromGUID2(list->clsid, buf, 39);
164         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
165                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
166         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
167
168         if (list->name) {
169             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
170                                  (CONST BYTE*)(list->name),
171                                  strlen(list->name) + 1);
172             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
173         }
174
175         if (list->ips) {
176             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
177             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
178         }
179
180         if (list->ips32) {
181             HKEY ips32_key;
182
183             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
184                                   KEY_READ | KEY_WRITE, NULL,
185                                   &ips32_key, NULL);
186             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
187
188             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
189                                  (CONST BYTE*)list->ips32,
190                                  lstrlenA(list->ips32) + 1);
191             if (res == ERROR_SUCCESS && list->ips32_tmodel)
192                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
193                                      (CONST BYTE*)list->ips32_tmodel,
194                                      strlen(list->ips32_tmodel) + 1);
195             RegCloseKey(ips32_key);
196             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
197         }
198
199         if (list->progid) {
200             res = register_key_defvalueA(clsid_key, progid_keyname,
201                                          list->progid);
202             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
203
204             res = register_progid(buf, list->progid, NULL,
205                                   list->name, list->progid_extra);
206             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
207         }
208
209         if (list->viprogid) {
210             res = register_key_defvalueA(clsid_key, viprogid_keyname,
211                                          list->viprogid);
212             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
213
214             res = register_progid(buf, list->viprogid, list->progid,
215                                   list->name, list->progid_extra);
216             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
217         }
218
219     error_close_clsid_key:
220         RegCloseKey(clsid_key);
221     }
222
223 error_close_coclass_key:
224     RegCloseKey(coclass_key);
225 error_return:
226     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
227 }
228
229 /***********************************************************************
230  *              unregister_coclasses
231  */
232 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
233 {
234     LONG res = ERROR_SUCCESS;
235     HKEY coclass_key;
236
237     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
238                         KEY_READ | KEY_WRITE, &coclass_key);
239     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
240     if (res != ERROR_SUCCESS) goto error_return;
241
242     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
243         WCHAR buf[39];
244
245         StringFromGUID2(list->clsid, buf, 39);
246         res = RegDeleteTreeW(coclass_key, buf);
247         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
248         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
249
250         if (list->progid) {
251             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
252             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
253             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
254         }
255
256         if (list->viprogid) {
257             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
258             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
259             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
260         }
261     }
262
263 error_close_coclass_key:
264     RegCloseKey(coclass_key);
265 error_return:
266     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
267 }
268
269 /***********************************************************************
270  *              register_decoders
271  */
272 static HRESULT register_decoders(struct regsvr_decoder const *list)
273 {
274     LONG res = ERROR_SUCCESS;
275     HKEY coclass_key;
276     WCHAR buf[39];
277     HKEY decoders_key;
278     HKEY instance_key;
279
280     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
281                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
282     if (res == ERROR_SUCCESS)  {
283         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
284         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
285                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
286         if (res == ERROR_SUCCESS)
287         {
288             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
289                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
290             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
291         }
292         if (res != ERROR_SUCCESS)
293             RegCloseKey(coclass_key);
294     }
295     if (res != ERROR_SUCCESS) goto error_return;
296
297     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
298         HKEY clsid_key;
299         HKEY instance_clsid_key;
300
301         StringFromGUID2(list->clsid, buf, 39);
302         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
303                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
304         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
305
306         StringFromGUID2(list->clsid, buf, 39);
307         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
308                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
309         if (res == ERROR_SUCCESS) {
310             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
311                                  (CONST BYTE*)(buf), 78);
312             RegCloseKey(instance_clsid_key);
313         }
314         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
315
316         if (list->author) {
317             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
318                                  (CONST BYTE*)(list->author),
319                                  strlen(list->author) + 1);
320             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
321         }
322
323         if (list->friendlyname) {
324             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
325                                  (CONST BYTE*)(list->friendlyname),
326                                  strlen(list->friendlyname) + 1);
327             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
328         }
329
330         if (list->vendor) {
331             StringFromGUID2(list->vendor, buf, 39);
332             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
333                                  (CONST BYTE*)(buf), 78);
334             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
335         }
336
337         if (list->version) {
338             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
339                                  (CONST BYTE*)(list->version),
340                                  strlen(list->version) + 1);
341             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
342         }
343
344         if (list->mimetypes) {
345             res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
346                                  (CONST BYTE*)(list->mimetypes),
347                                  strlen(list->mimetypes) + 1);
348             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
349         }
350
351         if (list->extensions) {
352             res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
353                                  (CONST BYTE*)(list->extensions),
354                                  strlen(list->extensions) + 1);
355             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
356         }
357
358         if (list->formats) {
359             HKEY formats_key;
360             GUID const * const *format;
361
362             res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
363                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
364             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
365             for (format=list->formats; *format; ++format)
366             {
367                 HKEY format_key;
368                 StringFromGUID2(*format, buf, 39);
369                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
370                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
371                 if (res != ERROR_SUCCESS) break;
372                 RegCloseKey(format_key);
373             }
374             RegCloseKey(formats_key);
375             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
376         }
377
378         if (list->patterns) {
379             HKEY patterns_key;
380             int i;
381
382             res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
383                                   KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
384             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
385             for (i=0; list->patterns[i].length; i++)
386             {
387                 HKEY pattern_key;
388                 static const WCHAR int_format[] = {'%','i',0};
389                 snprintfW(buf, 39, int_format, i);
390                 res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
391                                       KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
392                 if (res != ERROR_SUCCESS) break;
393                 res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
394                                      (CONST BYTE*)(&list->patterns[i].length), 4);
395                 if (res == ERROR_SUCCESS)
396                     res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
397                                          (CONST BYTE*)(&list->patterns[i].position), 4);
398                 if (res == ERROR_SUCCESS)
399                     res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
400                                          list->patterns[i].pattern,
401                                          list->patterns[i].length);
402                 if (res == ERROR_SUCCESS)
403                     res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
404                                          list->patterns[i].mask,
405                                          list->patterns[i].length);
406                 if (res == ERROR_SUCCESS)
407                     res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
408                                          (CONST BYTE*)&(list->patterns[i].endofstream), 4);
409                 RegCloseKey(pattern_key);
410             }
411             RegCloseKey(patterns_key);
412             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
413         }
414
415     error_close_clsid_key:
416         RegCloseKey(clsid_key);
417     }
418
419 error_close_coclass_key:
420     RegCloseKey(instance_key);
421     RegCloseKey(decoders_key);
422     RegCloseKey(coclass_key);
423 error_return:
424     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
425 }
426
427 /***********************************************************************
428  *              unregister_decoders
429  */
430 static HRESULT unregister_decoders(struct regsvr_decoder const *list)
431 {
432     LONG res = ERROR_SUCCESS;
433     HKEY coclass_key;
434     WCHAR buf[39];
435     HKEY decoders_key;
436     HKEY instance_key;
437
438     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
439                         KEY_READ | KEY_WRITE, &coclass_key);
440     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
441
442     if (res == ERROR_SUCCESS)  {
443         StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
444         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
445                               KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
446         if (res == ERROR_SUCCESS)
447         {
448             res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
449                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
450             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
451         }
452         if (res != ERROR_SUCCESS)
453             RegCloseKey(coclass_key);
454     }
455     if (res != ERROR_SUCCESS) goto error_return;
456
457     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
458         StringFromGUID2(list->clsid, buf, 39);
459
460         res = RegDeleteTreeW(coclass_key, buf);
461         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
462         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
463
464         res = RegDeleteTreeW(instance_key, buf);
465         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
466         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
467     }
468
469 error_close_coclass_key:
470     RegCloseKey(instance_key);
471     RegCloseKey(decoders_key);
472     RegCloseKey(coclass_key);
473 error_return:
474     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
475 }
476
477 /***********************************************************************
478  *              register_converters
479  */
480 static HRESULT register_converters(struct regsvr_converter const *list)
481 {
482     LONG res = ERROR_SUCCESS;
483     HKEY coclass_key;
484     WCHAR buf[39];
485     HKEY converters_key;
486     HKEY instance_key;
487
488     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
489                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
490     if (res == ERROR_SUCCESS)  {
491         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
492         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
493                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
494         if (res == ERROR_SUCCESS)
495         {
496             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
497                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
498             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
499         }
500         if (res != ERROR_SUCCESS)
501             RegCloseKey(coclass_key);
502     }
503     if (res != ERROR_SUCCESS) goto error_return;
504
505     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
506         HKEY clsid_key;
507         HKEY instance_clsid_key;
508
509         StringFromGUID2(list->clsid, buf, 39);
510         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
511                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
512         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
513
514         StringFromGUID2(list->clsid, buf, 39);
515         res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
516                               KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
517         if (res == ERROR_SUCCESS) {
518             res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
519                                  (CONST BYTE*)(buf), 78);
520             RegCloseKey(instance_clsid_key);
521         }
522         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
523
524         if (list->author) {
525             res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
526                                  (CONST BYTE*)(list->author),
527                                  strlen(list->author) + 1);
528             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
529         }
530
531         if (list->friendlyname) {
532             res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
533                                  (CONST BYTE*)(list->friendlyname),
534                                  strlen(list->friendlyname) + 1);
535             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
536         }
537
538         if (list->vendor) {
539             StringFromGUID2(list->vendor, buf, 39);
540             res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
541                                  (CONST BYTE*)(buf), 78);
542             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
543         }
544
545         if (list->version) {
546             res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
547                                  (CONST BYTE*)(list->version),
548                                  strlen(list->version) + 1);
549             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
550         }
551
552         if (list->formats) {
553             HKEY formats_key;
554             GUID const * const *format;
555
556             res = RegCreateKeyExW(clsid_key, pixelformats_keyname, 0, NULL, 0,
557                                   KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
558             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
559             for (format=list->formats; *format; ++format)
560             {
561                 HKEY format_key;
562                 StringFromGUID2(*format, buf, 39);
563                 res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
564                                       KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
565                 if (res != ERROR_SUCCESS) break;
566                 RegCloseKey(format_key);
567             }
568             RegCloseKey(formats_key);
569             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
570         }
571
572     error_close_clsid_key:
573         RegCloseKey(clsid_key);
574     }
575
576 error_close_coclass_key:
577     RegCloseKey(instance_key);
578     RegCloseKey(converters_key);
579     RegCloseKey(coclass_key);
580 error_return:
581     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
582 }
583
584 /***********************************************************************
585  *              unregister_converters
586  */
587 static HRESULT unregister_converters(struct regsvr_converter const *list)
588 {
589     LONG res = ERROR_SUCCESS;
590     HKEY coclass_key;
591     WCHAR buf[39];
592     HKEY converters_key;
593     HKEY instance_key;
594
595     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
596                         KEY_READ | KEY_WRITE, &coclass_key);
597     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
598
599     if (res == ERROR_SUCCESS)  {
600         StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
601         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
602                               KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
603         if (res == ERROR_SUCCESS)
604         {
605             res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
606                               KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
607             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
608         }
609         if (res != ERROR_SUCCESS)
610             RegCloseKey(coclass_key);
611     }
612     if (res != ERROR_SUCCESS) goto error_return;
613
614     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
615         StringFromGUID2(list->clsid, buf, 39);
616
617         res = RegDeleteTreeW(coclass_key, buf);
618         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
619         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
620
621         res = RegDeleteTreeW(instance_key, buf);
622         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
623         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
624     }
625
626 error_close_coclass_key:
627     RegCloseKey(instance_key);
628     RegCloseKey(converters_key);
629     RegCloseKey(coclass_key);
630 error_return:
631     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
632 }
633
634 /***********************************************************************
635  *              register_key_defvalueW
636  */
637 static LONG register_key_defvalueW(
638     HKEY base,
639     WCHAR const *name,
640     WCHAR const *value)
641 {
642     LONG res;
643     HKEY key;
644
645     res = RegCreateKeyExW(base, name, 0, NULL, 0,
646                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
647     if (res != ERROR_SUCCESS) return res;
648     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
649                          (lstrlenW(value) + 1) * sizeof(WCHAR));
650     RegCloseKey(key);
651     return res;
652 }
653
654 /***********************************************************************
655  *              register_key_defvalueA
656  */
657 static LONG register_key_defvalueA(
658     HKEY base,
659     WCHAR const *name,
660     char const *value)
661 {
662     LONG res;
663     HKEY key;
664
665     res = RegCreateKeyExW(base, name, 0, NULL, 0,
666                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
667     if (res != ERROR_SUCCESS) return res;
668     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
669                          lstrlenA(value) + 1);
670     RegCloseKey(key);
671     return res;
672 }
673
674 /***********************************************************************
675  *              register_progid
676  */
677 static LONG register_progid(
678     WCHAR const *clsid,
679     char const *progid,
680     char const *curver_progid,
681     char const *name,
682     char const *extra)
683 {
684     LONG res;
685     HKEY progid_key;
686
687     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
688                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
689                           &progid_key, NULL);
690     if (res != ERROR_SUCCESS) return res;
691
692     if (name) {
693         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
694                              (CONST BYTE*)name, strlen(name) + 1);
695         if (res != ERROR_SUCCESS) goto error_close_progid_key;
696     }
697
698     if (clsid) {
699         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
700         if (res != ERROR_SUCCESS) goto error_close_progid_key;
701     }
702
703     if (curver_progid) {
704         res = register_key_defvalueA(progid_key, curver_keyname,
705                                      curver_progid);
706         if (res != ERROR_SUCCESS) goto error_close_progid_key;
707     }
708
709     if (extra) {
710         HKEY extra_key;
711
712         res = RegCreateKeyExA(progid_key, extra, 0,
713                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
714                               &extra_key, NULL);
715         if (res == ERROR_SUCCESS)
716             RegCloseKey(extra_key);
717     }
718
719 error_close_progid_key:
720     RegCloseKey(progid_key);
721     return res;
722 }
723
724 /***********************************************************************
725  *              coclass list
726  */
727 static struct regsvr_coclass const coclass_list[] = {
728     {   &CLSID_WICImagingFactory,
729         "WIC Imaging Factory",
730         NULL,
731         "windowscodecs.dll",
732         "Both"
733     },
734     {   &CLSID_WICBmpDecoder,
735         "WIC BMP Decoder",
736         NULL,
737         "windowscodecs.dll",
738         "Both"
739     },
740     {   &CLSID_WICPngDecoder,
741         "WIC PNG Decoder",
742         NULL,
743         "windowscodecs.dll",
744         "Both"
745     },
746     {   &CLSID_WICPngEncoder,
747         "WIC PNG Encoder",
748         NULL,
749         "windowscodecs.dll",
750         "Both"
751     },
752     {   &CLSID_WICBmpEncoder,
753         "WIC BMP Encoder",
754         NULL,
755         "windowscodecs.dll",
756         "Apartment"
757     },
758     {   &CLSID_WICGifDecoder,
759         "WIC GIF Decoder",
760         NULL,
761         "windowscodecs.dll",
762         "Both"
763     },
764     {   &CLSID_WICIcoDecoder,
765         "WIC ICO Decoder",
766         NULL,
767         "windowscodecs.dll",
768         "Both"
769     },
770     {   &CLSID_WICJpegDecoder,
771         "WIC JPEG Decoder",
772         NULL,
773         "windowscodecs.dll",
774         "Both"
775     },
776     {   &CLSID_WICTiffDecoder,
777         "WIC TIFF Decoder",
778         NULL,
779         "windowscodecs.dll",
780         "Both"
781     },
782     {
783         &CLSID_WICIcnsEncoder,
784         "WIC ICNS Encoder",
785         NULL,
786         "windowscodecs.dll",
787         "Both"
788     },
789     {   &CLSID_WICDefaultFormatConverter,
790         "WIC Default Format Converter",
791         NULL,
792         "windowscodecs.dll",
793         "Both"
794     },
795     { NULL }                    /* list terminator */
796 };
797
798 /***********************************************************************
799  *              decoder list
800  */
801 static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
802
803 static const BYTE bmp_magic[] = {0x42,0x4d};
804
805 static GUID const * const bmp_formats[] = {
806     &GUID_WICPixelFormat1bppIndexed,
807     &GUID_WICPixelFormat2bppIndexed,
808     &GUID_WICPixelFormat4bppIndexed,
809     &GUID_WICPixelFormat8bppIndexed,
810     &GUID_WICPixelFormat16bppBGR555,
811     &GUID_WICPixelFormat16bppBGR565,
812     &GUID_WICPixelFormat24bppBGR,
813     &GUID_WICPixelFormat32bppBGR,
814     &GUID_WICPixelFormat32bppBGRA,
815     NULL
816 };
817
818 static struct decoder_pattern const bmp_patterns[] = {
819     {2,0,bmp_magic,mask_all,0},
820     {0}
821 };
822
823 static const BYTE gif87a_magic[6] = "GIF87a";
824 static const BYTE gif89a_magic[6] = "GIF89a";
825
826 static GUID const * const gif_formats[] = {
827     &GUID_WICPixelFormat8bppIndexed,
828     NULL
829 };
830
831 static struct decoder_pattern const gif_patterns[] = {
832     {6,0,gif87a_magic,mask_all,0},
833     {6,0,gif89a_magic,mask_all,0},
834     {0}
835 };
836
837 static const BYTE ico_magic[] = {00,00,01,00};
838
839 static GUID const * const ico_formats[] = {
840     &GUID_WICPixelFormat32bppBGRA,
841     NULL
842 };
843
844 static struct decoder_pattern const ico_patterns[] = {
845     {4,0,ico_magic,mask_all,0},
846     {0}
847 };
848
849 static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
850
851 static GUID const * const jpeg_formats[] = {
852     &GUID_WICPixelFormat24bppBGR,
853     &GUID_WICPixelFormat8bppGray,
854     NULL
855 };
856
857 static struct decoder_pattern const jpeg_patterns[] = {
858     {4,0,jpeg_magic,mask_all,0},
859     {0}
860 };
861
862 static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
863
864 static GUID const * const png_formats[] = {
865     &GUID_WICPixelFormatBlackWhite,
866     &GUID_WICPixelFormat2bppGray,
867     &GUID_WICPixelFormat4bppGray,
868     &GUID_WICPixelFormat8bppGray,
869     &GUID_WICPixelFormat16bppGray,
870     &GUID_WICPixelFormat32bppBGRA,
871     &GUID_WICPixelFormat64bppRGBA,
872     &GUID_WICPixelFormat1bppIndexed,
873     &GUID_WICPixelFormat2bppIndexed,
874     &GUID_WICPixelFormat4bppIndexed,
875     &GUID_WICPixelFormat8bppIndexed,
876     &GUID_WICPixelFormat24bppBGR,
877     &GUID_WICPixelFormat48bppRGB,
878     NULL
879 };
880
881 static struct decoder_pattern const png_patterns[] = {
882     {8,0,png_magic,mask_all,0},
883     {0}
884 };
885
886 static const BYTE tiff_magic_le[] = {0x49,0x49,42,0};
887 static const BYTE tiff_magic_be[] = {0x4d,0x4d,0,42};
888
889 static GUID const * const tiff_formats[] = {
890     &GUID_WICPixelFormatBlackWhite,
891     &GUID_WICPixelFormat4bppGray,
892     &GUID_WICPixelFormat8bppGray,
893     &GUID_WICPixelFormat4bppIndexed,
894     &GUID_WICPixelFormat8bppIndexed,
895     &GUID_WICPixelFormat32bppBGR,
896     &GUID_WICPixelFormat32bppBGRA,
897     &GUID_WICPixelFormat32bppPBGRA,
898     NULL
899 };
900
901 static struct decoder_pattern const tiff_patterns[] = {
902     {4,0,tiff_magic_le,mask_all,0},
903     {4,0,tiff_magic_be,mask_all,0},
904     {0}
905 };
906
907 static struct regsvr_decoder const decoder_list[] = {
908     {   &CLSID_WICBmpDecoder,
909         "The Wine Project",
910         "BMP Decoder",
911         "1.0.0.0",
912         &GUID_VendorMicrosoft,
913         "image/bmp",
914         ".bmp,.dib,.rle",
915         bmp_formats,
916         bmp_patterns
917     },
918     {   &CLSID_WICGifDecoder,
919         "The Wine Project",
920         "GIF Decoder",
921         "1.0.0.0",
922         &GUID_VendorMicrosoft,
923         "image/gif",
924         ".gif",
925         gif_formats,
926         gif_patterns
927     },
928     {   &CLSID_WICIcoDecoder,
929         "The Wine Project",
930         "ICO Decoder",
931         "1.0.0.0",
932         &GUID_VendorMicrosoft,
933         "image/vnd.microsoft.icon",
934         ".ico",
935         ico_formats,
936         ico_patterns
937     },
938     {   &CLSID_WICJpegDecoder,
939         "The Wine Project",
940         "JPEG Decoder",
941         "1.0.0.0",
942         &GUID_VendorMicrosoft,
943         "image/jpeg",
944         ".jpg;.jpeg;.jfif",
945         jpeg_formats,
946         jpeg_patterns
947     },
948     {   &CLSID_WICPngDecoder,
949         "The Wine Project",
950         "PNG Decoder",
951         "1.0.0.0",
952         &GUID_VendorMicrosoft,
953         "image/png",
954         ".png",
955         png_formats,
956         png_patterns
957     },
958     {   &CLSID_WICTiffDecoder,
959         "The Wine Project",
960         "TIFF Decoder",
961         "1.0.0.0",
962         &GUID_VendorMicrosoft,
963         "image/tiff",
964         ".tif;.tiff",
965         tiff_formats,
966         tiff_patterns
967     },
968     { NULL }                    /* list terminator */
969 };
970
971 static GUID const * const converter_formats[] = {
972     &GUID_WICPixelFormat1bppIndexed,
973     &GUID_WICPixelFormat2bppIndexed,
974     &GUID_WICPixelFormat4bppIndexed,
975     &GUID_WICPixelFormat8bppIndexed,
976     &GUID_WICPixelFormatBlackWhite,
977     &GUID_WICPixelFormat2bppGray,
978     &GUID_WICPixelFormat4bppGray,
979     &GUID_WICPixelFormat8bppGray,
980     &GUID_WICPixelFormat16bppGray,
981     &GUID_WICPixelFormat16bppBGR555,
982     &GUID_WICPixelFormat16bppBGR565,
983     &GUID_WICPixelFormat24bppBGR,
984     &GUID_WICPixelFormat32bppBGR,
985     &GUID_WICPixelFormat32bppBGRA,
986     &GUID_WICPixelFormat48bppRGB,
987     &GUID_WICPixelFormat64bppRGBA,
988     NULL
989 };
990
991 static struct regsvr_converter const converter_list[] = {
992     {   &CLSID_WICDefaultFormatConverter,
993         "The Wine Project",
994         "Default Pixel Format Converter",
995         "1.0.0.0",
996         &GUID_VendorMicrosoft,
997         converter_formats
998     },
999     { NULL }                    /* list terminator */
1000 };
1001
1002 HRESULT WINAPI DllRegisterServer(void)
1003 {
1004     HRESULT hr;
1005
1006     TRACE("\n");
1007
1008     hr = register_coclasses(coclass_list);
1009     if (SUCCEEDED(hr))
1010         register_decoders(decoder_list);
1011     if (SUCCEEDED(hr))
1012         register_converters(converter_list);
1013     return hr;
1014 }
1015
1016 HRESULT WINAPI DllUnregisterServer(void)
1017 {
1018     HRESULT hr;
1019
1020     TRACE("\n");
1021
1022     hr = unregister_coclasses(coclass_list);
1023     if (SUCCEEDED(hr))
1024         unregister_decoders(decoder_list);
1025     if (SUCCEEDED(hr))
1026         unregister_converters(converter_list);
1027     return hr;
1028 }