d3drm: Implement IDirect3DRMMesh_AddGroup.
[wine] / dlls / windowscodecs / info.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30
31 #include "wincodecs_private.h"
32
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "wine/list.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38
39 static const WCHAR mimetypes_valuename[] = {'M','i','m','e','T','y','p','e','s',0};
40 static const WCHAR pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
41 static const WCHAR containerformat_valuename[] = {'C','o','n','t','a','i','n','e','r','F','o','r','m','a','t',0};
42
43 static HRESULT ComponentInfo_GetStringValue(HKEY classkey, LPCWSTR value,
44     UINT buffer_size, WCHAR *buffer, UINT *actual_size)
45 {
46     LONG ret;
47     DWORD cbdata=buffer_size * sizeof(WCHAR);
48
49     if (!actual_size)
50         return E_INVALIDARG;
51
52     ret = RegGetValueW(classkey, NULL, value, RRF_RT_REG_SZ|RRF_NOEXPAND, NULL,
53         buffer, &cbdata);
54
55     if (ret == 0 || ret == ERROR_MORE_DATA)
56         *actual_size = cbdata/sizeof(WCHAR);
57
58     if (!buffer && buffer_size != 0)
59         /* Yes, native returns the correct size in this case. */
60         return E_INVALIDARG;
61
62     if (ret == ERROR_MORE_DATA)
63         return WINCODEC_ERR_INSUFFICIENTBUFFER;
64
65     return HRESULT_FROM_WIN32(ret);
66 }
67
68 static HRESULT ComponentInfo_GetGUIDValue(HKEY classkey, LPCWSTR value,
69     GUID *result)
70 {
71     LONG ret;
72     WCHAR guid_string[39];
73     DWORD cbdata = sizeof(guid_string);
74     HRESULT hr;
75
76     if (!result)
77         return E_INVALIDARG;
78
79     ret = RegGetValueW(classkey, NULL, value, RRF_RT_REG_SZ|RRF_NOEXPAND, NULL,
80         guid_string, &cbdata);
81
82     if (ret != ERROR_SUCCESS)
83         return HRESULT_FROM_WIN32(ret);
84
85     if (cbdata < sizeof(guid_string))
86     {
87         ERR("incomplete GUID value\n");
88         return E_FAIL;
89     }
90
91     hr = CLSIDFromString(guid_string, result);
92
93     return hr;
94 }
95
96 typedef struct {
97     IWICBitmapDecoderInfo IWICBitmapDecoderInfo_iface;
98     LONG ref;
99     HKEY classkey;
100     CLSID clsid;
101 } BitmapDecoderInfo;
102
103 static inline BitmapDecoderInfo *impl_from_IWICBitmapDecoderInfo(IWICBitmapDecoderInfo *iface)
104 {
105     return CONTAINING_RECORD(iface, BitmapDecoderInfo, IWICBitmapDecoderInfo_iface);
106 }
107
108 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
109     void **ppv)
110 {
111     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
112     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
113
114     if (!ppv) return E_INVALIDARG;
115
116     if (IsEqualIID(&IID_IUnknown, iid) ||
117         IsEqualIID(&IID_IWICComponentInfo, iid) ||
118         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
119         IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
120     {
121         *ppv = This;
122     }
123     else
124     {
125         *ppv = NULL;
126         return E_NOINTERFACE;
127     }
128
129     IUnknown_AddRef((IUnknown*)*ppv);
130     return S_OK;
131 }
132
133 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
134 {
135     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
136     ULONG ref = InterlockedIncrement(&This->ref);
137
138     TRACE("(%p) refcount=%u\n", iface, ref);
139
140     return ref;
141 }
142
143 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
144 {
145     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
146     ULONG ref = InterlockedDecrement(&This->ref);
147
148     TRACE("(%p) refcount=%u\n", iface, ref);
149
150     if (ref == 0)
151     {
152         RegCloseKey(This->classkey);
153         HeapFree(GetProcessHeap(), 0, This);
154     }
155
156     return ref;
157 }
158
159 static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
160     WICComponentType *pType)
161 {
162     TRACE("(%p,%p)\n", iface, pType);
163     *pType = WICDecoder;
164     return S_OK;
165 }
166
167 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
168 {
169     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
170     TRACE("(%p,%p)\n", iface, pclsid);
171
172     if (!pclsid)
173         return E_INVALIDARG;
174
175     memcpy(pclsid, &This->clsid, sizeof(CLSID));
176
177     return S_OK;
178 }
179
180 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
181 {
182     FIXME("(%p,%p): stub\n", iface, pStatus);
183     return E_NOTIMPL;
184 }
185
186 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
187     WCHAR *wzAuthor, UINT *pcchActual)
188 {
189     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
190     return E_NOTIMPL;
191 }
192
193 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
194 {
195     FIXME("(%p,%p): stub\n", iface, pguidVendor);
196     return E_NOTIMPL;
197 }
198
199 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
200     WCHAR *wzVersion, UINT *pcchActual)
201 {
202     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
203     return E_NOTIMPL;
204 }
205
206 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
207     WCHAR *wzSpecVersion, UINT *pcchActual)
208 {
209     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
210     return E_NOTIMPL;
211 }
212
213 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
214     WCHAR *wzFriendlyName, UINT *pcchActual)
215 {
216     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
217     return E_NOTIMPL;
218 }
219
220 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
221     GUID *pguidContainerFormat)
222 {
223     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
224     TRACE("(%p,%p)\n", iface, pguidContainerFormat);
225     return ComponentInfo_GetGUIDValue(This->classkey, containerformat_valuename, pguidContainerFormat);
226 }
227
228 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
229     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
230 {
231     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
232     return E_NOTIMPL;
233 }
234
235 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
236     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
237 {
238     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
239     return E_NOTIMPL;
240 }
241
242 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
243     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
244 {
245     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
246     return E_NOTIMPL;
247 }
248
249 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
250     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
251 {
252     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
253     return E_NOTIMPL;
254 }
255
256 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
257     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
258 {
259     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
260
261     TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
262
263     return ComponentInfo_GetStringValue(This->classkey, mimetypes_valuename,
264         cchMimeTypes, wzMimeTypes, pcchActual);
265 }
266
267 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
268     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
269 {
270     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
271     return E_NOTIMPL;
272 }
273
274 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
275     BOOL *pfSupportAnimation)
276 {
277     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
278     return E_NOTIMPL;
279 }
280
281 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
282     BOOL *pfSupportChromaKey)
283 {
284     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
285     return E_NOTIMPL;
286 }
287
288 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
289     BOOL *pfSupportLossless)
290 {
291     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
292     return E_NOTIMPL;
293 }
294
295 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
296     BOOL *pfSupportMultiframe)
297 {
298     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
299     return E_NOTIMPL;
300 }
301
302 static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
303     LPCWSTR wzMimeType, BOOL *pfMatches)
304 {
305     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
310     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
311 {
312     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
313     UINT pattern_count=0, patterns_size=0;
314     WCHAR subkeyname[11];
315     LONG res;
316     HKEY patternskey, patternkey;
317     static const WCHAR uintformatW[] = {'%','u',0};
318     static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
319     static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
320     static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
321     static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
322     static const WCHAR maskW[] = {'M','a','s','k',0};
323     static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
324     HRESULT hr=S_OK;
325     UINT i;
326     BYTE *bPatterns=(BYTE*)pPatterns;
327     DWORD length, valuesize;
328
329     TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
330
331     res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
332     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
333
334     res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
335     if (res == ERROR_SUCCESS)
336     {
337         patterns_size = pattern_count * sizeof(WICBitmapPattern);
338
339         for (i=0; i<pattern_count; i++)
340         {
341             snprintfW(subkeyname, 11, uintformatW, i);
342             res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
343             if (res == ERROR_SUCCESS)
344             {
345                 valuesize = sizeof(ULONG);
346                 res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
347                     &length, &valuesize);
348                 patterns_size += length*2;
349
350                 if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
351                 {
352                     pPatterns[i].Length = length;
353
354                     pPatterns[i].EndOfStream = 0;
355                     valuesize = sizeof(BOOL);
356                     RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
357                         &pPatterns[i].EndOfStream, &valuesize);
358
359                     pPatterns[i].Position.QuadPart = 0;
360                     valuesize = sizeof(ULARGE_INTEGER);
361                     res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
362                         &pPatterns[i].Position, &valuesize);
363
364                     if (res == ERROR_SUCCESS)
365                     {
366                         pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
367                         valuesize = length;
368                         res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
369                             pPatterns[i].Pattern, &valuesize);
370                     }
371
372                     if (res == ERROR_SUCCESS)
373                     {
374                         pPatterns[i].Mask = bPatterns+patterns_size-length;
375                         valuesize = length;
376                         res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
377                             pPatterns[i].Mask, &valuesize);
378                     }
379                 }
380
381                 RegCloseKey(patternkey);
382             }
383             if (res != ERROR_SUCCESS)
384             {
385                 hr = HRESULT_FROM_WIN32(res);
386                 break;
387             }
388         }
389     }
390     else hr = HRESULT_FROM_WIN32(res);
391
392     RegCloseKey(patternskey);
393
394     if (hr == S_OK)
395     {
396         *pcPatterns = pattern_count;
397         *pcbPatternsActual = patterns_size;
398         if (pPatterns && cbSizePatterns < patterns_size)
399             hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
400     }
401
402     return hr;
403 }
404
405 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
406     IStream *pIStream, BOOL *pfMatches)
407 {
408     WICBitmapPattern *patterns;
409     UINT pattern_count=0, patterns_size=0;
410     HRESULT hr;
411     int i, pos;
412     BYTE *data=NULL;
413     ULONG datasize=0;
414     ULONG bytesread;
415     LARGE_INTEGER seekpos;
416
417     TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
418
419     hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
420     if (FAILED(hr)) return hr;
421
422     patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
423     if (!patterns) return E_OUTOFMEMORY;
424
425     hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
426     if (FAILED(hr)) goto end;
427
428     for (i=0; i<pattern_count; i++)
429     {
430         if (datasize < patterns[i].Length)
431         {
432             HeapFree(GetProcessHeap(), 0, data);
433             datasize = patterns[i].Length;
434             data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
435             if (!data)
436             {
437                 hr = E_OUTOFMEMORY;
438                 break;
439             }
440         }
441
442         if (patterns[i].EndOfStream)
443             seekpos.QuadPart = -patterns[i].Position.QuadPart;
444         else
445             seekpos.QuadPart = patterns[i].Position.QuadPart;
446         hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
447         if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
448         if (FAILED(hr)) break;
449
450         hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
451         if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
452             continue;
453         if (FAILED(hr)) break;
454
455         for (pos=0; pos<patterns[i].Length; pos++)
456         {
457             if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
458                 break;
459         }
460         if (pos == patterns[i].Length) /* matches pattern */
461         {
462             hr = S_OK;
463             *pfMatches = TRUE;
464             break;
465         }
466     }
467
468     if (i == pattern_count) /* does not match any pattern */
469     {
470         hr = S_OK;
471         *pfMatches = FALSE;
472     }
473
474 end:
475     HeapFree(GetProcessHeap(), 0, patterns);
476     HeapFree(GetProcessHeap(), 0, data);
477
478     return hr;
479 }
480
481 static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
482     IWICBitmapDecoder **ppIBitmapDecoder)
483 {
484     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
485
486     TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
487
488     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
489         &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
490 }
491
492 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
493     BitmapDecoderInfo_QueryInterface,
494     BitmapDecoderInfo_AddRef,
495     BitmapDecoderInfo_Release,
496     BitmapDecoderInfo_GetComponentType,
497     BitmapDecoderInfo_GetCLSID,
498     BitmapDecoderInfo_GetSigningStatus,
499     BitmapDecoderInfo_GetAuthor,
500     BitmapDecoderInfo_GetVendorGUID,
501     BitmapDecoderInfo_GetVersion,
502     BitmapDecoderInfo_GetSpecVersion,
503     BitmapDecoderInfo_GetFriendlyName,
504     BitmapDecoderInfo_GetContainerFormat,
505     BitmapDecoderInfo_GetPixelFormats,
506     BitmapDecoderInfo_GetColorManagementVersion,
507     BitmapDecoderInfo_GetDeviceManufacturer,
508     BitmapDecoderInfo_GetDeviceModels,
509     BitmapDecoderInfo_GetMimeTypes,
510     BitmapDecoderInfo_GetFileExtensions,
511     BitmapDecoderInfo_DoesSupportAnimation,
512     BitmapDecoderInfo_DoesSupportChromaKey,
513     BitmapDecoderInfo_DoesSupportLossless,
514     BitmapDecoderInfo_DoesSupportMultiframe,
515     BitmapDecoderInfo_MatchesMimeType,
516     BitmapDecoderInfo_GetPatterns,
517     BitmapDecoderInfo_MatchesPattern,
518     BitmapDecoderInfo_CreateInstance
519 };
520
521 static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
522 {
523     BitmapDecoderInfo *This;
524
525     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
526     if (!This)
527     {
528         RegCloseKey(classkey);
529         return E_OUTOFMEMORY;
530     }
531
532     This->IWICBitmapDecoderInfo_iface.lpVtbl = &BitmapDecoderInfo_Vtbl;
533     This->ref = 1;
534     This->classkey = classkey;
535     memcpy(&This->clsid, clsid, sizeof(CLSID));
536
537     *ppIInfo = (IWICComponentInfo*)This;
538     return S_OK;
539 }
540
541 typedef struct {
542     IWICBitmapEncoderInfo IWICBitmapEncoderInfo_iface;
543     LONG ref;
544     HKEY classkey;
545     CLSID clsid;
546 } BitmapEncoderInfo;
547
548 static inline BitmapEncoderInfo *impl_from_IWICBitmapEncoderInfo(IWICBitmapEncoderInfo *iface)
549 {
550     return CONTAINING_RECORD(iface, BitmapEncoderInfo, IWICBitmapEncoderInfo_iface);
551 }
552
553 static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *iface, REFIID iid,
554     void **ppv)
555 {
556     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
557     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
558
559     if (!ppv) return E_INVALIDARG;
560
561     if (IsEqualIID(&IID_IUnknown, iid) ||
562         IsEqualIID(&IID_IWICComponentInfo, iid) ||
563         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
564         IsEqualIID(&IID_IWICBitmapEncoderInfo ,iid))
565     {
566         *ppv = This;
567     }
568     else
569     {
570         *ppv = NULL;
571         return E_NOINTERFACE;
572     }
573
574     IUnknown_AddRef((IUnknown*)*ppv);
575     return S_OK;
576 }
577
578 static ULONG WINAPI BitmapEncoderInfo_AddRef(IWICBitmapEncoderInfo *iface)
579 {
580     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
581     ULONG ref = InterlockedIncrement(&This->ref);
582
583     TRACE("(%p) refcount=%u\n", iface, ref);
584
585     return ref;
586 }
587
588 static ULONG WINAPI BitmapEncoderInfo_Release(IWICBitmapEncoderInfo *iface)
589 {
590     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
591     ULONG ref = InterlockedDecrement(&This->ref);
592
593     TRACE("(%p) refcount=%u\n", iface, ref);
594
595     if (ref == 0)
596     {
597         RegCloseKey(This->classkey);
598         HeapFree(GetProcessHeap(), 0, This);
599     }
600
601     return ref;
602 }
603
604 static HRESULT WINAPI BitmapEncoderInfo_GetComponentType(IWICBitmapEncoderInfo *iface,
605     WICComponentType *pType)
606 {
607     TRACE("(%p,%p)\n", iface, pType);
608     *pType = WICEncoder;
609     return S_OK;
610 }
611
612 static HRESULT WINAPI BitmapEncoderInfo_GetCLSID(IWICBitmapEncoderInfo *iface, CLSID *pclsid)
613 {
614     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
615     TRACE("(%p,%p)\n", iface, pclsid);
616
617     if (!pclsid)
618         return E_INVALIDARG;
619
620     memcpy(pclsid, &This->clsid, sizeof(CLSID));
621
622     return S_OK;
623 }
624
625 static HRESULT WINAPI BitmapEncoderInfo_GetSigningStatus(IWICBitmapEncoderInfo *iface, DWORD *pStatus)
626 {
627     FIXME("(%p,%p): stub\n", iface, pStatus);
628     return E_NOTIMPL;
629 }
630
631 static HRESULT WINAPI BitmapEncoderInfo_GetAuthor(IWICBitmapEncoderInfo *iface, UINT cchAuthor,
632     WCHAR *wzAuthor, UINT *pcchActual)
633 {
634     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
635     return E_NOTIMPL;
636 }
637
638 static HRESULT WINAPI BitmapEncoderInfo_GetVendorGUID(IWICBitmapEncoderInfo *iface, GUID *pguidVendor)
639 {
640     FIXME("(%p,%p): stub\n", iface, pguidVendor);
641     return E_NOTIMPL;
642 }
643
644 static HRESULT WINAPI BitmapEncoderInfo_GetVersion(IWICBitmapEncoderInfo *iface, UINT cchVersion,
645     WCHAR *wzVersion, UINT *pcchActual)
646 {
647     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
648     return E_NOTIMPL;
649 }
650
651 static HRESULT WINAPI BitmapEncoderInfo_GetSpecVersion(IWICBitmapEncoderInfo *iface, UINT cchSpecVersion,
652     WCHAR *wzSpecVersion, UINT *pcchActual)
653 {
654     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
655     return E_NOTIMPL;
656 }
657
658 static HRESULT WINAPI BitmapEncoderInfo_GetFriendlyName(IWICBitmapEncoderInfo *iface, UINT cchFriendlyName,
659     WCHAR *wzFriendlyName, UINT *pcchActual)
660 {
661     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
662     return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI BitmapEncoderInfo_GetContainerFormat(IWICBitmapEncoderInfo *iface,
666     GUID *pguidContainerFormat)
667 {
668     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
669     TRACE("(%p,%p)\n", iface, pguidContainerFormat);
670     return ComponentInfo_GetGUIDValue(This->classkey, containerformat_valuename, pguidContainerFormat);
671 }
672
673 static HRESULT WINAPI BitmapEncoderInfo_GetPixelFormats(IWICBitmapEncoderInfo *iface,
674     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
675 {
676     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
677     return E_NOTIMPL;
678 }
679
680 static HRESULT WINAPI BitmapEncoderInfo_GetColorManagementVersion(IWICBitmapEncoderInfo *iface,
681     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
682 {
683     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
684     return E_NOTIMPL;
685 }
686
687 static HRESULT WINAPI BitmapEncoderInfo_GetDeviceManufacturer(IWICBitmapEncoderInfo *iface,
688     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
689 {
690     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
691     return E_NOTIMPL;
692 }
693
694 static HRESULT WINAPI BitmapEncoderInfo_GetDeviceModels(IWICBitmapEncoderInfo *iface,
695     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
696 {
697     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
698     return E_NOTIMPL;
699 }
700
701 static HRESULT WINAPI BitmapEncoderInfo_GetMimeTypes(IWICBitmapEncoderInfo *iface,
702     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
703 {
704     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
705
706     TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
707
708     return ComponentInfo_GetStringValue(This->classkey, mimetypes_valuename,
709         cchMimeTypes, wzMimeTypes, pcchActual);
710 }
711
712 static HRESULT WINAPI BitmapEncoderInfo_GetFileExtensions(IWICBitmapEncoderInfo *iface,
713     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
714 {
715     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
716     return E_NOTIMPL;
717 }
718
719 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportAnimation(IWICBitmapEncoderInfo *iface,
720     BOOL *pfSupportAnimation)
721 {
722     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
723     return E_NOTIMPL;
724 }
725
726 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportChromaKey(IWICBitmapEncoderInfo *iface,
727     BOOL *pfSupportChromaKey)
728 {
729     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
730     return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportLossless(IWICBitmapEncoderInfo *iface,
734     BOOL *pfSupportLossless)
735 {
736     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
737     return E_NOTIMPL;
738 }
739
740 static HRESULT WINAPI BitmapEncoderInfo_DoesSupportMultiframe(IWICBitmapEncoderInfo *iface,
741     BOOL *pfSupportMultiframe)
742 {
743     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
744     return E_NOTIMPL;
745 }
746
747 static HRESULT WINAPI BitmapEncoderInfo_MatchesMimeType(IWICBitmapEncoderInfo *iface,
748     LPCWSTR wzMimeType, BOOL *pfMatches)
749 {
750     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
751     return E_NOTIMPL;
752 }
753
754 static HRESULT WINAPI BitmapEncoderInfo_CreateInstance(IWICBitmapEncoderInfo *iface,
755     IWICBitmapEncoder **ppIBitmapEncoder)
756 {
757     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
758
759     TRACE("(%p,%p)\n", iface, ppIBitmapEncoder);
760
761     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
762         &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder);
763 }
764
765 static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = {
766     BitmapEncoderInfo_QueryInterface,
767     BitmapEncoderInfo_AddRef,
768     BitmapEncoderInfo_Release,
769     BitmapEncoderInfo_GetComponentType,
770     BitmapEncoderInfo_GetCLSID,
771     BitmapEncoderInfo_GetSigningStatus,
772     BitmapEncoderInfo_GetAuthor,
773     BitmapEncoderInfo_GetVendorGUID,
774     BitmapEncoderInfo_GetVersion,
775     BitmapEncoderInfo_GetSpecVersion,
776     BitmapEncoderInfo_GetFriendlyName,
777     BitmapEncoderInfo_GetContainerFormat,
778     BitmapEncoderInfo_GetPixelFormats,
779     BitmapEncoderInfo_GetColorManagementVersion,
780     BitmapEncoderInfo_GetDeviceManufacturer,
781     BitmapEncoderInfo_GetDeviceModels,
782     BitmapEncoderInfo_GetMimeTypes,
783     BitmapEncoderInfo_GetFileExtensions,
784     BitmapEncoderInfo_DoesSupportAnimation,
785     BitmapEncoderInfo_DoesSupportChromaKey,
786     BitmapEncoderInfo_DoesSupportLossless,
787     BitmapEncoderInfo_DoesSupportMultiframe,
788     BitmapEncoderInfo_MatchesMimeType,
789     BitmapEncoderInfo_CreateInstance
790 };
791
792 static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
793 {
794     BitmapEncoderInfo *This;
795
796     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapEncoderInfo));
797     if (!This)
798     {
799         RegCloseKey(classkey);
800         return E_OUTOFMEMORY;
801     }
802
803     This->IWICBitmapEncoderInfo_iface.lpVtbl = &BitmapEncoderInfo_Vtbl;
804     This->ref = 1;
805     This->classkey = classkey;
806     memcpy(&This->clsid, clsid, sizeof(CLSID));
807
808     *ppIInfo = (IWICComponentInfo*)This;
809     return S_OK;
810 }
811
812 typedef struct {
813     IWICFormatConverterInfo IWICFormatConverterInfo_iface;
814     LONG ref;
815     HKEY classkey;
816     CLSID clsid;
817 } FormatConverterInfo;
818
819 static inline FormatConverterInfo *impl_from_IWICFormatConverterInfo(IWICFormatConverterInfo *iface)
820 {
821     return CONTAINING_RECORD(iface, FormatConverterInfo, IWICFormatConverterInfo_iface);
822 }
823
824 static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
825     void **ppv)
826 {
827     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
828     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
829
830     if (!ppv) return E_INVALIDARG;
831
832     if (IsEqualIID(&IID_IUnknown, iid) ||
833         IsEqualIID(&IID_IWICComponentInfo, iid) ||
834         IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
835     {
836         *ppv = This;
837     }
838     else
839     {
840         *ppv = NULL;
841         return E_NOINTERFACE;
842     }
843
844     IUnknown_AddRef((IUnknown*)*ppv);
845     return S_OK;
846 }
847
848 static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
849 {
850     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
851     ULONG ref = InterlockedIncrement(&This->ref);
852
853     TRACE("(%p) refcount=%u\n", iface, ref);
854
855     return ref;
856 }
857
858 static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
859 {
860     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
861     ULONG ref = InterlockedDecrement(&This->ref);
862
863     TRACE("(%p) refcount=%u\n", iface, ref);
864
865     if (ref == 0)
866     {
867         RegCloseKey(This->classkey);
868         HeapFree(GetProcessHeap(), 0, This);
869     }
870
871     return ref;
872 }
873
874 static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
875     WICComponentType *pType)
876 {
877     TRACE("(%p,%p)\n", iface, pType);
878     *pType = WICPixelFormatConverter;
879     return S_OK;
880 }
881
882 static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
883 {
884     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
885     TRACE("(%p,%p)\n", iface, pclsid);
886
887     if (!pclsid)
888         return E_INVALIDARG;
889
890     memcpy(pclsid, &This->clsid, sizeof(CLSID));
891
892     return S_OK;
893 }
894
895 static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
896 {
897     FIXME("(%p,%p): stub\n", iface, pStatus);
898     return E_NOTIMPL;
899 }
900
901 static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
902     WCHAR *wzAuthor, UINT *pcchActual)
903 {
904     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
905     return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
909 {
910     FIXME("(%p,%p): stub\n", iface, pguidVendor);
911     return E_NOTIMPL;
912 }
913
914 static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
915     WCHAR *wzVersion, UINT *pcchActual)
916 {
917     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
918     return E_NOTIMPL;
919 }
920
921 static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
922     WCHAR *wzSpecVersion, UINT *pcchActual)
923 {
924     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
925     return E_NOTIMPL;
926 }
927
928 static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
929     WCHAR *wzFriendlyName, UINT *pcchActual)
930 {
931     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
932     return E_NOTIMPL;
933 }
934
935 static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
936     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
937 {
938     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
939     return E_NOTIMPL;
940 }
941
942 static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
943     IWICFormatConverter **ppIFormatConverter)
944 {
945     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
946
947     TRACE("(%p,%p)\n", iface, ppIFormatConverter);
948
949     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
950         &IID_IWICFormatConverter, (void**)ppIFormatConverter);
951 }
952
953 static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
954 {
955     LONG res;
956     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
957     HKEY formats_key, guid_key;
958
959     /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
960         would be O(n). A registry test should do better. */
961
962     res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
963     if (res != ERROR_SUCCESS) return FALSE;
964
965     res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
966     if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
967
968     RegCloseKey(formats_key);
969
970     return (res == ERROR_SUCCESS);
971 }
972
973 static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
974     FormatConverterInfo_QueryInterface,
975     FormatConverterInfo_AddRef,
976     FormatConverterInfo_Release,
977     FormatConverterInfo_GetComponentType,
978     FormatConverterInfo_GetCLSID,
979     FormatConverterInfo_GetSigningStatus,
980     FormatConverterInfo_GetAuthor,
981     FormatConverterInfo_GetVendorGUID,
982     FormatConverterInfo_GetVersion,
983     FormatConverterInfo_GetSpecVersion,
984     FormatConverterInfo_GetFriendlyName,
985     FormatConverterInfo_GetPixelFormats,
986     FormatConverterInfo_CreateInstance
987 };
988
989 static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
990 {
991     FormatConverterInfo *This;
992
993     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
994     if (!This)
995     {
996         RegCloseKey(classkey);
997         return E_OUTOFMEMORY;
998     }
999
1000     This->IWICFormatConverterInfo_iface.lpVtbl = &FormatConverterInfo_Vtbl;
1001     This->ref = 1;
1002     This->classkey = classkey;
1003     memcpy(&This->clsid, clsid, sizeof(CLSID));
1004
1005     *ppIInfo = (IWICComponentInfo*)This;
1006     return S_OK;
1007 }
1008
1009 static const WCHAR clsid_keyname[] = {'C','L','S','I','D',0};
1010 static const WCHAR instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
1011
1012 struct category {
1013     WICComponentType type;
1014     const GUID *catid;
1015     HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
1016 };
1017
1018 static const struct category categories[] = {
1019     {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
1020     {WICEncoder, &CATID_WICBitmapEncoders, BitmapEncoderInfo_Constructor},
1021     {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
1022     {0}
1023 };
1024
1025 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
1026 {
1027     HKEY clsidkey;
1028     HKEY classkey;
1029     HKEY catidkey;
1030     HKEY instancekey;
1031     WCHAR guidstring[39];
1032     LONG res;
1033     const struct category *category;
1034     int found=0;
1035     HRESULT hr;
1036
1037     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
1038     if (res != ERROR_SUCCESS)
1039         return HRESULT_FROM_WIN32(res);
1040
1041     for (category=categories; category->type; category++)
1042     {
1043         StringFromGUID2(category->catid, guidstring, 39);
1044         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
1045         if (res == ERROR_SUCCESS)
1046         {
1047             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
1048             if (res == ERROR_SUCCESS)
1049             {
1050                 StringFromGUID2(clsid, guidstring, 39);
1051                 res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
1052                 if (res == ERROR_SUCCESS)
1053                 {
1054                     RegCloseKey(classkey);
1055                     found = 1;
1056                 }
1057                 RegCloseKey(instancekey);
1058             }
1059             RegCloseKey(catidkey);
1060         }
1061         if (found) break;
1062     }
1063
1064     if (found)
1065     {
1066         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
1067         if (res == ERROR_SUCCESS)
1068             hr = category->constructor(classkey, clsid, ppIInfo);
1069         else
1070             hr = HRESULT_FROM_WIN32(res);
1071     }
1072     else
1073         hr = E_FAIL;
1074
1075     RegCloseKey(clsidkey);
1076
1077     return hr;
1078 }
1079
1080 typedef struct {
1081     IEnumUnknown IEnumUnknown_iface;
1082     LONG ref;
1083     struct list objects;
1084     struct list *cursor;
1085     CRITICAL_SECTION lock; /* Must be held when reading or writing cursor */
1086 } ComponentEnum;
1087
1088 static inline ComponentEnum *impl_from_IEnumUnknown(IEnumUnknown *iface)
1089 {
1090     return CONTAINING_RECORD(iface, ComponentEnum, IEnumUnknown_iface);
1091 }
1092
1093 typedef struct {
1094     struct list entry;
1095     IUnknown *unk;
1096 } ComponentEnumItem;
1097
1098 static const IEnumUnknownVtbl ComponentEnumVtbl;
1099
1100 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
1101     void **ppv)
1102 {
1103     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1104     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1105
1106     if (!ppv) return E_INVALIDARG;
1107
1108     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
1109     {
1110         *ppv = This;
1111     }
1112     else
1113     {
1114         *ppv = NULL;
1115         return E_NOINTERFACE;
1116     }
1117
1118     IUnknown_AddRef((IUnknown*)*ppv);
1119     return S_OK;
1120 }
1121
1122 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
1123 {
1124     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1125     ULONG ref = InterlockedIncrement(&This->ref);
1126
1127     TRACE("(%p) refcount=%u\n", iface, ref);
1128
1129     return ref;
1130 }
1131
1132 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
1133 {
1134     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1135     ULONG ref = InterlockedDecrement(&This->ref);
1136     ComponentEnumItem *cursor, *cursor2;
1137
1138     TRACE("(%p) refcount=%u\n", iface, ref);
1139
1140     if (ref == 0)
1141     {
1142         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
1143         {
1144             IUnknown_Release(cursor->unk);
1145             list_remove(&cursor->entry);
1146             HeapFree(GetProcessHeap(), 0, cursor);
1147         }
1148         This->lock.DebugInfo->Spare[0] = 0;
1149         DeleteCriticalSection(&This->lock);
1150         HeapFree(GetProcessHeap(), 0, This);
1151     }
1152
1153     return ref;
1154 }
1155
1156 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
1157     IUnknown **rgelt, ULONG *pceltFetched)
1158 {
1159     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1160     int num_fetched=0;
1161     ComponentEnumItem *item;
1162     HRESULT hr=S_OK;
1163
1164     TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
1165
1166     EnterCriticalSection(&This->lock);
1167     while (num_fetched<celt)
1168     {
1169         if (!This->cursor)
1170         {
1171             hr = S_FALSE;
1172             break;
1173         }
1174         item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
1175         IUnknown_AddRef(item->unk);
1176         rgelt[num_fetched] = item->unk;
1177         num_fetched++;
1178         This->cursor = list_next(&This->objects, This->cursor);
1179     }
1180     LeaveCriticalSection(&This->lock);
1181     if (pceltFetched)
1182         *pceltFetched = num_fetched;
1183     return hr;
1184 }
1185
1186 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
1187 {
1188     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1189     int i;
1190     HRESULT hr=S_OK;
1191
1192     TRACE("(%p,%u)\n", iface, celt);
1193
1194     EnterCriticalSection(&This->lock);
1195     for (i=0; i<celt; i++)
1196     {
1197         if (!This->cursor)
1198         {
1199             hr = S_FALSE;
1200             break;
1201         }
1202         This->cursor = list_next(&This->objects, This->cursor);
1203     }
1204     LeaveCriticalSection(&This->lock);
1205     return hr;
1206 }
1207
1208 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
1209 {
1210     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1211
1212     TRACE("(%p)\n", iface);
1213
1214     EnterCriticalSection(&This->lock);
1215     This->cursor = list_head(&This->objects);
1216     LeaveCriticalSection(&This->lock);
1217     return S_OK;
1218 }
1219
1220 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
1221 {
1222     ComponentEnum *This = impl_from_IEnumUnknown(iface);
1223     ComponentEnum *new_enum;
1224     ComponentEnumItem *old_item, *new_item;
1225     HRESULT ret=S_OK;
1226     struct list *old_cursor;
1227
1228     new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
1229     if (!new_enum)
1230     {
1231         *ppenum = NULL;
1232         return E_OUTOFMEMORY;
1233     }
1234
1235     new_enum->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
1236     new_enum->ref = 1;
1237     new_enum->cursor = NULL;
1238     list_init(&new_enum->objects);
1239     InitializeCriticalSection(&new_enum->lock);
1240     new_enum->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
1241
1242     EnterCriticalSection(&This->lock);
1243     old_cursor = This->cursor;
1244     LeaveCriticalSection(&This->lock);
1245
1246     LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
1247     {
1248         new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
1249         if (!new_item)
1250         {
1251             ret = E_OUTOFMEMORY;
1252             break;
1253         }
1254         new_item->unk = old_item->unk;
1255         list_add_tail(&new_enum->objects, &new_item->entry);
1256         IUnknown_AddRef(new_item->unk);
1257         if (&old_item->entry == old_cursor) new_enum->cursor = &new_item->entry;
1258     }
1259
1260     if (FAILED(ret))
1261     {
1262         IUnknown_Release((IUnknown*)new_enum);
1263         *ppenum = NULL;
1264     }
1265     else
1266         *ppenum = (IEnumUnknown*)new_enum;
1267
1268     return ret;
1269 }
1270
1271 static const IEnumUnknownVtbl ComponentEnumVtbl = {
1272     ComponentEnum_QueryInterface,
1273     ComponentEnum_AddRef,
1274     ComponentEnum_Release,
1275     ComponentEnum_Next,
1276     ComponentEnum_Skip,
1277     ComponentEnum_Reset,
1278     ComponentEnum_Clone
1279 };
1280
1281 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
1282 {
1283     ComponentEnum *This;
1284     ComponentEnumItem *item;
1285     const struct category *category;
1286     HKEY clsidkey, catidkey, instancekey;
1287     WCHAR guidstring[39];
1288     LONG res;
1289     int i;
1290     HRESULT hr=S_OK;
1291     CLSID clsid;
1292
1293     if (options) FIXME("ignoring flags %x\n", options);
1294
1295     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
1296     if (res != ERROR_SUCCESS)
1297         return HRESULT_FROM_WIN32(res);
1298
1299     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
1300     if (!This)
1301     {
1302         RegCloseKey(clsidkey);
1303         return E_OUTOFMEMORY;
1304     }
1305
1306     This->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
1307     This->ref = 1;
1308     list_init(&This->objects);
1309     InitializeCriticalSection(&This->lock);
1310     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
1311
1312     for (category=categories; category->type && hr == S_OK; category++)
1313     {
1314         if ((category->type & componentTypes) == 0) continue;
1315         StringFromGUID2(category->catid, guidstring, 39);
1316         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
1317         if (res == ERROR_SUCCESS)
1318         {
1319             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
1320             if (res == ERROR_SUCCESS)
1321             {
1322                 i=0;
1323                 for (;;i++)
1324                 {
1325                     DWORD guidstring_size = 39;
1326                     res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
1327                     if (res != ERROR_SUCCESS) break;
1328
1329                     item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
1330                     if (!item) { hr = E_OUTOFMEMORY; break; }
1331
1332                     hr = CLSIDFromString(guidstring, &clsid);
1333                     if (SUCCEEDED(hr))
1334                     {
1335                         hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
1336                         if (SUCCEEDED(hr))
1337                             list_add_tail(&This->objects, &item->entry);
1338                     }
1339
1340                     if (FAILED(hr))
1341                     {
1342                         HeapFree(GetProcessHeap(), 0, item);
1343                         hr = S_OK;
1344                     }
1345                 }
1346                 RegCloseKey(instancekey);
1347             }
1348             RegCloseKey(catidkey);
1349         }
1350         if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
1351             hr = HRESULT_FROM_WIN32(res);
1352     }
1353     RegCloseKey(clsidkey);
1354
1355     if (SUCCEEDED(hr))
1356     {
1357         IEnumUnknown_Reset((IEnumUnknown*)This);
1358         *ppIEnumUnknown = (IEnumUnknown*)This;
1359     }
1360     else
1361     {
1362         *ppIEnumUnknown = NULL;
1363         IUnknown_Release((IUnknown*)This);
1364     }
1365
1366     return hr;
1367 }
1368
1369 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
1370 {
1371     HRESULT res;
1372     IEnumUnknown *enumconverters;
1373     IUnknown *unkconverterinfo;
1374     IWICFormatConverterInfo *converterinfo=NULL;
1375     IWICFormatConverter *converter=NULL;
1376     GUID srcFormat;
1377     WCHAR srcformatstr[39], dstformatstr[39];
1378     BOOL canconvert;
1379     ULONG num_fetched;
1380
1381     res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
1382     if (FAILED(res)) return res;
1383
1384     if (IsEqualGUID(&srcFormat, dstFormat))
1385     {
1386         IWICBitmapSource_AddRef(pISrc);
1387         *ppIDst = pISrc;
1388         return S_OK;
1389     }
1390
1391     StringFromGUID2(&srcFormat, srcformatstr, 39);
1392     StringFromGUID2(dstFormat, dstformatstr, 39);
1393
1394     res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
1395     if (FAILED(res)) return res;
1396
1397     while (!converter)
1398     {
1399         res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
1400
1401         if (res == S_OK)
1402         {
1403             res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
1404
1405             if (SUCCEEDED(res))
1406             {
1407                 canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
1408
1409                 if (canconvert)
1410                     canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
1411
1412                 if (canconvert)
1413                 {
1414                     res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
1415
1416                     if (SUCCEEDED(res))
1417                         res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
1418
1419                     if (SUCCEEDED(res) && canconvert)
1420                         res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
1421                             NULL, 0.0, WICBitmapPaletteTypeCustom);
1422
1423                     if (FAILED(res) || !canconvert)
1424                     {
1425                         if (converter)
1426                         {
1427                             IWICFormatConverter_Release(converter);
1428                             converter = NULL;
1429                         }
1430                         res = S_OK;
1431                     }
1432                 }
1433
1434                 IWICFormatConverterInfo_Release(converterinfo);
1435             }
1436
1437             IUnknown_Release(unkconverterinfo);
1438         }
1439         else
1440             break;
1441     }
1442
1443     IEnumUnknown_Release(enumconverters);
1444
1445     if (converter)
1446     {
1447         *ppIDst = (IWICBitmapSource*)converter;
1448         return S_OK;
1449     }
1450     else
1451     {
1452         FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1453         *ppIDst = NULL;
1454         return WINCODEC_ERR_COMPONENTNOTFOUND;
1455     }
1456 }