2 * Copyright 2009 Vincent Povirk for CodeWeavers
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.
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.
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
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
41 /***********************************************************************
42 * interface for self-registering
46 CLSID
const *clsid
; /* NULL for end of list */
47 LPCSTR name
; /* can be NULL to omit */
48 LPCSTR ips
; /* can be NULL to omit */
49 LPCSTR ips32
; /* can be NULL to omit */
50 LPCSTR ips32_tmodel
; /* can be NULL to omit */
51 LPCSTR progid
; /* can be NULL to omit */
52 LPCSTR viprogid
; /* can be NULL to omit */
53 LPCSTR progid_extra
; /* can be NULL to omit */
56 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
);
57 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
);
59 struct decoder_pattern
61 DWORD length
; /* 0 for end of list */
70 CLSID
const *clsid
; /* NULL for end of list */
77 GUID
const * const *formats
;
78 const struct decoder_pattern
*patterns
;
81 static HRESULT
register_decoders(struct regsvr_decoder
const *list
);
82 static HRESULT
unregister_decoders(struct regsvr_decoder
const *list
);
84 /***********************************************************************
85 * static string constants
87 static WCHAR
const clsid_keyname
[6] = {
88 'C', 'L', 'S', 'I', 'D', 0 };
89 static WCHAR
const curver_keyname
[7] = {
90 'C', 'u', 'r', 'V', 'e', 'r', 0 };
91 static WCHAR
const ips_keyname
[13] = {
92 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
94 static WCHAR
const ips32_keyname
[15] = {
95 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
97 static WCHAR
const progid_keyname
[7] = {
98 'P', 'r', 'o', 'g', 'I', 'D', 0 };
99 static WCHAR
const viprogid_keyname
[25] = {
100 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
101 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
103 static char const tmodel_valuename
[] = "ThreadingModel";
104 static char const author_valuename
[] = "Author";
105 static char const friendlyname_valuename
[] = "FriendlyName";
106 static WCHAR
const vendor_valuename
[] = {'V','e','n','d','o','r',0};
107 static char const version_valuename
[] = "Version";
108 static char const mimetypes_valuename
[] = "MimeTypes";
109 static char const extensions_valuename
[] = "FileExtensions";
110 static WCHAR
const formats_keyname
[] = {'F','o','r','m','a','t','s',0};
111 static WCHAR
const patterns_keyname
[] = {'P','a','t','t','e','r','n','s',0};
112 static WCHAR
const instance_keyname
[] = {'I','n','s','t','a','n','c','e',0};
113 static WCHAR
const clsid_valuename
[] = {'C','L','S','I','D',0};
114 static char const length_valuename
[] = "Length";
115 static char const position_valuename
[] = "Position";
116 static char const pattern_valuename
[] = "Pattern";
117 static char const mask_valuename
[] = "Mask";
118 static char const endofstream_valuename
[] = "EndOfStream";
120 /***********************************************************************
121 * static helper functions
123 static LONG
register_key_defvalueW(HKEY base
, WCHAR
const *name
,
125 static LONG
register_key_defvalueA(HKEY base
, WCHAR
const *name
,
127 static LONG
register_progid(WCHAR
const *clsid
,
128 char const *progid
, char const *curver_progid
,
129 char const *name
, char const *extra
);
131 /***********************************************************************
134 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
)
136 LONG res
= ERROR_SUCCESS
;
139 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
140 KEY_READ
| KEY_WRITE
, NULL
, &coclass_key
, NULL
);
141 if (res
!= ERROR_SUCCESS
) goto error_return
;
143 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
147 StringFromGUID2(list
->clsid
, buf
, 39);
148 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
149 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
150 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
153 res
= RegSetValueExA(clsid_key
, NULL
, 0, REG_SZ
,
154 (CONST BYTE
*)(list
->name
),
155 strlen(list
->name
) + 1);
156 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
160 res
= register_key_defvalueA(clsid_key
, ips_keyname
, list
->ips
);
161 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
167 res
= RegCreateKeyExW(clsid_key
, ips32_keyname
, 0, NULL
, 0,
168 KEY_READ
| KEY_WRITE
, NULL
,
170 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
172 res
= RegSetValueExA(ips32_key
, NULL
, 0, REG_SZ
,
173 (CONST BYTE
*)list
->ips32
,
174 lstrlenA(list
->ips32
) + 1);
175 if (res
== ERROR_SUCCESS
&& list
->ips32_tmodel
)
176 res
= RegSetValueExA(ips32_key
, tmodel_valuename
, 0, REG_SZ
,
177 (CONST BYTE
*)list
->ips32_tmodel
,
178 strlen(list
->ips32_tmodel
) + 1);
179 RegCloseKey(ips32_key
);
180 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
184 res
= register_key_defvalueA(clsid_key
, progid_keyname
,
186 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
188 res
= register_progid(buf
, list
->progid
, NULL
,
189 list
->name
, list
->progid_extra
);
190 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
193 if (list
->viprogid
) {
194 res
= register_key_defvalueA(clsid_key
, viprogid_keyname
,
196 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
198 res
= register_progid(buf
, list
->viprogid
, list
->progid
,
199 list
->name
, list
->progid_extra
);
200 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
203 error_close_clsid_key
:
204 RegCloseKey(clsid_key
);
207 error_close_coclass_key
:
208 RegCloseKey(coclass_key
);
210 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
213 /***********************************************************************
214 * unregister_coclasses
216 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
)
218 LONG res
= ERROR_SUCCESS
;
221 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0,
222 KEY_READ
| KEY_WRITE
, &coclass_key
);
223 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
224 if (res
!= ERROR_SUCCESS
) goto error_return
;
226 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
229 StringFromGUID2(list
->clsid
, buf
, 39);
230 res
= RegDeleteTreeW(coclass_key
, buf
);
231 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
232 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
235 res
= RegDeleteTreeA(HKEY_CLASSES_ROOT
, list
->progid
);
236 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
237 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
240 if (list
->viprogid
) {
241 res
= RegDeleteTreeA(HKEY_CLASSES_ROOT
, list
->viprogid
);
242 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
243 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
247 error_close_coclass_key
:
248 RegCloseKey(coclass_key
);
250 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
253 /***********************************************************************
256 static HRESULT
register_decoders(struct regsvr_decoder
const *list
)
258 LONG res
= ERROR_SUCCESS
;
264 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
265 KEY_READ
| KEY_WRITE
, NULL
, &coclass_key
, NULL
);
266 if (res
== ERROR_SUCCESS
) {
267 StringFromGUID2(&CATID_WICBitmapDecoders
, buf
, 39);
268 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
269 KEY_READ
| KEY_WRITE
, NULL
, &decoders_key
, NULL
);
270 if (res
== ERROR_SUCCESS
)
272 res
= RegCreateKeyExW(decoders_key
, instance_keyname
, 0, NULL
, 0,
273 KEY_READ
| KEY_WRITE
, NULL
, &instance_key
, NULL
);
274 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
276 if (res
!= ERROR_SUCCESS
)
277 RegCloseKey(coclass_key
);
279 if (res
!= ERROR_SUCCESS
) goto error_return
;
281 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
283 HKEY instance_clsid_key
;
285 StringFromGUID2(list
->clsid
, buf
, 39);
286 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
287 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
288 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
290 StringFromGUID2(list
->clsid
, buf
, 39);
291 res
= RegCreateKeyExW(instance_key
, buf
, 0, NULL
, 0,
292 KEY_READ
| KEY_WRITE
, NULL
, &instance_clsid_key
, NULL
);
293 if (res
== ERROR_SUCCESS
) {
294 res
= RegSetValueExW(instance_clsid_key
, clsid_valuename
, 0, REG_SZ
,
295 (CONST BYTE
*)(buf
), 78);
296 RegCloseKey(instance_clsid_key
);
298 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
301 res
= RegSetValueExA(clsid_key
, author_valuename
, 0, REG_SZ
,
302 (CONST BYTE
*)(list
->author
),
303 strlen(list
->author
) + 1);
304 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
307 if (list
->friendlyname
) {
308 res
= RegSetValueExA(clsid_key
, friendlyname_valuename
, 0, REG_SZ
,
309 (CONST BYTE
*)(list
->friendlyname
),
310 strlen(list
->friendlyname
) + 1);
311 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
315 StringFromGUID2(list
->vendor
, buf
, 39);
316 res
= RegSetValueExW(clsid_key
, vendor_valuename
, 0, REG_SZ
,
317 (CONST BYTE
*)(buf
), 78);
318 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
322 res
= RegSetValueExA(clsid_key
, version_valuename
, 0, REG_SZ
,
323 (CONST BYTE
*)(list
->version
),
324 strlen(list
->version
) + 1);
325 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
328 if (list
->mimetypes
) {
329 res
= RegSetValueExA(clsid_key
, mimetypes_valuename
, 0, REG_SZ
,
330 (CONST BYTE
*)(list
->mimetypes
),
331 strlen(list
->mimetypes
) + 1);
332 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
335 if (list
->extensions
) {
336 res
= RegSetValueExA(clsid_key
, extensions_valuename
, 0, REG_SZ
,
337 (CONST BYTE
*)(list
->extensions
),
338 strlen(list
->extensions
) + 1);
339 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
344 GUID
const * const *format
;
346 res
= RegCreateKeyExW(clsid_key
, formats_keyname
, 0, NULL
, 0,
347 KEY_READ
| KEY_WRITE
, NULL
, &formats_key
, NULL
);
348 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
349 for (format
=list
->formats
; *format
; ++format
)
352 StringFromGUID2(*format
, buf
, 39);
353 res
= RegCreateKeyExW(formats_key
, buf
, 0, NULL
, 0,
354 KEY_READ
| KEY_WRITE
, NULL
, &format_key
, NULL
);
355 if (res
!= ERROR_SUCCESS
) break;
356 RegCloseKey(format_key
);
358 RegCloseKey(formats_key
);
359 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
362 if (list
->patterns
) {
366 res
= RegCreateKeyExW(clsid_key
, patterns_keyname
, 0, NULL
, 0,
367 KEY_READ
| KEY_WRITE
, NULL
, &patterns_key
, NULL
);
368 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
369 for (i
=0; list
->patterns
[i
].length
; i
++)
372 static const WCHAR int_format
[] = {'%','i',0};
373 snprintfW(buf
, 39, int_format
, i
);
374 res
= RegCreateKeyExW(patterns_key
, buf
, 0, NULL
, 0,
375 KEY_READ
| KEY_WRITE
, NULL
, &pattern_key
, NULL
);
376 if (res
!= ERROR_SUCCESS
) break;
377 res
= RegSetValueExA(pattern_key
, length_valuename
, 0, REG_DWORD
,
378 (CONST BYTE
*)(&list
->patterns
[i
].length
), 4);
379 if (res
== ERROR_SUCCESS
)
380 res
= RegSetValueExA(pattern_key
, position_valuename
, 0, REG_DWORD
,
381 (CONST BYTE
*)(&list
->patterns
[i
].position
), 4);
382 if (res
== ERROR_SUCCESS
)
383 res
= RegSetValueExA(pattern_key
, pattern_valuename
, 0, REG_BINARY
,
384 list
->patterns
[i
].pattern
,
385 list
->patterns
[i
].length
);
386 if (res
== ERROR_SUCCESS
)
387 res
= RegSetValueExA(pattern_key
, mask_valuename
, 0, REG_BINARY
,
388 list
->patterns
[i
].mask
,
389 list
->patterns
[i
].length
);
390 if (res
== ERROR_SUCCESS
)
391 res
= RegSetValueExA(pattern_key
, endofstream_valuename
, 0, REG_DWORD
,
392 (CONST BYTE
*)&(list
->patterns
[i
].endofstream
), 4);
393 RegCloseKey(pattern_key
);
395 RegCloseKey(patterns_key
);
396 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
399 error_close_clsid_key
:
400 RegCloseKey(clsid_key
);
403 error_close_coclass_key
:
404 RegCloseKey(instance_key
);
405 RegCloseKey(decoders_key
);
406 RegCloseKey(coclass_key
);
408 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
411 /***********************************************************************
412 * unregister_decoders
414 static HRESULT
unregister_decoders(struct regsvr_decoder
const *list
)
416 LONG res
= ERROR_SUCCESS
;
422 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0,
423 KEY_READ
| KEY_WRITE
, &coclass_key
);
424 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
426 if (res
== ERROR_SUCCESS
) {
427 StringFromGUID2(&CATID_WICBitmapDecoders
, buf
, 39);
428 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
429 KEY_READ
| KEY_WRITE
, NULL
, &decoders_key
, NULL
);
430 if (res
== ERROR_SUCCESS
)
432 res
= RegCreateKeyExW(decoders_key
, instance_keyname
, 0, NULL
, 0,
433 KEY_READ
| KEY_WRITE
, NULL
, &instance_key
, NULL
);
434 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
436 if (res
!= ERROR_SUCCESS
)
437 RegCloseKey(coclass_key
);
439 if (res
!= ERROR_SUCCESS
) goto error_return
;
441 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
442 StringFromGUID2(list
->clsid
, buf
, 39);
444 res
= RegDeleteTreeW(coclass_key
, buf
);
445 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
446 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
448 res
= RegDeleteTreeW(instance_key
, buf
);
449 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
450 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
453 error_close_coclass_key
:
454 RegCloseKey(instance_key
);
455 RegCloseKey(decoders_key
);
456 RegCloseKey(coclass_key
);
458 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
461 /***********************************************************************
462 * register_key_defvalueW
464 static LONG
register_key_defvalueW(
472 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
473 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
474 if (res
!= ERROR_SUCCESS
) return res
;
475 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
476 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
481 /***********************************************************************
482 * register_key_defvalueA
484 static LONG
register_key_defvalueA(
492 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
493 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
494 if (res
!= ERROR_SUCCESS
) return res
;
495 res
= RegSetValueExA(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
496 lstrlenA(value
) + 1);
501 /***********************************************************************
504 static LONG
register_progid(
507 char const *curver_progid
,
514 res
= RegCreateKeyExA(HKEY_CLASSES_ROOT
, progid
, 0,
515 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
517 if (res
!= ERROR_SUCCESS
) return res
;
520 res
= RegSetValueExA(progid_key
, NULL
, 0, REG_SZ
,
521 (CONST BYTE
*)name
, strlen(name
) + 1);
522 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
526 res
= register_key_defvalueW(progid_key
, clsid_keyname
, clsid
);
527 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
531 res
= register_key_defvalueA(progid_key
, curver_keyname
,
533 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
539 res
= RegCreateKeyExA(progid_key
, extra
, 0,
540 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
542 if (res
== ERROR_SUCCESS
)
543 RegCloseKey(extra_key
);
546 error_close_progid_key
:
547 RegCloseKey(progid_key
);
551 /***********************************************************************
554 static struct regsvr_coclass
const coclass_list
[] = {
555 { &CLSID_WICImagingFactory
,
556 "WIC Imaging Factory",
561 { &CLSID_WICBmpDecoder
,
567 { NULL
} /* list terminator */
570 /***********************************************************************
573 static const BYTE bmp_magic
[] = {0x42,0x4d};
574 static const BYTE mask_all
[] = {0xff,0xff};
576 static GUID
const * const bmp_formats
[] = {
577 &GUID_WICPixelFormat1bppIndexed
,
578 &GUID_WICPixelFormat2bppIndexed
,
579 &GUID_WICPixelFormat4bppIndexed
,
580 &GUID_WICPixelFormat8bppIndexed
,
581 &GUID_WICPixelFormat16bppBGR555
,
582 &GUID_WICPixelFormat24bppBGR
,
583 &GUID_WICPixelFormat32bppBGR
,
587 static struct decoder_pattern
const bmp_patterns
[] = {
588 {2,0,bmp_magic
,mask_all
,0},
592 static struct regsvr_decoder
const decoder_list
[] = {
593 { &CLSID_WICBmpDecoder
,
597 &GUID_VendorMicrosoft
,
603 { NULL
} /* list terminator */
606 HRESULT WINAPI
DllRegisterServer(void)
612 hr
= register_coclasses(coclass_list
);
614 register_decoders(decoder_list
);
618 HRESULT WINAPI
DllUnregisterServer(void)
624 hr
= unregister_coclasses(coclass_list
);
626 unregister_decoders(decoder_list
);