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