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