xref: /reactos/dll/win32/windowscodecs/info.c (revision 9c5efed7)
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  * Copyright 2012 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <stdarg.h>
21 
22 #define COBJMACROS
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "objbase.h"
28 
29 #include "wincodecs_private.h"
30 
31 #include "wine/debug.h"
32 #include "wine/list.h"
33 #include "wine/rbtree.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 
37 typedef struct {
38     IWICComponentInfo IWICComponentInfo_iface;
39     LONG ref;
40     CLSID clsid;
41     struct wine_rb_entry entry;
42 } ComponentInfo;
43 
44 static HRESULT ComponentInfo_GetStringValue(HKEY classkey, LPCWSTR value,
45     UINT buffer_size, WCHAR *buffer, UINT *actual_size)
46 {
47     LONG ret;
48     DWORD cbdata=buffer_size * sizeof(WCHAR);
49 
50     if (!actual_size)
51         return E_INVALIDARG;
52 
53     ret = RegQueryValueExW(classkey, value, 0, NULL, (void *)buffer, &cbdata);
54 
55     if (ret == ERROR_FILE_NOT_FOUND)
56     {
57         *actual_size = 0;
58         return S_OK;
59     }
60 
61     if (ret == 0 || ret == ERROR_MORE_DATA)
62         *actual_size = cbdata/sizeof(WCHAR);
63 
64     if (!buffer && buffer_size != 0)
65         /* Yes, native returns the correct size in this case. */
66         return E_INVALIDARG;
67 
68     if (ret == ERROR_MORE_DATA)
69         return WINCODEC_ERR_INSUFFICIENTBUFFER;
70 
71     return HRESULT_FROM_WIN32(ret);
72 }
73 
74 static HRESULT ComponentInfo_GetGUIDValue(HKEY classkey, LPCWSTR value,
75     GUID *result)
76 {
77     LONG ret;
78     WCHAR guid_string[39];
79     DWORD cbdata = sizeof(guid_string);
80     HRESULT hr;
81 
82     if (!result)
83         return E_INVALIDARG;
84 
85     ret = RegGetValueW(classkey, NULL, value, RRF_RT_REG_SZ|RRF_NOEXPAND, NULL,
86         guid_string, &cbdata);
87 
88     if (ret != ERROR_SUCCESS)
89         return HRESULT_FROM_WIN32(ret);
90 
91     if (cbdata < sizeof(guid_string))
92     {
93         ERR("incomplete GUID value\n");
94         return E_FAIL;
95     }
96 
97     hr = CLSIDFromString(guid_string, result);
98 
99     return hr;
100 }
101 
102 static HRESULT ComponentInfo_GetUINTValue(HKEY classkey, LPCWSTR value,
103     void *result)
104 {
105     LONG ret;
106     DWORD cbdata = sizeof(DWORD);
107 
108     if (!result)
109         return E_INVALIDARG;
110 
111     ret = RegGetValueW(classkey, NULL, value, RRF_RT_DWORD, NULL,
112         result, &cbdata);
113 
114     if (ret == ERROR_FILE_NOT_FOUND)
115     {
116         *(UINT *)result = 0;
117         return S_OK;
118     }
119 
120     return HRESULT_FROM_WIN32(ret);
121 }
122 
123 static HRESULT ComponentInfo_GetGuidList(HKEY classkey, LPCWSTR subkeyname,
124     UINT buffersize, GUID *buffer, UINT *actual_size)
125 {
126     LONG ret;
127     HKEY subkey;
128     UINT items_returned;
129     WCHAR guid_string[39];
130     DWORD guid_string_size;
131     HRESULT hr=S_OK;
132 
133     if (!actual_size)
134         return E_INVALIDARG;
135 
136     ret = RegOpenKeyExW(classkey, subkeyname, 0, KEY_READ, &subkey);
137     if (ret == ERROR_FILE_NOT_FOUND)
138     {
139         *actual_size = 0;
140         return S_OK;
141     }
142     else if (ret != ERROR_SUCCESS) return HRESULT_FROM_WIN32(ret);
143 
144     if (buffer)
145     {
146         items_returned = 0;
147         guid_string_size = 39;
148         while (items_returned < buffersize)
149         {
150             ret = RegEnumKeyExW(subkey, items_returned, guid_string,
151                 &guid_string_size, NULL, NULL, NULL, NULL);
152 
153             if (ret != ERROR_SUCCESS)
154             {
155                 hr = HRESULT_FROM_WIN32(ret);
156                 break;
157             }
158 
159             if (guid_string_size != 38)
160             {
161                 hr = E_FAIL;
162                 break;
163             }
164 
165             hr = CLSIDFromString(guid_string, &buffer[items_returned]);
166             if (FAILED(hr))
167                 break;
168 
169             items_returned++;
170             guid_string_size = 39;
171         }
172 
173         if (ret == ERROR_NO_MORE_ITEMS)
174             hr = S_OK;
175 
176         *actual_size = items_returned;
177     }
178     else
179     {
180         ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, (DWORD *)actual_size, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
181         if (ret != ERROR_SUCCESS)
182             hr = HRESULT_FROM_WIN32(ret);
183     }
184 
185     RegCloseKey(subkey);
186 
187     return hr;
188 }
189 
190 typedef struct {
191     ComponentInfo base;
192     HKEY classkey;
193     WICBitmapPattern *patterns;
194     UINT pattern_count;
195     UINT patterns_size;
196 } BitmapDecoderInfo;
197 
198 static inline BitmapDecoderInfo *impl_from_IWICBitmapDecoderInfo(IWICBitmapDecoderInfo *iface)
199 {
200     return CONTAINING_RECORD((IWICComponentInfo*)iface, BitmapDecoderInfo, base.IWICComponentInfo_iface);
201 }
202 
203 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
204     void **ppv)
205 {
206     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
207     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
208 
209     if (!ppv) return E_INVALIDARG;
210 
211     if (IsEqualIID(&IID_IUnknown, iid) ||
212         IsEqualIID(&IID_IWICComponentInfo, iid) ||
213         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
214         IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
215     {
216         *ppv = &This->base.IWICComponentInfo_iface;
217     }
218     else
219     {
220         *ppv = NULL;
221         return E_NOINTERFACE;
222     }
223 
224     IUnknown_AddRef((IUnknown*)*ppv);
225     return S_OK;
226 }
227 
228 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
229 {
230     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
231     ULONG ref = InterlockedIncrement(&This->base.ref);
232 
233     TRACE("(%p) refcount=%lu\n", iface, ref);
234 
235     return ref;
236 }
237 
238 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
239 {
240     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
241     ULONG ref = InterlockedDecrement(&This->base.ref);
242 
243     TRACE("(%p) refcount=%lu\n", iface, ref);
244 
245     if (ref == 0)
246     {
247         RegCloseKey(This->classkey);
248         free(This->patterns);
249         free(This);
250     }
251 
252     return ref;
253 }
254 
255 static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
256     WICComponentType *pType)
257 {
258     TRACE("(%p,%p)\n", iface, pType);
259     if (!pType) return E_INVALIDARG;
260     *pType = WICDecoder;
261     return S_OK;
262 }
263 
264 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
265 {
266     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
267     TRACE("(%p,%p)\n", iface, pclsid);
268 
269     if (!pclsid)
270         return E_INVALIDARG;
271 
272     *pclsid = This->base.clsid;
273     return S_OK;
274 }
275 
276 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
277 {
278     FIXME("(%p,%p): stub\n", iface, pStatus);
279     return E_NOTIMPL;
280 }
281 
282 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
283     WCHAR *wzAuthor, UINT *pcchActual)
284 {
285     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
286 
287     TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
288 
289     return ComponentInfo_GetStringValue(This->classkey, L"Author", cchAuthor, wzAuthor, pcchActual);
290 }
291 
292 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
293 {
294     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
295 
296     TRACE("(%p,%p)\n", iface, pguidVendor);
297 
298     return ComponentInfo_GetGUIDValue(This->classkey, L"Vendor", pguidVendor);
299 }
300 
301 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
302     WCHAR *wzVersion, UINT *pcchActual)
303 {
304     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
305 
306     TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
307 
308     return ComponentInfo_GetStringValue(This->classkey, L"Version",
309         cchVersion, wzVersion, pcchActual);
310 }
311 
312 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
313     WCHAR *wzSpecVersion, UINT *pcchActual)
314 {
315     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
316 
317     TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
318 
319     return ComponentInfo_GetStringValue(This->classkey, L"SpecVersion",
320         cchSpecVersion, wzSpecVersion, pcchActual);
321 }
322 
323 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
324     WCHAR *wzFriendlyName, UINT *pcchActual)
325 {
326     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
327 
328     TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
329 
330     return ComponentInfo_GetStringValue(This->classkey, L"FriendlyName",
331         cchFriendlyName, wzFriendlyName, pcchActual);
332 }
333 
334 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
335     GUID *pguidContainerFormat)
336 {
337     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
338     TRACE("(%p,%p)\n", iface, pguidContainerFormat);
339     return ComponentInfo_GetGUIDValue(This->classkey, L"ContainerFormat", pguidContainerFormat);
340 }
341 
342 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
343     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
344 {
345     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
346     TRACE("(%p,%u,%p,%p)\n", iface, cFormats, pguidPixelFormats, pcActual);
347     return ComponentInfo_GetGuidList(This->classkey, L"Formats", cFormats, pguidPixelFormats, pcActual);
348 }
349 
350 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
351     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
352 {
353     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
354     return E_NOTIMPL;
355 }
356 
357 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
358     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
359 {
360     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
361     return E_NOTIMPL;
362 }
363 
364 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
365     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
366 {
367     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
368     return E_NOTIMPL;
369 }
370 
371 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
372     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
373 {
374     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
375 
376     TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
377 
378     return ComponentInfo_GetStringValue(This->classkey, L"MimeTypes",
379         cchMimeTypes, wzMimeTypes, pcchActual);
380 }
381 
382 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
383     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
384 {
385     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
386 
387     TRACE("(%p,%u,%p,%p)\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
388 
389     return ComponentInfo_GetStringValue(This->classkey, L"FileExtensions",
390         cchFileExtensions, wzFileExtensions, pcchActual);
391 }
392 
393 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
394     BOOL *pfSupportAnimation)
395 {
396     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
397     return E_NOTIMPL;
398 }
399 
400 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
401     BOOL *pfSupportChromaKey)
402 {
403     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
404     return E_NOTIMPL;
405 }
406 
407 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
408     BOOL *pfSupportLossless)
409 {
410     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
411     return E_NOTIMPL;
412 }
413 
414 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
415     BOOL *pfSupportMultiframe)
416 {
417     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
418     return E_NOTIMPL;
419 }
420 
421 static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
422     LPCWSTR wzMimeType, BOOL *pfMatches)
423 {
424     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
425     return E_NOTIMPL;
426 }
427 
428 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
429     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
430 {
431     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
432 
433     TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
434 
435     if (!pcPatterns || !pcbPatternsActual) return E_INVALIDARG;
436 
437     *pcPatterns = This->pattern_count;
438     *pcbPatternsActual = This->patterns_size;
439     if (pPatterns)
440     {
441         if (This->patterns_size && cbSizePatterns < This->patterns_size)
442             return WINCODEC_ERR_INSUFFICIENTBUFFER;
443         memcpy(pPatterns, This->patterns, This->patterns_size);
444     }
445     return S_OK;
446 }
447 
448 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
449     IStream *pIStream, BOOL *pfMatches)
450 {
451     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
452     HRESULT hr;
453     UINT i;
454     ULONG pos;
455     BYTE *data=NULL;
456     ULONG datasize=0;
457     ULONG bytesread;
458     LARGE_INTEGER seekpos;
459 
460     TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
461 
462     for (i=0; i < This->pattern_count; i++)
463     {
464         if (datasize < This->patterns[i].Length)
465         {
466             free(data);
467             datasize = This->patterns[i].Length;
468             data = malloc(This->patterns[i].Length);
469             if (!data)
470             {
471                 hr = E_OUTOFMEMORY;
472                 break;
473             }
474         }
475 
476         if (This->patterns[i].EndOfStream)
477             seekpos.QuadPart = -This->patterns[i].Position.QuadPart;
478         else
479             seekpos.QuadPart = This->patterns[i].Position.QuadPart;
480         hr = IStream_Seek(pIStream, seekpos, This->patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
481         if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
482         if (FAILED(hr)) break;
483 
484         hr = IStream_Read(pIStream, data, This->patterns[i].Length, &bytesread);
485         if (hr == S_FALSE || (hr == S_OK && bytesread != This->patterns[i].Length)) /* past end of stream */
486             continue;
487         if (FAILED(hr)) break;
488 
489         for (pos=0; pos < This->patterns[i].Length; pos++)
490         {
491             if ((data[pos] & This->patterns[i].Mask[pos]) != This->patterns[i].Pattern[pos])
492                 break;
493         }
494         if (pos == This->patterns[i].Length) /* matches pattern */
495         {
496             hr = S_OK;
497             *pfMatches = TRUE;
498             break;
499         }
500     }
501 
502     if (i == This->pattern_count) /* does not match any pattern */
503     {
504         hr = S_OK;
505         *pfMatches = FALSE;
506     }
507 
508     free(data);
509     return hr;
510 }
511 
512 static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
513     IWICBitmapDecoder **ppIBitmapDecoder)
514 {
515     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
516 
517     TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
518 
519     return create_instance(&This->base.clsid, &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
520 }
521 
522 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
523     BitmapDecoderInfo_QueryInterface,
524     BitmapDecoderInfo_AddRef,
525     BitmapDecoderInfo_Release,
526     BitmapDecoderInfo_GetComponentType,
527     BitmapDecoderInfo_GetCLSID,
528     BitmapDecoderInfo_GetSigningStatus,
529     BitmapDecoderInfo_GetAuthor,
530     BitmapDecoderInfo_GetVendorGUID,
531     BitmapDecoderInfo_GetVersion,
532     BitmapDecoderInfo_GetSpecVersion,
533     BitmapDecoderInfo_GetFriendlyName,
534     BitmapDecoderInfo_GetContainerFormat,
535     BitmapDecoderInfo_GetPixelFormats,
536     BitmapDecoderInfo_GetColorManagementVersion,
537     BitmapDecoderInfo_GetDeviceManufacturer,
538     BitmapDecoderInfo_GetDeviceModels,
539     BitmapDecoderInfo_GetMimeTypes,
540     BitmapDecoderInfo_GetFileExtensions,
541     BitmapDecoderInfo_DoesSupportAnimation,
542     BitmapDecoderInfo_DoesSupportChromaKey,
543     BitmapDecoderInfo_DoesSupportLossless,
544     BitmapDecoderInfo_DoesSupportMultiframe,
545     BitmapDecoderInfo_MatchesMimeType,
546     BitmapDecoderInfo_GetPatterns,
547     BitmapDecoderInfo_MatchesPattern,
548     BitmapDecoderInfo_CreateInstance
549 };
550 
551 static void read_bitmap_patterns(BitmapDecoderInfo *info)
552 {
553     DWORD pattern_count=0;
554     UINT patterns_size=0;
555     WCHAR subkeyname[11];
556     LONG res;
557     HKEY patternskey, patternkey;
558     UINT i;
559     WICBitmapPattern *patterns;
560     BYTE *patterns_ptr;
561     DWORD length, valuesize;
562 
563     res = RegOpenKeyExW(info->classkey, L"Patterns", 0, KEY_READ, &patternskey);
564     if (res != ERROR_SUCCESS) return;
565 
566     res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
567     if (res != ERROR_SUCCESS)
568     {
569         RegCloseKey(patternskey);
570         return;
571     }
572 
573     patterns_size = pattern_count * sizeof(WICBitmapPattern);
574     patterns = malloc(patterns_size);
575     if (!patterns)
576     {
577         RegCloseKey(patternskey);
578         return;
579     }
580 
581     for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
582     {
583         swprintf(subkeyname, 11, L"%u", i);
584         res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
585         if (res != ERROR_SUCCESS) break;
586 
587         valuesize = sizeof(ULONG);
588         res = RegGetValueW(patternkey, NULL, L"Length", RRF_RT_DWORD, NULL, &length, &valuesize);
589         if (res == ERROR_SUCCESS)
590         {
591             patterns_size += length*2;
592             patterns[i].Length = length;
593 
594             valuesize = sizeof(BOOL);
595             res = RegGetValueW(patternkey, NULL, L"EndOfStream", RRF_RT_DWORD, NULL,
596                                &patterns[i].EndOfStream, &valuesize);
597             if (res) patterns[i].EndOfStream = 0;
598 
599             patterns[i].Position.QuadPart = 0;
600             valuesize = sizeof(ULARGE_INTEGER);
601             res = RegGetValueW(patternkey, NULL, L"Position", RRF_RT_DWORD|RRF_RT_QWORD, NULL,
602                                &patterns[i].Position, &valuesize);
603         }
604 
605         RegCloseKey(patternkey);
606     }
607 
608     if (res != ERROR_SUCCESS || !(patterns_ptr = realloc(patterns, patterns_size)))
609     {
610         free(patterns);
611         RegCloseKey(patternskey);
612         return;
613     }
614     patterns = (WICBitmapPattern*)patterns_ptr;
615     patterns_ptr += pattern_count * sizeof(*patterns);
616 
617     for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
618     {
619         swprintf(subkeyname, 11, L"%u", i);
620         res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
621         if (res != ERROR_SUCCESS) break;
622 
623         length = patterns[i].Length;
624         patterns[i].Pattern = patterns_ptr;
625         valuesize = length;
626         res = RegGetValueW(patternkey, NULL, L"Pattern", RRF_RT_REG_BINARY, NULL,
627                            patterns[i].Pattern, &valuesize);
628         patterns_ptr += length;
629 
630         if (res == ERROR_SUCCESS)
631         {
632             patterns[i].Mask = patterns_ptr;
633             valuesize = length;
634             res = RegGetValueW(patternkey, NULL, L"Mask", RRF_RT_REG_BINARY, NULL,
635                                patterns[i].Mask, &valuesize);
636             patterns_ptr += length;
637         }
638 
639         RegCloseKey(patternkey);
640     }
641 
642     RegCloseKey(patternskey);
643 
644     if (res != ERROR_SUCCESS)
645     {
646         free(patterns);
647         return;
648     }
649 
650     info->pattern_count = pattern_count;
651     info->patterns_size = patterns_size;
652     info->patterns = patterns;
653 }
654 
655 static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
656 {
657     BitmapDecoderInfo *This;
658 
659     This = calloc(1, sizeof(BitmapDecoderInfo));
660     if (!This)
661     {
662         RegCloseKey(classkey);
663         return E_OUTOFMEMORY;
664     }
665 
666     This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&BitmapDecoderInfo_Vtbl;
667     This->base.ref = 1;
668     This->classkey = classkey;
669     This->base.clsid = *clsid;
670 
671     read_bitmap_patterns(This);
672 
673     *ret = &This->base;
674     return S_OK;
675 }
676 
677 typedef struct {
678     ComponentInfo base;
679     HKEY classkey;
680 } BitmapEncoderInfo;
681 
682 static inline BitmapEncoderInfo *impl_from_IWICBitmapEncoderInfo(IWICBitmapEncoderInfo *iface)
683 {
684     return CONTAINING_RECORD((IWICComponentInfo*)iface, BitmapEncoderInfo, base.IWICComponentInfo_iface);
685 }
686 
687 static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *iface, REFIID iid,
688     void **ppv)
689 {
690     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
691     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
692 
693     if (!ppv) return E_INVALIDARG;
694 
695     if (IsEqualIID(&IID_IUnknown, iid) ||
696         IsEqualIID(&IID_IWICComponentInfo, iid) ||
697         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
698         IsEqualIID(&IID_IWICBitmapEncoderInfo ,iid))
699     {
700         *ppv = &This->base.IWICComponentInfo_iface;
701     }
702     else
703     {
704         *ppv = NULL;
705         return E_NOINTERFACE;
706     }
707 
708     IUnknown_AddRef((IUnknown*)*ppv);
709     return S_OK;
710 }
711 
712 static ULONG WINAPI BitmapEncoderInfo_AddRef(IWICBitmapEncoderInfo *iface)
713 {
714     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
715     ULONG ref = InterlockedIncrement(&This->base.ref);
716 
717     TRACE("(%p) refcount=%lu\n", iface, ref);
718 
719     return ref;
720 }
721 
722 static ULONG WINAPI BitmapEncoderInfo_Release(IWICBitmapEncoderInfo *iface)
723 {
724     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
725     ULONG ref = InterlockedDecrement(&This->base.ref);
726 
727     TRACE("(%p) refcount=%lu\n", iface, ref);
728 
729     if (ref == 0)
730     {
731         RegCloseKey(This->classkey);
732         free(This);
733     }
734 
735     return ref;
736 }
737 
738 static HRESULT WINAPI BitmapEncoderInfo_GetComponentType(IWICBitmapEncoderInfo *iface,
739     WICComponentType *pType)
740 {
741     TRACE("(%p,%p)\n", iface, pType);
742     if (!pType) return E_INVALIDARG;
743     *pType = WICEncoder;
744     return S_OK;
745 }
746 
747 static HRESULT WINAPI BitmapEncoderInfo_GetCLSID(IWICBitmapEncoderInfo *iface, CLSID *pclsid)
748 {
749     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
750     TRACE("(%p,%p)\n", iface, pclsid);
751 
752     if (!pclsid)
753         return E_INVALIDARG;
754 
755     *pclsid = This->base.clsid;
756     return S_OK;
757 }
758 
759 static HRESULT WINAPI BitmapEncoderInfo_GetSigningStatus(IWICBitmapEncoderInfo *iface, DWORD *pStatus)
760 {
761     FIXME("(%p,%p): stub\n", iface, pStatus);
762     return E_NOTIMPL;
763 }
764 
765 static HRESULT WINAPI BitmapEncoderInfo_GetAuthor(IWICBitmapEncoderInfo *iface, UINT cchAuthor,
766     WCHAR *wzAuthor, UINT *pcchActual)
767 {
768     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
769 
770     TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
771 
772     return ComponentInfo_GetStringValue(This->classkey, L"Author", cchAuthor, wzAuthor, pcchActual);
773 }
774 
775 static HRESULT WINAPI BitmapEncoderInfo_GetVendorGUID(IWICBitmapEncoderInfo *iface, GUID *pguidVendor)
776 {
777     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
778 
779     TRACE("(%p,%p)\n", iface, pguidVendor);
780 
781     return ComponentInfo_GetGUIDValue(This->classkey, L"Vendor", pguidVendor);
782 }
783 
784 static HRESULT WINAPI BitmapEncoderInfo_GetVersion(IWICBitmapEncoderInfo *iface, UINT cchVersion,
785     WCHAR *wzVersion, UINT *pcchActual)
786 {
787     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
788 
789     TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
790 
791     return ComponentInfo_GetStringValue(This->classkey, L"Version",
792         cchVersion, wzVersion, pcchActual);
793 }
794 
795 static HRESULT WINAPI BitmapEncoderInfo_GetSpecVersion(IWICBitmapEncoderInfo *iface, UINT cchSpecVersion,
796     WCHAR *wzSpecVersion, UINT *pcchActual)
797 {
798     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
799 
800     TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
801 
802     return ComponentInfo_GetStringValue(This->classkey, L"SpecVersion",
803         cchSpecVersion, wzSpecVersion, pcchActual);
804 }
805 
806 static HRESULT WINAPI BitmapEncoderInfo_GetFriendlyName(IWICBitmapEncoderInfo *iface, UINT cchFriendlyName,
807     WCHAR *wzFriendlyName, UINT *pcchActual)
808 {
809     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
810 
811     TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
812 
813     return ComponentInfo_GetStringValue(This->classkey, L"FriendlyName",
814         cchFriendlyName, wzFriendlyName, pcchActual);
815 }
816 
817 static HRESULT WINAPI BitmapEncoderInfo_GetContainerFormat(IWICBitmapEncoderInfo *iface,
818     GUID *pguidContainerFormat)
819 {
820     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
821     TRACE("(%p,%p)\n", iface, pguidContainerFormat);
822     return ComponentInfo_GetGUIDValue(This->classkey, L"ContainerFormat", pguidContainerFormat);
823 }
824 
825 static HRESULT WINAPI BitmapEncoderInfo_GetPixelFormats(IWICBitmapEncoderInfo *iface,
826     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
827 {
828     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
829     TRACE("(%p,%u,%p,%p)\n", iface, cFormats, pguidPixelFormats, pcActual);
830     return ComponentInfo_GetGuidList(This->classkey, L"Formats", cFormats, pguidPixelFormats, pcActual);
831 }
832 
833 static HRESULT WINAPI BitmapEncoderInfo_GetColorManagementVersion(IWICBitmapEncoderInfo *iface,
834     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
835 {
836     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
837     return E_NOTIMPL;
838 }
839 
840 static HRESULT WINAPI BitmapEncoderInfo_GetDeviceManufacturer(IWICBitmapEncoderInfo *iface,
841     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
842 {
843     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
844     return E_NOTIMPL;
845 }
846 
847 static HRESULT WINAPI BitmapEncoderInfo_GetDeviceModels(IWICBitmapEncoderInfo *iface,
848     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
849 {
850     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
851     return E_NOTIMPL;
852 }
853 
854 static HRESULT WINAPI BitmapEncoderInfo_GetMimeTypes(IWICBitmapEncoderInfo *iface,
855     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
856 {
857     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
858 
859     TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
860 
861     return ComponentInfo_GetStringValue(This->classkey, L"MimeTypes",
862         cchMimeTypes, wzMimeTypes, pcchActual);
863 }
864 
865 static HRESULT WINAPI BitmapEncoderInfo_GetFileExtensions(IWICBitmapEncoderInfo *iface,
866     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
867 {
868     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
869 
870     TRACE("(%p,%u,%p,%p)\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
871 
872     return ComponentInfo_GetStringValue(This->classkey, L"FileExtensions",
873         cchFileExtensions, wzFileExtensions, pcchActual);
874 }
875 
876 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportAnimation(IWICBitmapEncoderInfo *iface,
877     BOOL *pfSupportAnimation)
878 {
879     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
880     return E_NOTIMPL;
881 }
882 
883 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportChromaKey(IWICBitmapEncoderInfo *iface,
884     BOOL *pfSupportChromaKey)
885 {
886     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
887     return E_NOTIMPL;
888 }
889 
890 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportLossless(IWICBitmapEncoderInfo *iface,
891     BOOL *pfSupportLossless)
892 {
893     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
894     return E_NOTIMPL;
895 }
896 
897 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportMultiframe(IWICBitmapEncoderInfo *iface,
898     BOOL *pfSupportMultiframe)
899 {
900     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
901     return E_NOTIMPL;
902 }
903 
904 static HRESULT WINAPI BitmapEncoderInfo_MatchesMimeType(IWICBitmapEncoderInfo *iface,
905     LPCWSTR wzMimeType, BOOL *pfMatches)
906 {
907     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
908     return E_NOTIMPL;
909 }
910 
911 static HRESULT WINAPI BitmapEncoderInfo_CreateInstance(IWICBitmapEncoderInfo *iface,
912     IWICBitmapEncoder **ppIBitmapEncoder)
913 {
914     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
915 
916     TRACE("(%p,%p)\n", iface, ppIBitmapEncoder);
917 
918     return create_instance(&This->base.clsid, &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder);
919 }
920 
921 static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = {
922     BitmapEncoderInfo_QueryInterface,
923     BitmapEncoderInfo_AddRef,
924     BitmapEncoderInfo_Release,
925     BitmapEncoderInfo_GetComponentType,
926     BitmapEncoderInfo_GetCLSID,
927     BitmapEncoderInfo_GetSigningStatus,
928     BitmapEncoderInfo_GetAuthor,
929     BitmapEncoderInfo_GetVendorGUID,
930     BitmapEncoderInfo_GetVersion,
931     BitmapEncoderInfo_GetSpecVersion,
932     BitmapEncoderInfo_GetFriendlyName,
933     BitmapEncoderInfo_GetContainerFormat,
934     BitmapEncoderInfo_GetPixelFormats,
935     BitmapEncoderInfo_GetColorManagementVersion,
936     BitmapEncoderInfo_GetDeviceManufacturer,
937     BitmapEncoderInfo_GetDeviceModels,
938     BitmapEncoderInfo_GetMimeTypes,
939     BitmapEncoderInfo_GetFileExtensions,
940     BitmapEncoderInfo_DoesSupportAnimation,
941     BitmapEncoderInfo_DoesSupportChromaKey,
942     BitmapEncoderInfo_DoesSupportLossless,
943     BitmapEncoderInfo_DoesSupportMultiframe,
944     BitmapEncoderInfo_MatchesMimeType,
945     BitmapEncoderInfo_CreateInstance
946 };
947 
948 static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
949 {
950     BitmapEncoderInfo *This;
951 
952     This = malloc(sizeof(BitmapEncoderInfo));
953     if (!This)
954     {
955         RegCloseKey(classkey);
956         return E_OUTOFMEMORY;
957     }
958 
959     This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&BitmapEncoderInfo_Vtbl;
960     This->base.ref = 1;
961     This->classkey = classkey;
962     This->base.clsid = *clsid;
963 
964     *ret = &This->base;
965     return S_OK;
966 }
967 
968 typedef struct {
969     ComponentInfo base;
970     HKEY classkey;
971 } FormatConverterInfo;
972 
973 static inline FormatConverterInfo *impl_from_IWICFormatConverterInfo(IWICFormatConverterInfo *iface)
974 {
975     return CONTAINING_RECORD((IWICComponentInfo*)iface, FormatConverterInfo, base.IWICComponentInfo_iface);
976 }
977 
978 static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
979     void **ppv)
980 {
981     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
982     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
983 
984     if (!ppv) return E_INVALIDARG;
985 
986     if (IsEqualIID(&IID_IUnknown, iid) ||
987         IsEqualIID(&IID_IWICComponentInfo, iid) ||
988         IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
989     {
990         *ppv = &This->base.IWICComponentInfo_iface;
991     }
992     else
993     {
994         *ppv = NULL;
995         return E_NOINTERFACE;
996     }
997 
998     IUnknown_AddRef((IUnknown*)*ppv);
999     return S_OK;
1000 }
1001 
1002 static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
1003 {
1004     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1005     ULONG ref = InterlockedIncrement(&This->base.ref);
1006 
1007     TRACE("(%p) refcount=%lu\n", iface, ref);
1008 
1009     return ref;
1010 }
1011 
1012 static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
1013 {
1014     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1015     ULONG ref = InterlockedDecrement(&This->base.ref);
1016 
1017     TRACE("(%p) refcount=%lu\n", iface, ref);
1018 
1019     if (ref == 0)
1020     {
1021         RegCloseKey(This->classkey);
1022         free(This);
1023     }
1024 
1025     return ref;
1026 }
1027 
1028 static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
1029     WICComponentType *pType)
1030 {
1031     TRACE("(%p,%p)\n", iface, pType);
1032     if (!pType) return E_INVALIDARG;
1033     *pType = WICPixelFormatConverter;
1034     return S_OK;
1035 }
1036 
1037 static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
1038 {
1039     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1040     TRACE("(%p,%p)\n", iface, pclsid);
1041 
1042     if (!pclsid)
1043         return E_INVALIDARG;
1044 
1045     *pclsid = This->base.clsid;
1046     return S_OK;
1047 }
1048 
1049 static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
1050 {
1051     FIXME("(%p,%p): stub\n", iface, pStatus);
1052     return E_NOTIMPL;
1053 }
1054 
1055 static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
1056     WCHAR *wzAuthor, UINT *pcchActual)
1057 {
1058     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1059 
1060     TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
1061 
1062     return ComponentInfo_GetStringValue(This->classkey, L"Author", cchAuthor, wzAuthor, pcchActual);
1063 }
1064 
1065 static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
1066 {
1067     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1068 
1069     TRACE("(%p,%p)\n", iface, pguidVendor);
1070 
1071     return ComponentInfo_GetGUIDValue(This->classkey, L"Vendor", pguidVendor);
1072 }
1073 
1074 static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
1075     WCHAR *wzVersion, UINT *pcchActual)
1076 {
1077     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1078 
1079     TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
1080 
1081     return ComponentInfo_GetStringValue(This->classkey, L"Version",
1082         cchVersion, wzVersion, pcchActual);
1083 }
1084 
1085 static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
1086     WCHAR *wzSpecVersion, UINT *pcchActual)
1087 {
1088     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1089 
1090     TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
1091 
1092     return ComponentInfo_GetStringValue(This->classkey, L"SpecVersion",
1093         cchSpecVersion, wzSpecVersion, pcchActual);
1094 }
1095 
1096 static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
1097     WCHAR *wzFriendlyName, UINT *pcchActual)
1098 {
1099     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1100 
1101     TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
1102 
1103     return ComponentInfo_GetStringValue(This->classkey, L"FriendlyName",
1104         cchFriendlyName, wzFriendlyName, pcchActual);
1105 }
1106 
1107 static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
1108     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
1109 {
1110     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
1111     return E_NOTIMPL;
1112 }
1113 
1114 static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
1115     IWICFormatConverter **ppIFormatConverter)
1116 {
1117     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1118 
1119     TRACE("(%p,%p)\n", iface, ppIFormatConverter);
1120 
1121     return create_instance(&This->base.clsid, &IID_IWICFormatConverter,
1122             (void**)ppIFormatConverter);
1123 }
1124 
1125 static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
1126 {
1127     LONG res;
1128     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
1129     HKEY formats_key, guid_key;
1130 
1131     /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
1132         would be O(n). A registry test should do better. */
1133 
1134     res = RegOpenKeyExW(This->classkey, L"PixelFormats", 0, KEY_READ, &formats_key);
1135     if (res != ERROR_SUCCESS) return FALSE;
1136 
1137     res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
1138     if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
1139 
1140     RegCloseKey(formats_key);
1141 
1142     return (res == ERROR_SUCCESS);
1143 }
1144 
1145 static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
1146     FormatConverterInfo_QueryInterface,
1147     FormatConverterInfo_AddRef,
1148     FormatConverterInfo_Release,
1149     FormatConverterInfo_GetComponentType,
1150     FormatConverterInfo_GetCLSID,
1151     FormatConverterInfo_GetSigningStatus,
1152     FormatConverterInfo_GetAuthor,
1153     FormatConverterInfo_GetVendorGUID,
1154     FormatConverterInfo_GetVersion,
1155     FormatConverterInfo_GetSpecVersion,
1156     FormatConverterInfo_GetFriendlyName,
1157     FormatConverterInfo_GetPixelFormats,
1158     FormatConverterInfo_CreateInstance
1159 };
1160 
1161 static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
1162 {
1163     FormatConverterInfo *This;
1164 
1165     This = malloc(sizeof(FormatConverterInfo));
1166     if (!This)
1167     {
1168         RegCloseKey(classkey);
1169         return E_OUTOFMEMORY;
1170     }
1171 
1172     This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&FormatConverterInfo_Vtbl;
1173     This->base.ref = 1;
1174     This->classkey = classkey;
1175     This->base.clsid = *clsid;
1176 
1177     *ret = &This->base;
1178     return S_OK;
1179 }
1180 
1181 typedef struct {
1182     ComponentInfo base;
1183     HKEY classkey;
1184 } PixelFormatInfo;
1185 
1186 static inline PixelFormatInfo *impl_from_IWICPixelFormatInfo2(IWICPixelFormatInfo2 *iface)
1187 {
1188     return CONTAINING_RECORD((IWICComponentInfo*)iface, PixelFormatInfo, base.IWICComponentInfo_iface);
1189 }
1190 
1191 static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface, REFIID iid,
1192     void **ppv)
1193 {
1194     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1195     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1196 
1197     if (!ppv) return E_INVALIDARG;
1198 
1199     if (IsEqualIID(&IID_IUnknown, iid) ||
1200         IsEqualIID(&IID_IWICComponentInfo, iid) ||
1201         IsEqualIID(&IID_IWICPixelFormatInfo, iid) ||
1202         IsEqualIID(&IID_IWICPixelFormatInfo2 ,iid))
1203     {
1204         *ppv = &This->base.IWICComponentInfo_iface;
1205     }
1206     else
1207     {
1208         *ppv = NULL;
1209         return E_NOINTERFACE;
1210     }
1211 
1212     IUnknown_AddRef((IUnknown*)*ppv);
1213     return S_OK;
1214 }
1215 
1216 static ULONG WINAPI PixelFormatInfo_AddRef(IWICPixelFormatInfo2 *iface)
1217 {
1218     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1219     ULONG ref = InterlockedIncrement(&This->base.ref);
1220 
1221     TRACE("(%p) refcount=%lu\n", iface, ref);
1222 
1223     return ref;
1224 }
1225 
1226 static ULONG WINAPI PixelFormatInfo_Release(IWICPixelFormatInfo2 *iface)
1227 {
1228     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1229     ULONG ref = InterlockedDecrement(&This->base.ref);
1230 
1231     TRACE("(%p) refcount=%lu\n", iface, ref);
1232 
1233     if (ref == 0)
1234     {
1235         RegCloseKey(This->classkey);
1236         free(This);
1237     }
1238 
1239     return ref;
1240 }
1241 
1242 static HRESULT WINAPI PixelFormatInfo_GetComponentType(IWICPixelFormatInfo2 *iface,
1243     WICComponentType *pType)
1244 {
1245     TRACE("(%p,%p)\n", iface, pType);
1246     if (!pType) return E_INVALIDARG;
1247     *pType = WICPixelFormat;
1248     return S_OK;
1249 }
1250 
1251 static HRESULT WINAPI PixelFormatInfo_GetCLSID(IWICPixelFormatInfo2 *iface, CLSID *pclsid)
1252 {
1253     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1254     TRACE("(%p,%p)\n", iface, pclsid);
1255 
1256     if (!pclsid)
1257         return E_INVALIDARG;
1258 
1259     *pclsid = This->base.clsid;
1260     return S_OK;
1261 }
1262 
1263 static HRESULT WINAPI PixelFormatInfo_GetSigningStatus(IWICPixelFormatInfo2 *iface, DWORD *pStatus)
1264 {
1265     TRACE("(%p,%p)\n", iface, pStatus);
1266 
1267     if (!pStatus)
1268         return E_INVALIDARG;
1269 
1270     /* Pixel formats don't require code, so they are considered signed. */
1271     *pStatus = WICComponentSigned;
1272 
1273     return S_OK;
1274 }
1275 
1276 static HRESULT WINAPI PixelFormatInfo_GetAuthor(IWICPixelFormatInfo2 *iface, UINT cchAuthor,
1277     WCHAR *wzAuthor, UINT *pcchActual)
1278 {
1279     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1280 
1281     TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
1282 
1283     return ComponentInfo_GetStringValue(This->classkey, L"Author", cchAuthor, wzAuthor, pcchActual);
1284 }
1285 
1286 static HRESULT WINAPI PixelFormatInfo_GetVendorGUID(IWICPixelFormatInfo2 *iface, GUID *pguidVendor)
1287 {
1288     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1289 
1290     TRACE("(%p,%p)\n", iface, pguidVendor);
1291 
1292     return ComponentInfo_GetGUIDValue(This->classkey, L"Vendor", pguidVendor);
1293 }
1294 
1295 static HRESULT WINAPI PixelFormatInfo_GetVersion(IWICPixelFormatInfo2 *iface, UINT cchVersion,
1296     WCHAR *wzVersion, UINT *pcchActual)
1297 {
1298     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1299 
1300     TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
1301 
1302     return ComponentInfo_GetStringValue(This->classkey, L"Version",
1303         cchVersion, wzVersion, pcchActual);
1304 }
1305 
1306 static HRESULT WINAPI PixelFormatInfo_GetSpecVersion(IWICPixelFormatInfo2 *iface, UINT cchSpecVersion,
1307     WCHAR *wzSpecVersion, UINT *pcchActual)
1308 {
1309     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1310 
1311     TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
1312 
1313     return ComponentInfo_GetStringValue(This->classkey, L"SpecVersion",
1314         cchSpecVersion, wzSpecVersion, pcchActual);
1315 }
1316 
1317 static HRESULT WINAPI PixelFormatInfo_GetFriendlyName(IWICPixelFormatInfo2 *iface, UINT cchFriendlyName,
1318     WCHAR *wzFriendlyName, UINT *pcchActual)
1319 {
1320     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1321 
1322     TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
1323 
1324     return ComponentInfo_GetStringValue(This->classkey, L"FriendlyName",
1325         cchFriendlyName, wzFriendlyName, pcchActual);
1326 }
1327 
1328 static HRESULT WINAPI PixelFormatInfo_GetFormatGUID(IWICPixelFormatInfo2 *iface,
1329     GUID *pFormat)
1330 {
1331     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1332     TRACE("(%p,%p)\n", iface, pFormat);
1333 
1334     if (!pFormat)
1335         return E_INVALIDARG;
1336 
1337     *pFormat = This->base.clsid;
1338     return S_OK;
1339 }
1340 
1341 static HRESULT WINAPI PixelFormatInfo_GetColorContext(IWICPixelFormatInfo2 *iface,
1342     IWICColorContext **ppIColorContext)
1343 {
1344     FIXME("(%p,%p): stub\n", iface, ppIColorContext);
1345     return E_NOTIMPL;
1346 }
1347 
1348 static HRESULT WINAPI PixelFormatInfo_GetBitsPerPixel(IWICPixelFormatInfo2 *iface,
1349     UINT *puiBitsPerPixel)
1350 {
1351     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1352 
1353     TRACE("(%p,%p)\n", iface, puiBitsPerPixel);
1354 
1355     return ComponentInfo_GetUINTValue(This->classkey, L"BitLength", puiBitsPerPixel);
1356 }
1357 
1358 static HRESULT WINAPI PixelFormatInfo_GetChannelCount(IWICPixelFormatInfo2 *iface,
1359     UINT *puiChannelCount)
1360 {
1361     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1362 
1363     TRACE("(%p,%p)\n", iface, puiChannelCount);
1364 
1365     return ComponentInfo_GetUINTValue(This->classkey, L"ChannelCount", puiChannelCount);
1366 }
1367 
1368 static HRESULT WINAPI PixelFormatInfo_GetChannelMask(IWICPixelFormatInfo2 *iface,
1369     UINT uiChannelIndex, UINT cbMaskBuffer, BYTE *pbMaskBuffer, UINT *pcbActual)
1370 {
1371     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1372     UINT channel_count;
1373     HRESULT hr;
1374     LONG ret;
1375     WCHAR valuename[11];
1376     DWORD cbData;
1377 
1378     TRACE("(%p,%u,%u,%p,%p)\n", iface, uiChannelIndex, cbMaskBuffer, pbMaskBuffer, pcbActual);
1379 
1380     if (!pcbActual)
1381         return E_INVALIDARG;
1382 
1383     hr = PixelFormatInfo_GetChannelCount(iface, &channel_count);
1384 
1385     if (SUCCEEDED(hr) && uiChannelIndex >= channel_count)
1386         hr = E_INVALIDARG;
1387 
1388     if (SUCCEEDED(hr))
1389     {
1390         swprintf(valuename, 11, L"%u", uiChannelIndex);
1391 
1392         cbData = cbMaskBuffer;
1393 
1394         ret = RegGetValueW(This->classkey, L"ChannelMasks", valuename, RRF_RT_REG_BINARY, NULL, pbMaskBuffer, &cbData);
1395 
1396         if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
1397             *pcbActual = cbData;
1398 
1399         if (ret == ERROR_MORE_DATA)
1400             hr = E_INVALIDARG;
1401         else
1402             hr = HRESULT_FROM_WIN32(ret);
1403     }
1404 
1405     return hr;
1406 }
1407 
1408 static HRESULT WINAPI PixelFormatInfo_SupportsTransparency(IWICPixelFormatInfo2 *iface,
1409     BOOL *pfSupportsTransparency)
1410 {
1411     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1412 
1413     TRACE("(%p,%p)\n", iface, pfSupportsTransparency);
1414 
1415     return ComponentInfo_GetUINTValue(This->classkey, L"SupportsTransparency", pfSupportsTransparency);
1416 }
1417 
1418 static HRESULT WINAPI PixelFormatInfo_GetNumericRepresentation(IWICPixelFormatInfo2 *iface,
1419     WICPixelFormatNumericRepresentation *pNumericRepresentation)
1420 {
1421     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
1422 
1423     TRACE("(%p,%p)\n", iface, pNumericRepresentation);
1424 
1425     return ComponentInfo_GetUINTValue(This->classkey, L"NumericRepresentation", pNumericRepresentation);
1426 }
1427 
1428 static const IWICPixelFormatInfo2Vtbl PixelFormatInfo_Vtbl = {
1429     PixelFormatInfo_QueryInterface,
1430     PixelFormatInfo_AddRef,
1431     PixelFormatInfo_Release,
1432     PixelFormatInfo_GetComponentType,
1433     PixelFormatInfo_GetCLSID,
1434     PixelFormatInfo_GetSigningStatus,
1435     PixelFormatInfo_GetAuthor,
1436     PixelFormatInfo_GetVendorGUID,
1437     PixelFormatInfo_GetVersion,
1438     PixelFormatInfo_GetSpecVersion,
1439     PixelFormatInfo_GetFriendlyName,
1440     PixelFormatInfo_GetFormatGUID,
1441     PixelFormatInfo_GetColorContext,
1442     PixelFormatInfo_GetBitsPerPixel,
1443     PixelFormatInfo_GetChannelCount,
1444     PixelFormatInfo_GetChannelMask,
1445     PixelFormatInfo_SupportsTransparency,
1446     PixelFormatInfo_GetNumericRepresentation
1447 };
1448 
1449 static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
1450 {
1451     PixelFormatInfo *This;
1452 
1453     This = malloc(sizeof(PixelFormatInfo));
1454     if (!This)
1455     {
1456         RegCloseKey(classkey);
1457         return E_OUTOFMEMORY;
1458     }
1459 
1460     This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&PixelFormatInfo_Vtbl;
1461     This->base.ref = 1;
1462     This->classkey = classkey;
1463     This->base.clsid = *clsid;
1464 
1465     *ret = &This->base;
1466     return S_OK;
1467 }
1468 
1469 struct metadata_container
1470 {
1471     WICMetadataPattern *patterns;
1472     UINT pattern_count;
1473     UINT patterns_size;
1474 };
1475 
1476 typedef struct
1477 {
1478     ComponentInfo base;
1479     HKEY classkey;
1480     GUID *container_formats;
1481     struct metadata_container *containers;
1482     UINT container_count;
1483 } MetadataReaderInfo;
1484 
1485 static struct metadata_container *get_metadata_container(MetadataReaderInfo *info, const GUID *guid)
1486 {
1487     unsigned i;
1488 
1489     for (i = 0; i < info->container_count; i++)
1490         if (IsEqualGUID(info->container_formats + i, guid))
1491             return info->containers + i;
1492 
1493     return NULL;
1494 }
1495 
1496 static inline MetadataReaderInfo *impl_from_IWICMetadataReaderInfo(IWICMetadataReaderInfo *iface)
1497 {
1498     return CONTAINING_RECORD((IWICComponentInfo*)iface, MetadataReaderInfo, base.IWICComponentInfo_iface);
1499 }
1500 
1501 static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo *iface,
1502     REFIID riid, void **ppv)
1503 {
1504     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1505 
1506     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
1507 
1508     if (!ppv) return E_INVALIDARG;
1509 
1510     if (IsEqualIID(&IID_IUnknown, riid) ||
1511         IsEqualIID(&IID_IWICComponentInfo, riid) ||
1512         IsEqualIID(&IID_IWICMetadataHandlerInfo, riid) ||
1513         IsEqualIID(&IID_IWICMetadataReaderInfo, riid))
1514     {
1515         *ppv = &This->base.IWICComponentInfo_iface;
1516     }
1517     else
1518     {
1519         *ppv = NULL;
1520         return E_NOINTERFACE;
1521     }
1522 
1523     IUnknown_AddRef((IUnknown *)*ppv);
1524     return S_OK;
1525 }
1526 
1527 static ULONG WINAPI MetadataReaderInfo_AddRef(IWICMetadataReaderInfo *iface)
1528 {
1529     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1530     ULONG ref = InterlockedIncrement(&This->base.ref);
1531 
1532     TRACE("(%p) refcount=%lu\n", iface, ref);
1533     return ref;
1534 }
1535 
1536 static ULONG WINAPI MetadataReaderInfo_Release(IWICMetadataReaderInfo *iface)
1537 {
1538     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1539     ULONG ref = InterlockedDecrement(&This->base.ref);
1540 
1541     TRACE("(%p) refcount=%lu\n", iface, ref);
1542 
1543     if (!ref)
1544     {
1545         unsigned i;
1546         RegCloseKey(This->classkey);
1547         for (i = 0; i < This->container_count; i++)
1548             free(This->containers[i].patterns);
1549         free(This->containers);
1550         free(This->container_formats);
1551         free(This);
1552     }
1553     return ref;
1554 }
1555 
1556 static HRESULT WINAPI MetadataReaderInfo_GetComponentType(IWICMetadataReaderInfo *iface,
1557     WICComponentType *type)
1558 {
1559     TRACE("(%p,%p)\n", iface, type);
1560 
1561     if (!type) return E_INVALIDARG;
1562     *type = WICMetadataReader;
1563     return S_OK;
1564 }
1565 
1566 static HRESULT WINAPI MetadataReaderInfo_GetCLSID(IWICMetadataReaderInfo *iface,
1567     CLSID *clsid)
1568 {
1569     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1570 
1571     TRACE("(%p,%p)\n", iface, clsid);
1572 
1573     if (!clsid) return E_INVALIDARG;
1574     *clsid = This->base.clsid;
1575     return S_OK;
1576 }
1577 
1578 static HRESULT WINAPI MetadataReaderInfo_GetSigningStatus(IWICMetadataReaderInfo *iface,
1579     DWORD *status)
1580 {
1581     FIXME("(%p,%p): stub\n", iface, status);
1582     return E_NOTIMPL;
1583 }
1584 
1585 static HRESULT WINAPI MetadataReaderInfo_GetAuthor(IWICMetadataReaderInfo *iface,
1586     UINT length, WCHAR *author, UINT *actual_length)
1587 {
1588     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1589 
1590     TRACE("(%p,%u,%p,%p)\n", iface, length, author, actual_length);
1591 
1592     return ComponentInfo_GetStringValue(This->classkey, L"Author", length, author, actual_length);
1593 }
1594 
1595 static HRESULT WINAPI MetadataReaderInfo_GetVendorGUID(IWICMetadataReaderInfo *iface,
1596     GUID *vendor)
1597 {
1598     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1599 
1600     TRACE("(%p,%p)\n", iface, vendor);
1601 
1602     return ComponentInfo_GetGUIDValue(This->classkey, L"Vendor", vendor);
1603 }
1604 
1605 static HRESULT WINAPI MetadataReaderInfo_GetVersion(IWICMetadataReaderInfo *iface,
1606     UINT length, WCHAR *version, UINT *actual_length)
1607 {
1608     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1609 
1610     TRACE("(%p,%u,%p,%p)\n", iface, length, version, actual_length);
1611 
1612     return ComponentInfo_GetStringValue(This->classkey, L"Version", length, version, actual_length);
1613 }
1614 
1615 static HRESULT WINAPI MetadataReaderInfo_GetSpecVersion(IWICMetadataReaderInfo *iface,
1616     UINT length, WCHAR *version, UINT *actual_length)
1617 {
1618     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1619 
1620     TRACE("(%p,%u,%p,%p)\n", iface, length, version, actual_length);
1621 
1622     return ComponentInfo_GetStringValue(This->classkey, L"SpecVersion",
1623                                         length, version, actual_length);
1624 }
1625 
1626 static HRESULT WINAPI MetadataReaderInfo_GetFriendlyName(IWICMetadataReaderInfo *iface,
1627     UINT length, WCHAR *name, UINT *actual_length)
1628 {
1629     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1630 
1631     TRACE("(%p,%u,%p,%p)\n", iface, length, name, actual_length);
1632 
1633     return ComponentInfo_GetStringValue(This->classkey, L"FriendlyName",
1634                                         length, name, actual_length);
1635 }
1636 
1637 static HRESULT WINAPI MetadataReaderInfo_GetMetadataFormat(IWICMetadataReaderInfo *iface,
1638     GUID *format)
1639 {
1640     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1641     TRACE("(%p,%p)\n", iface, format);
1642     return ComponentInfo_GetGUIDValue(This->classkey, L"MetadataFormat", format);
1643 }
1644 
1645 static HRESULT WINAPI MetadataReaderInfo_GetContainerFormats(IWICMetadataReaderInfo *iface,
1646     UINT length, GUID *formats, UINT *actual_length)
1647 {
1648     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1649 
1650     TRACE("(%p,%u,%p,%p)\n", iface, length, formats, actual_length);
1651 
1652     if (!actual_length)
1653         return E_INVALIDARG;
1654 
1655     *actual_length = This->container_count;
1656     if (formats)
1657     {
1658         if (This->container_count && length < This->container_count)
1659             return WINCODEC_ERR_INSUFFICIENTBUFFER;
1660         memcpy(formats, This->container_formats, This->container_count * sizeof(*formats));
1661     }
1662     return S_OK;
1663 }
1664 
1665 static HRESULT WINAPI MetadataReaderInfo_GetDeviceManufacturer(IWICMetadataReaderInfo *iface,
1666     UINT length, WCHAR *manufacturer, UINT *actual_length)
1667 {
1668     FIXME("(%p,%u,%p,%p): stub\n", iface, length, manufacturer, actual_length);
1669     return E_NOTIMPL;
1670 }
1671 
1672 static HRESULT WINAPI MetadataReaderInfo_GetDeviceModels(IWICMetadataReaderInfo *iface,
1673     UINT length, WCHAR *models, UINT *actual_length)
1674 {
1675     FIXME("(%p,%u,%p,%p): stub\n", iface, length, models, actual_length);
1676     return E_NOTIMPL;
1677 }
1678 
1679 static HRESULT WINAPI MetadataReaderInfo_DoesRequireFullStream(IWICMetadataReaderInfo *iface,
1680     BOOL *param)
1681 {
1682     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1683     TRACE("(%p,%p)\n", iface, param);
1684     return ComponentInfo_GetUINTValue(This->classkey, L"RequiresFullStream", param);
1685 }
1686 
1687 static HRESULT WINAPI MetadataReaderInfo_DoesSupportPadding(IWICMetadataReaderInfo *iface,
1688     BOOL *param)
1689 {
1690     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1691     TRACE("(%p,%p)\n", iface, param);
1692     return ComponentInfo_GetUINTValue(This->classkey, L"SupportsPadding", param);
1693 }
1694 
1695 static HRESULT WINAPI MetadataReaderInfo_DoesRequireFixedSize(IWICMetadataReaderInfo *iface,
1696     BOOL *param)
1697 {
1698     FIXME("(%p,%p): stub\n", iface, param);
1699     return E_NOTIMPL;
1700 }
1701 
1702 static HRESULT WINAPI MetadataReaderInfo_GetPatterns(IWICMetadataReaderInfo *iface,
1703     REFGUID container_guid, UINT length, WICMetadataPattern *patterns, UINT *count, UINT *actual_length)
1704 {
1705     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1706     struct metadata_container *container;
1707 
1708     TRACE("(%p,%s,%u,%p,%p,%p)\n", iface, debugstr_guid(container_guid), length, patterns, count, actual_length);
1709 
1710     if (!actual_length || !container_guid) return E_INVALIDARG;
1711 
1712     if (!(container = get_metadata_container(This, container_guid)))
1713         return WINCODEC_ERR_COMPONENTNOTFOUND;
1714 
1715     *count = container->pattern_count;
1716     *actual_length = container->patterns_size;
1717     if (patterns)
1718     {
1719         if (container->patterns_size && length < container->patterns_size)
1720             return WINCODEC_ERR_INSUFFICIENTBUFFER;
1721         memcpy(patterns, container->patterns, container->patterns_size);
1722     }
1723     return S_OK;
1724 }
1725 
1726 static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *iface,
1727     REFGUID container_guid, IStream *stream, BOOL *matches)
1728 {
1729     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1730     struct metadata_container *container;
1731     HRESULT hr;
1732     ULONG datasize=0;
1733     BYTE *data=NULL;
1734     ULONG bytesread;
1735     UINT i;
1736     LARGE_INTEGER seekpos;
1737     ULONG pos;
1738 
1739     TRACE("(%p,%s,%p,%p)\n", iface, debugstr_guid(container_guid), stream, matches);
1740 
1741     if (!(container = get_metadata_container(This, container_guid)))
1742         return WINCODEC_ERR_COMPONENTNOTFOUND;
1743 
1744     for (i=0; i < container->pattern_count; i++)
1745     {
1746         if (datasize < container->patterns[i].Length)
1747         {
1748             free(data);
1749             datasize = container->patterns[i].Length;
1750             data = malloc(container->patterns[i].Length);
1751             if (!data)
1752             {
1753                 hr = E_OUTOFMEMORY;
1754                 break;
1755             }
1756         }
1757 
1758         seekpos.QuadPart = container->patterns[i].Position.QuadPart;
1759         hr = IStream_Seek(stream, seekpos, STREAM_SEEK_SET, NULL);
1760         if (FAILED(hr)) break;
1761 
1762         hr = IStream_Read(stream, data, container->patterns[i].Length, &bytesread);
1763         if (hr == S_FALSE || (hr == S_OK && bytesread != container->patterns[i].Length)) /* past end of stream */
1764             continue;
1765         if (FAILED(hr)) break;
1766 
1767         for (pos=0; pos < container->patterns[i].Length; pos++)
1768         {
1769             if ((data[pos] & container->patterns[i].Mask[pos]) != container->patterns[i].Pattern[pos])
1770                 break;
1771         }
1772         if (pos == container->patterns[i].Length) /* matches pattern */
1773         {
1774             hr = S_OK;
1775             *matches = TRUE;
1776             break;
1777         }
1778     }
1779 
1780     if (i == container->pattern_count) /* does not match any pattern */
1781     {
1782         hr = S_OK;
1783         *matches = FALSE;
1784     }
1785 
1786     free(data);
1787 
1788     return hr;
1789 }
1790 
1791 static HRESULT WINAPI MetadataReaderInfo_CreateInstance(IWICMetadataReaderInfo *iface,
1792     IWICMetadataReader **reader)
1793 {
1794     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
1795 
1796     TRACE("(%p,%p)\n", iface, reader);
1797 
1798     return create_instance(&This->base.clsid, &IID_IWICMetadataReader, (void **)reader);
1799 }
1800 
1801 static const IWICMetadataReaderInfoVtbl MetadataReaderInfo_Vtbl = {
1802     MetadataReaderInfo_QueryInterface,
1803     MetadataReaderInfo_AddRef,
1804     MetadataReaderInfo_Release,
1805     MetadataReaderInfo_GetComponentType,
1806     MetadataReaderInfo_GetCLSID,
1807     MetadataReaderInfo_GetSigningStatus,
1808     MetadataReaderInfo_GetAuthor,
1809     MetadataReaderInfo_GetVendorGUID,
1810     MetadataReaderInfo_GetVersion,
1811     MetadataReaderInfo_GetSpecVersion,
1812     MetadataReaderInfo_GetFriendlyName,
1813     MetadataReaderInfo_GetMetadataFormat,
1814     MetadataReaderInfo_GetContainerFormats,
1815     MetadataReaderInfo_GetDeviceManufacturer,
1816     MetadataReaderInfo_GetDeviceModels,
1817     MetadataReaderInfo_DoesRequireFullStream,
1818     MetadataReaderInfo_DoesSupportPadding,
1819     MetadataReaderInfo_DoesRequireFixedSize,
1820     MetadataReaderInfo_GetPatterns,
1821     MetadataReaderInfo_MatchesPattern,
1822     MetadataReaderInfo_CreateInstance
1823 };
1824 
1825 static void read_metadata_patterns(MetadataReaderInfo *info, GUID *container_guid,
1826                                    struct metadata_container *container)
1827 {
1828     DWORD pattern_count=0;
1829     UINT patterns_size=0;
1830     WCHAR subkeyname[11], guidkeyname[39];
1831     LONG res;
1832     HKEY containers_key, guid_key, patternkey;
1833     UINT i;
1834     WICMetadataPattern *patterns;
1835     BYTE *patterns_ptr;
1836     DWORD length, valuesize;
1837 
1838     res = RegOpenKeyExW(info->classkey, L"Containers", 0, KEY_READ, &containers_key);
1839     if (res != ERROR_SUCCESS) return;
1840 
1841     StringFromGUID2(container_guid, guidkeyname, 39);
1842     res = RegOpenKeyExW(containers_key, guidkeyname, 0, KEY_READ, &guid_key);
1843     RegCloseKey(containers_key);
1844     if (res != ERROR_SUCCESS) return;
1845 
1846     res = RegQueryInfoKeyW(guid_key, NULL, NULL, NULL, &pattern_count,
1847                            NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1848     if (res != ERROR_SUCCESS)
1849     {
1850         RegCloseKey(guid_key);
1851         return;
1852     }
1853 
1854     patterns_size = pattern_count * sizeof(WICMetadataPattern);
1855     patterns = malloc(patterns_size);
1856     if (!patterns)
1857     {
1858         RegCloseKey(guid_key);
1859         return;
1860     }
1861 
1862     for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
1863     {
1864         swprintf(subkeyname, 11, L"%u", i);
1865         res = RegOpenKeyExW(guid_key, subkeyname, 0, KEY_READ, &patternkey);
1866         if (res != ERROR_SUCCESS) break;
1867 
1868         res = RegGetValueW(patternkey, NULL, L"Pattern", RRF_RT_REG_BINARY, NULL, NULL, &length);
1869         if (res == ERROR_SUCCESS)
1870         {
1871             patterns_size += length*2;
1872             patterns[i].Length = length;
1873 
1874             valuesize = sizeof(DWORD64);
1875             res = RegGetValueW(patternkey, NULL, L"DataOffset", RRF_RT_DWORD|RRF_RT_QWORD, NULL,
1876                                &patterns[i].DataOffset, &valuesize);
1877             if (res) patterns[i].DataOffset.QuadPart = 0;
1878 
1879             patterns[i].Position.QuadPart = 0;
1880             valuesize = sizeof(DWORD64);
1881             res = RegGetValueW(patternkey, NULL, L"Position", RRF_RT_DWORD|RRF_RT_QWORD, NULL,
1882                                &patterns[i].Position, &valuesize);
1883         }
1884 
1885         RegCloseKey(patternkey);
1886     }
1887 
1888     if (res != ERROR_SUCCESS || !(patterns_ptr = realloc(patterns, patterns_size)))
1889     {
1890         free(patterns);
1891         RegCloseKey(guid_key);
1892         return;
1893     }
1894     patterns = (WICMetadataPattern*)patterns_ptr;
1895     patterns_ptr += pattern_count * sizeof(*patterns);
1896 
1897     for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
1898     {
1899         swprintf(subkeyname, 11, L"%u", i);
1900         res = RegOpenKeyExW(guid_key, subkeyname, 0, KEY_READ, &patternkey);
1901         if (res != ERROR_SUCCESS) break;
1902 
1903         length = patterns[i].Length;
1904         patterns[i].Pattern = patterns_ptr;
1905         valuesize = length;
1906         res = RegGetValueW(patternkey, NULL, L"Pattern", RRF_RT_REG_BINARY, NULL,
1907                            patterns[i].Pattern, &valuesize);
1908         patterns_ptr += length;
1909 
1910         if (res == ERROR_SUCCESS)
1911         {
1912             patterns[i].Mask = patterns_ptr;
1913             valuesize = length;
1914             res = RegGetValueW(patternkey, NULL, L"Mask", RRF_RT_REG_BINARY, NULL,
1915                                patterns[i].Mask, &valuesize);
1916             patterns_ptr += length;
1917         }
1918 
1919         RegCloseKey(patternkey);
1920     }
1921 
1922     RegCloseKey(guid_key);
1923 
1924     if (res != ERROR_SUCCESS)
1925     {
1926         free(patterns);
1927         return;
1928     }
1929 
1930     container->pattern_count = pattern_count;
1931     container->patterns_size = patterns_size;
1932     container->patterns = patterns;
1933 }
1934 
1935 static BOOL read_metadata_info(MetadataReaderInfo *info)
1936 {
1937     UINT format_count;
1938     GUID *formats;
1939     HRESULT hr;
1940 
1941     hr = ComponentInfo_GetGuidList(info->classkey, L"Containers", 0, NULL, &format_count);
1942     if (FAILED(hr)) return TRUE;
1943 
1944     formats = calloc(format_count, sizeof(*formats));
1945     if (!formats) return FALSE;
1946 
1947     hr = ComponentInfo_GetGuidList(info->classkey, L"Containers", format_count, formats,
1948                                    &format_count);
1949     if (FAILED(hr))
1950     {
1951         free(formats);
1952         return FALSE;
1953     }
1954 
1955     info->container_formats = formats;
1956     info->container_count = format_count;
1957 
1958     if (format_count)
1959     {
1960         unsigned i;
1961 
1962         info->containers = calloc(format_count, sizeof(*info->containers));
1963         if (!info->containers) return FALSE;
1964 
1965         for (i = 0; i < format_count; i++)
1966             read_metadata_patterns(info, info->container_formats + i, info->containers + i);
1967     }
1968 
1969     return TRUE;
1970 }
1971 
1972 static HRESULT MetadataReaderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **info)
1973 {
1974     MetadataReaderInfo *This;
1975 
1976     This = calloc(1, sizeof(*This));
1977     if (!This)
1978     {
1979         RegCloseKey(classkey);
1980         return E_OUTOFMEMORY;
1981     }
1982 
1983     This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&MetadataReaderInfo_Vtbl;
1984     This->base.ref = 1;
1985     This->classkey = classkey;
1986     This->base.clsid = *clsid;
1987 
1988     if (!read_metadata_info(This))
1989     {
1990         IWICComponentInfo_Release(&This->base.IWICComponentInfo_iface);
1991         return WINCODEC_ERR_COMPONENTNOTFOUND;
1992     }
1993 
1994     *info = &This->base;
1995     return S_OK;
1996 }
1997 
1998 struct category {
1999     WICComponentType type;
2000     const GUID *catid;
2001     HRESULT (*constructor)(HKEY,REFCLSID,ComponentInfo**);
2002 };
2003 
2004 static const struct category categories[] = {
2005     {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
2006     {WICEncoder, &CATID_WICBitmapEncoders, BitmapEncoderInfo_Constructor},
2007     {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
2008     {WICPixelFormat, &CATID_WICPixelFormats, PixelFormatInfo_Constructor},
2009     {WICMetadataReader, &CATID_WICMetadataReader, MetadataReaderInfo_Constructor},
2010     {0}
2011 };
2012 
2013 static int ComponentInfo_Compare(const void *key, const struct wine_rb_entry *entry)
2014 {
2015     ComponentInfo *info = WINE_RB_ENTRY_VALUE(entry, ComponentInfo, entry);
2016     return memcmp(key, &info->clsid, sizeof(info->clsid));
2017 }
2018 
2019 static struct wine_rb_tree component_info_cache = { ComponentInfo_Compare };
2020 
2021 static CRITICAL_SECTION component_info_cache_cs;
2022 static CRITICAL_SECTION_DEBUG component_info_cache_cs_dbg =
2023 {
2024     0, 0, &component_info_cache_cs,
2025     { &component_info_cache_cs_dbg.ProcessLocksList, &component_info_cache_cs_dbg.ProcessLocksList },
2026       0, 0, { (DWORD_PTR)(__FILE__ ": component_info_cache") }
2027 };
2028 static CRITICAL_SECTION component_info_cache_cs = { &component_info_cache_cs_dbg, -1, 0, 0, 0, 0 };
2029 
2030 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
2031 {
2032     struct wine_rb_entry *cache_entry;
2033     ComponentInfo *info;
2034     HKEY clsidkey;
2035     HKEY classkey;
2036     HKEY catidkey;
2037     HKEY instancekey;
2038     WCHAR guidstring[39];
2039     LONG res;
2040     const struct category *category;
2041     BOOL found = FALSE;
2042     HRESULT hr;
2043 
2044     EnterCriticalSection(&component_info_cache_cs);
2045 
2046     cache_entry = wine_rb_get(&component_info_cache, clsid);
2047     if(cache_entry)
2048     {
2049         info = WINE_RB_ENTRY_VALUE(cache_entry, ComponentInfo, entry);
2050         IWICComponentInfo_AddRef(*ppIInfo = &info->IWICComponentInfo_iface);
2051         LeaveCriticalSection(&component_info_cache_cs);
2052         return S_OK;
2053     }
2054 
2055     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &clsidkey);
2056     if (res != ERROR_SUCCESS)
2057     {
2058         LeaveCriticalSection(&component_info_cache_cs);
2059         return HRESULT_FROM_WIN32(res);
2060     }
2061 
2062     for (category=categories; category->type; category++)
2063     {
2064         StringFromGUID2(category->catid, guidstring, 39);
2065         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
2066         if (res == ERROR_SUCCESS)
2067         {
2068             res = RegOpenKeyExW(catidkey, L"Instance", 0, KEY_READ, &instancekey);
2069             if (res == ERROR_SUCCESS)
2070             {
2071                 StringFromGUID2(clsid, guidstring, 39);
2072                 res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
2073                 if (res == ERROR_SUCCESS)
2074                 {
2075                     RegCloseKey(classkey);
2076                     found = TRUE;
2077                 }
2078                 RegCloseKey(instancekey);
2079             }
2080             RegCloseKey(catidkey);
2081         }
2082         if (found) break;
2083     }
2084 
2085     if (found)
2086     {
2087         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
2088         if (res == ERROR_SUCCESS)
2089             hr = category->constructor(classkey, clsid, &info);
2090         else
2091             hr = HRESULT_FROM_WIN32(res);
2092     }
2093     else
2094     {
2095         FIXME("%s is not supported\n", wine_dbgstr_guid(clsid));
2096         hr = E_FAIL;
2097     }
2098 
2099     RegCloseKey(clsidkey);
2100 
2101     if (SUCCEEDED(hr))
2102     {
2103         wine_rb_put(&component_info_cache, clsid, &info->entry);
2104         IWICComponentInfo_AddRef(*ppIInfo = &info->IWICComponentInfo_iface);
2105     }
2106     LeaveCriticalSection(&component_info_cache_cs);
2107     return hr;
2108 }
2109 
2110 void ReleaseComponentInfos(void)
2111 {
2112     ComponentInfo *info, *next_info;
2113     WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(info, next_info, &component_info_cache, ComponentInfo, entry)
2114         IWICComponentInfo_Release(&info->IWICComponentInfo_iface);
2115 }
2116 
2117 HRESULT get_decoder_info(REFCLSID clsid, IWICBitmapDecoderInfo **info)
2118 {
2119     IWICComponentInfo *compinfo;
2120     HRESULT hr;
2121 
2122     hr = CreateComponentInfo(clsid, &compinfo);
2123     if (FAILED(hr)) return hr;
2124 
2125     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
2126         (void **)info);
2127 
2128     IWICComponentInfo_Release(compinfo);
2129 
2130     return hr;
2131 }
2132 
2133 typedef struct {
2134     IEnumUnknown IEnumUnknown_iface;
2135     LONG ref;
2136     struct list objects;
2137     struct list *cursor;
2138     CRITICAL_SECTION lock; /* Must be held when reading or writing cursor */
2139 } ComponentEnum;
2140 
2141 static inline ComponentEnum *impl_from_IEnumUnknown(IEnumUnknown *iface)
2142 {
2143     return CONTAINING_RECORD(iface, ComponentEnum, IEnumUnknown_iface);
2144 }
2145 
2146 typedef struct {
2147     struct list entry;
2148     IUnknown *unk;
2149 } ComponentEnumItem;
2150 
2151 static const IEnumUnknownVtbl ComponentEnumVtbl;
2152 
2153 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
2154     void **ppv)
2155 {
2156     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2157     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
2158 
2159     if (!ppv) return E_INVALIDARG;
2160 
2161     if (IsEqualIID(&IID_IUnknown, iid) ||
2162         IsEqualIID(&IID_IEnumUnknown, iid))
2163     {
2164         *ppv = &This->IEnumUnknown_iface;
2165     }
2166     else
2167     {
2168         *ppv = NULL;
2169         return E_NOINTERFACE;
2170     }
2171 
2172     IUnknown_AddRef((IUnknown*)*ppv);
2173     return S_OK;
2174 }
2175 
2176 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
2177 {
2178     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2179     ULONG ref = InterlockedIncrement(&This->ref);
2180 
2181     TRACE("(%p) refcount=%lu\n", iface, ref);
2182 
2183     return ref;
2184 }
2185 
2186 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
2187 {
2188     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2189     ULONG ref = InterlockedDecrement(&This->ref);
2190     ComponentEnumItem *cursor, *cursor2;
2191 
2192     TRACE("(%p) refcount=%lu\n", iface, ref);
2193 
2194     if (ref == 0)
2195     {
2196         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
2197         {
2198             IUnknown_Release(cursor->unk);
2199             list_remove(&cursor->entry);
2200             free(cursor);
2201         }
2202         This->lock.DebugInfo->Spare[0] = 0;
2203         DeleteCriticalSection(&This->lock);
2204         free(This);
2205     }
2206 
2207     return ref;
2208 }
2209 
2210 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
2211     IUnknown **rgelt, ULONG *pceltFetched)
2212 {
2213     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2214     ULONG num_fetched=0;
2215     ComponentEnumItem *item;
2216     HRESULT hr=S_OK;
2217 
2218     TRACE("(%p,%lu,%p,%p)\n", iface, celt, rgelt, pceltFetched);
2219 
2220     EnterCriticalSection(&This->lock);
2221     while (num_fetched<celt)
2222     {
2223         if (!This->cursor)
2224         {
2225             hr = S_FALSE;
2226             break;
2227         }
2228         item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
2229         IUnknown_AddRef(item->unk);
2230         rgelt[num_fetched] = item->unk;
2231         num_fetched++;
2232         This->cursor = list_next(&This->objects, This->cursor);
2233     }
2234     LeaveCriticalSection(&This->lock);
2235     if (pceltFetched)
2236         *pceltFetched = num_fetched;
2237     return hr;
2238 }
2239 
2240 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
2241 {
2242     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2243     ULONG i;
2244     HRESULT hr=S_OK;
2245 
2246     TRACE("(%p,%lu)\n", iface, celt);
2247 
2248     EnterCriticalSection(&This->lock);
2249     for (i=0; i<celt; i++)
2250     {
2251         if (!This->cursor)
2252         {
2253             hr = S_FALSE;
2254             break;
2255         }
2256         This->cursor = list_next(&This->objects, This->cursor);
2257     }
2258     LeaveCriticalSection(&This->lock);
2259     return hr;
2260 }
2261 
2262 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
2263 {
2264     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2265 
2266     TRACE("(%p)\n", iface);
2267 
2268     EnterCriticalSection(&This->lock);
2269     This->cursor = list_head(&This->objects);
2270     LeaveCriticalSection(&This->lock);
2271     return S_OK;
2272 }
2273 
2274 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
2275 {
2276     ComponentEnum *This = impl_from_IEnumUnknown(iface);
2277     ComponentEnum *new_enum;
2278     ComponentEnumItem *old_item, *new_item;
2279     HRESULT ret=S_OK;
2280     struct list *old_cursor;
2281 
2282     new_enum = malloc(sizeof(ComponentEnum));
2283     if (!new_enum)
2284     {
2285         *ppenum = NULL;
2286         return E_OUTOFMEMORY;
2287     }
2288 
2289     new_enum->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
2290     new_enum->ref = 1;
2291     new_enum->cursor = NULL;
2292     list_init(&new_enum->objects);
2293 #ifdef __REACTOS__
2294     InitializeCriticalSection(&new_enum->lock);
2295 #else
2296     InitializeCriticalSectionEx(&new_enum->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
2297 #endif
2298     new_enum->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
2299 
2300     EnterCriticalSection(&This->lock);
2301     old_cursor = This->cursor;
2302     LeaveCriticalSection(&This->lock);
2303 
2304     LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
2305     {
2306         new_item = malloc(sizeof(ComponentEnumItem));
2307         if (!new_item)
2308         {
2309             ret = E_OUTOFMEMORY;
2310             break;
2311         }
2312         new_item->unk = old_item->unk;
2313         list_add_tail(&new_enum->objects, &new_item->entry);
2314         IUnknown_AddRef(new_item->unk);
2315         if (&old_item->entry == old_cursor) new_enum->cursor = &new_item->entry;
2316     }
2317 
2318     if (FAILED(ret))
2319     {
2320         IEnumUnknown_Release(&new_enum->IEnumUnknown_iface);
2321         *ppenum = NULL;
2322     }
2323     else
2324         *ppenum = &new_enum->IEnumUnknown_iface;
2325 
2326     return ret;
2327 }
2328 
2329 static const IEnumUnknownVtbl ComponentEnumVtbl = {
2330     ComponentEnum_QueryInterface,
2331     ComponentEnum_AddRef,
2332     ComponentEnum_Release,
2333     ComponentEnum_Next,
2334     ComponentEnum_Skip,
2335     ComponentEnum_Reset,
2336     ComponentEnum_Clone
2337 };
2338 
2339 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
2340 {
2341     ComponentEnum *This;
2342     ComponentEnumItem *item;
2343     const struct category *category;
2344     HKEY clsidkey, catidkey, instancekey;
2345     WCHAR guidstring[39];
2346     LONG res;
2347     int i;
2348     HRESULT hr=S_OK;
2349     CLSID clsid;
2350 
2351     if (options) FIXME("ignoring flags %lx\n", options);
2352 
2353     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, KEY_READ, &clsidkey);
2354     if (res != ERROR_SUCCESS)
2355         return HRESULT_FROM_WIN32(res);
2356 
2357     This = malloc(sizeof(ComponentEnum));
2358     if (!This)
2359     {
2360         RegCloseKey(clsidkey);
2361         return E_OUTOFMEMORY;
2362     }
2363 
2364     This->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
2365     This->ref = 1;
2366     list_init(&This->objects);
2367 #ifdef __REACTOS__
2368     InitializeCriticalSection(&This->lock);
2369 #else
2370     InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
2371 #endif
2372     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
2373 
2374     for (category=categories; category->type && hr == S_OK; category++)
2375     {
2376         if ((category->type & componentTypes) == 0) continue;
2377         StringFromGUID2(category->catid, guidstring, 39);
2378         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
2379         if (res == ERROR_SUCCESS)
2380         {
2381             res = RegOpenKeyExW(catidkey, L"Instance", 0, KEY_READ, &instancekey);
2382             if (res == ERROR_SUCCESS)
2383             {
2384                 i=0;
2385                 for (;;i++)
2386                 {
2387                     DWORD guidstring_size = 39;
2388                     res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
2389                     if (res != ERROR_SUCCESS) break;
2390 
2391                     item = malloc(sizeof(ComponentEnumItem));
2392                     if (!item) { hr = E_OUTOFMEMORY; break; }
2393 
2394                     hr = CLSIDFromString(guidstring, &clsid);
2395                     if (SUCCEEDED(hr))
2396                     {
2397                         hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
2398                         if (SUCCEEDED(hr))
2399                             list_add_tail(&This->objects, &item->entry);
2400                     }
2401 
2402                     if (FAILED(hr))
2403                     {
2404                         free(item);
2405                         hr = S_OK;
2406                     }
2407                 }
2408                 RegCloseKey(instancekey);
2409             }
2410             RegCloseKey(catidkey);
2411         }
2412         if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
2413             hr = HRESULT_FROM_WIN32(res);
2414     }
2415     RegCloseKey(clsidkey);
2416 
2417     if (SUCCEEDED(hr))
2418     {
2419         IEnumUnknown_Reset(&This->IEnumUnknown_iface);
2420         *ppIEnumUnknown = &This->IEnumUnknown_iface;
2421     }
2422     else
2423     {
2424         *ppIEnumUnknown = NULL;
2425         IEnumUnknown_Release(&This->IEnumUnknown_iface);
2426     }
2427 
2428     return hr;
2429 }
2430 
2431 static BOOL is_1bpp_format(const WICPixelFormatGUID *format)
2432 {
2433     return IsEqualGUID(format, &GUID_WICPixelFormatBlackWhite) ||
2434            IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed);
2435 }
2436 
2437 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
2438 {
2439     HRESULT res;
2440     IEnumUnknown *enumconverters;
2441     IUnknown *unkconverterinfo;
2442     IWICFormatConverterInfo *converterinfo=NULL;
2443     IWICFormatConverter *converter=NULL;
2444     GUID srcFormat;
2445     WCHAR srcformatstr[39], dstformatstr[39];
2446     BOOL canconvert;
2447     ULONG num_fetched;
2448 
2449     TRACE("%s,%p,%p\n", debugstr_guid(dstFormat), pISrc, ppIDst);
2450 
2451     res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
2452     if (FAILED(res)) return res;
2453 
2454     if (IsEqualGUID(&srcFormat, dstFormat) || (is_1bpp_format(&srcFormat) && is_1bpp_format(dstFormat)))
2455     {
2456         IWICBitmapSource_AddRef(pISrc);
2457         *ppIDst = pISrc;
2458         return S_OK;
2459     }
2460 
2461     StringFromGUID2(&srcFormat, srcformatstr, 39);
2462     StringFromGUID2(dstFormat, dstformatstr, 39);
2463 
2464     res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
2465     if (FAILED(res)) return res;
2466 
2467     while (!converter)
2468     {
2469         res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
2470 
2471         if (res == S_OK)
2472         {
2473             res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
2474 
2475             if (SUCCEEDED(res))
2476             {
2477                 canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
2478 
2479                 if (canconvert)
2480                     canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
2481 
2482                 if (canconvert)
2483                 {
2484                     res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
2485 
2486                     if (SUCCEEDED(res))
2487                         res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
2488 
2489                     if (SUCCEEDED(res) && canconvert)
2490                         res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
2491                             NULL, 0.0, WICBitmapPaletteTypeMedianCut);
2492 
2493                     if (FAILED(res) || !canconvert)
2494                     {
2495                         if (converter)
2496                         {
2497                             IWICFormatConverter_Release(converter);
2498                             converter = NULL;
2499                         }
2500                     }
2501                 }
2502 
2503                 IWICFormatConverterInfo_Release(converterinfo);
2504             }
2505 
2506             IUnknown_Release(unkconverterinfo);
2507         }
2508         else
2509             break;
2510     }
2511 
2512     IEnumUnknown_Release(enumconverters);
2513 
2514     if (converter)
2515     {
2516         res = IWICFormatConverter_QueryInterface(converter, &IID_IWICBitmapSource, (void **)ppIDst);
2517         IWICFormatConverter_Release(converter);
2518         return res;
2519     }
2520     else
2521     {
2522         FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
2523         *ppIDst = NULL;
2524         return WINCODEC_ERR_COMPONENTNOTFOUND;
2525     }
2526 }
2527