kernel32: Check the 64-bit flag when starting a process.
[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 typedef struct {
40     const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl;
41     LONG ref;
42     HKEY classkey;
43     CLSID clsid;
44 } BitmapDecoderInfo;
45
46 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
47     void **ppv)
48 {
49     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
50     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
51
52     if (!ppv) return E_INVALIDARG;
53
54     if (IsEqualIID(&IID_IUnknown, iid) ||
55         IsEqualIID(&IID_IWICComponentInfo, iid) ||
56         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
57         IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
58     {
59         *ppv = This;
60     }
61     else
62     {
63         *ppv = NULL;
64         return E_NOINTERFACE;
65     }
66
67     IUnknown_AddRef((IUnknown*)*ppv);
68     return S_OK;
69 }
70
71 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
72 {
73     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
74     ULONG ref = InterlockedIncrement(&This->ref);
75
76     TRACE("(%p) refcount=%u\n", iface, ref);
77
78     return ref;
79 }
80
81 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
82 {
83     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
84     ULONG ref = InterlockedDecrement(&This->ref);
85
86     TRACE("(%p) refcount=%u\n", iface, ref);
87
88     if (ref == 0)
89     {
90         RegCloseKey(This->classkey);
91         HeapFree(GetProcessHeap(), 0, This);
92     }
93
94     return ref;
95 }
96
97 static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
98     WICComponentType *pType)
99 {
100     TRACE("(%p,%p)\n", iface, pType);
101     *pType = WICDecoder;
102     return S_OK;
103 }
104
105 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
106 {
107     FIXME("(%p,%p): stub\n", iface, pclsid);
108     return E_NOTIMPL;
109 }
110
111 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
112 {
113     FIXME("(%p,%p): stub\n", iface, pStatus);
114     return E_NOTIMPL;
115 }
116
117 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
118     WCHAR *wzAuthor, UINT *pcchActual)
119 {
120     FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
121     return E_NOTIMPL;
122 }
123
124 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
125 {
126     FIXME("(%p,%p): stub\n", iface, pguidVendor);
127     return E_NOTIMPL;
128 }
129
130 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
131     WCHAR *wzVersion, UINT *pcchActual)
132 {
133     FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
134     return E_NOTIMPL;
135 }
136
137 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
138     WCHAR *wzSpecVersion, UINT *pcchActual)
139 {
140     FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
141     return E_NOTIMPL;
142 }
143
144 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
145     WCHAR *wzFriendlyName, UINT *pcchActual)
146 {
147     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
148     return E_NOTIMPL;
149 }
150
151 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
152     GUID *pguidContainerFormat)
153 {
154     FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
155     return E_NOTIMPL;
156 }
157
158 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
159     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
160 {
161     FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
162     return E_NOTIMPL;
163 }
164
165 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
166     UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
167 {
168     FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
169     return E_NOTIMPL;
170 }
171
172 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
173     UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
174 {
175     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
176     return E_NOTIMPL;
177 }
178
179 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
180     UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
181 {
182     FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
183     return E_NOTIMPL;
184 }
185
186 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
187     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
188 {
189     FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
190     return E_NOTIMPL;
191 }
192
193 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
194     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
195 {
196     FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
197     return E_NOTIMPL;
198 }
199
200 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
201     BOOL *pfSupportAnimation)
202 {
203     FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
204     return E_NOTIMPL;
205 }
206
207 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
208     BOOL *pfSupportChromaKey)
209 {
210     FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
211     return E_NOTIMPL;
212 }
213
214 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
215     BOOL *pfSupportLossless)
216 {
217     FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
222     BOOL *pfSupportMultiframe)
223 {
224     FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
225     return E_NOTIMPL;
226 }
227
228 static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
229     LPCWSTR wzMimeType, BOOL *pfMatches)
230 {
231     FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
232     return E_NOTIMPL;
233 }
234
235 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
236     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
237 {
238     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
239     UINT pattern_count=0, patterns_size=0;
240     WCHAR subkeyname[11];
241     LONG res;
242     HKEY patternskey, patternkey;
243     static const WCHAR uintformatW[] = {'%','u',0};
244     static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
245     static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
246     static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
247     static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
248     static const WCHAR maskW[] = {'M','a','s','k',0};
249     static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
250     HRESULT hr=S_OK;
251     UINT i;
252     BYTE *bPatterns=(BYTE*)pPatterns;
253     DWORD length, valuesize;
254
255     TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
256
257     res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
258     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
259
260     res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
261     if (res == ERROR_SUCCESS)
262     {
263         patterns_size = pattern_count * sizeof(WICBitmapPattern);
264
265         for (i=0; i<pattern_count; i++)
266         {
267             snprintfW(subkeyname, 11, uintformatW, i);
268             res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
269             if (res == ERROR_SUCCESS)
270             {
271                 valuesize = sizeof(ULONG);
272                 res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
273                     &length, &valuesize);
274                 patterns_size += length*2;
275
276                 if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
277                 {
278                     pPatterns[i].Length = length;
279
280                     pPatterns[i].EndOfStream = 0;
281                     valuesize = sizeof(BOOL);
282                     RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
283                         &pPatterns[i].EndOfStream, &valuesize);
284
285                     pPatterns[i].Position.QuadPart = 0;
286                     valuesize = sizeof(ULARGE_INTEGER);
287                     res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
288                         &pPatterns[i].Position, &valuesize);
289
290                     if (res == ERROR_SUCCESS)
291                     {
292                         pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
293                         valuesize = length;
294                         res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
295                             pPatterns[i].Pattern, &valuesize);
296                     }
297
298                     if (res == ERROR_SUCCESS)
299                     {
300                         pPatterns[i].Mask = bPatterns+patterns_size-length;
301                         valuesize = length;
302                         res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
303                             pPatterns[i].Mask, &valuesize);
304                     }
305                 }
306
307                 RegCloseKey(patternkey);
308             }
309             if (res != ERROR_SUCCESS)
310             {
311                 hr = HRESULT_FROM_WIN32(res);
312                 break;
313             }
314         }
315     }
316     else hr = HRESULT_FROM_WIN32(res);
317
318     RegCloseKey(patternskey);
319
320     if (hr == S_OK)
321     {
322         *pcPatterns = pattern_count;
323         *pcbPatternsActual = patterns_size;
324         if (pPatterns && cbSizePatterns < patterns_size)
325             hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
326     }
327
328     return hr;
329 }
330
331 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
332     IStream *pIStream, BOOL *pfMatches)
333 {
334     WICBitmapPattern *patterns;
335     UINT pattern_count=0, patterns_size=0;
336     HRESULT hr;
337     int i, pos;
338     BYTE *data=NULL;
339     ULONG datasize=0;
340     ULONG bytesread;
341     LARGE_INTEGER seekpos;
342
343     TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
344
345     hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
346     if (FAILED(hr)) return hr;
347
348     patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
349     if (!patterns) return E_OUTOFMEMORY;
350
351     hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
352     if (FAILED(hr)) goto end;
353
354     for (i=0; i<pattern_count; i++)
355     {
356         if (datasize < patterns[i].Length)
357         {
358             HeapFree(GetProcessHeap(), 0, data);
359             datasize = patterns[i].Length;
360             data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
361             if (!data)
362             {
363                 hr = E_OUTOFMEMORY;
364                 break;
365             }
366         }
367
368         if (patterns[i].EndOfStream)
369             seekpos.QuadPart = -patterns[i].Position.QuadPart;
370         else
371             seekpos.QuadPart = patterns[i].Position.QuadPart;
372         hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
373         if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
374         if (FAILED(hr)) break;
375
376         hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
377         if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
378             continue;
379         if (FAILED(hr)) break;
380
381         for (pos=0; pos<patterns[i].Length; pos++)
382         {
383             if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
384                 break;
385         }
386         if (pos == patterns[i].Length) /* matches pattern */
387         {
388             hr = S_OK;
389             *pfMatches = TRUE;
390             break;
391         }
392     }
393
394     if (i == pattern_count) /* does not match any pattern */
395     {
396         hr = S_OK;
397         *pfMatches = FALSE;
398     }
399
400 end:
401     HeapFree(GetProcessHeap(), 0, patterns);
402     HeapFree(GetProcessHeap(), 0, data);
403
404     return hr;
405 }
406
407 static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
408     IWICBitmapDecoder **ppIBitmapDecoder)
409 {
410     BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
411
412     TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
413
414     return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
415         &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
416 }
417
418 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
419     BitmapDecoderInfo_QueryInterface,
420     BitmapDecoderInfo_AddRef,
421     BitmapDecoderInfo_Release,
422     BitmapDecoderInfo_GetComponentType,
423     BitmapDecoderInfo_GetCLSID,
424     BitmapDecoderInfo_GetSigningStatus,
425     BitmapDecoderInfo_GetAuthor,
426     BitmapDecoderInfo_GetVendorGUID,
427     BitmapDecoderInfo_GetVersion,
428     BitmapDecoderInfo_GetSpecVersion,
429     BitmapDecoderInfo_GetFriendlyName,
430     BitmapDecoderInfo_GetContainerFormat,
431     BitmapDecoderInfo_GetPixelFormats,
432     BitmapDecoderInfo_GetColorManagementVersion,
433     BitmapDecoderInfo_GetDeviceManufacturer,
434     BitmapDecoderInfo_GetDeviceModels,
435     BitmapDecoderInfo_GetMimeTypes,
436     BitmapDecoderInfo_GetFileExtensions,
437     BitmapDecoderInfo_DoesSupportAnimation,
438     BitmapDecoderInfo_DoesSupportChromaKey,
439     BitmapDecoderInfo_DoesSupportLossless,
440     BitmapDecoderInfo_DoesSupportMultiframe,
441     BitmapDecoderInfo_MatchesMimeType,
442     BitmapDecoderInfo_GetPatterns,
443     BitmapDecoderInfo_MatchesPattern,
444     BitmapDecoderInfo_CreateInstance
445 };
446
447 static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
448 {
449     BitmapDecoderInfo *This;
450
451     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
452     if (!This)
453     {
454         RegCloseKey(classkey);
455         return E_OUTOFMEMORY;
456     }
457
458     This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl;
459     This->ref = 1;
460     This->classkey = classkey;
461     memcpy(&This->clsid, clsid, sizeof(CLSID));
462
463     *ppIInfo = (IWICComponentInfo*)This;
464     return S_OK;
465 }
466
467 static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0};
468 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
469
470 struct category {
471     WICComponentType type;
472     const GUID *catid;
473     HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
474 };
475
476 static const struct category categories[] = {
477     {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
478     {0}
479 };
480
481 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
482 {
483     HKEY clsidkey;
484     HKEY classkey;
485     HKEY catidkey;
486     HKEY instancekey;
487     WCHAR guidstring[39];
488     LONG res;
489     const struct category *category;
490     int found=0;
491     HRESULT hr;
492
493     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
494     if (res != ERROR_SUCCESS)
495         return HRESULT_FROM_WIN32(res);
496
497     for (category=categories; category->type; category++)
498     {
499         StringFromGUID2(category->catid, guidstring, 39);
500         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
501         if (res == ERROR_SUCCESS)
502         {
503             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
504             if (res == ERROR_SUCCESS)
505             {
506                 StringFromGUID2(clsid, guidstring, 39);
507                 res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
508                 if (res == ERROR_SUCCESS)
509                 {
510                     RegCloseKey(classkey);
511                     found = 1;
512                 }
513                 RegCloseKey(instancekey);
514             }
515             RegCloseKey(catidkey);
516         }
517         if (found) break;
518     }
519
520     if (found)
521     {
522         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
523         if (res == ERROR_SUCCESS)
524             hr = category->constructor(classkey, clsid, ppIInfo);
525         else
526             hr = HRESULT_FROM_WIN32(res);
527     }
528     else
529         hr = E_FAIL;
530
531     RegCloseKey(clsidkey);
532
533     return hr;
534 }
535
536 typedef struct {
537     const IEnumUnknownVtbl *IEnumUnknown_Vtbl;
538     LONG ref;
539     struct list objects;
540     struct list *cursor;
541 } ComponentEnum;
542
543 typedef struct {
544     struct list entry;
545     IUnknown *unk;
546 } ComponentEnumItem;
547
548 static const IEnumUnknownVtbl ComponentEnumVtbl;
549
550 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
551     void **ppv)
552 {
553     ComponentEnum *This = (ComponentEnum*)iface;
554     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
555
556     if (!ppv) return E_INVALIDARG;
557
558     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
559     {
560         *ppv = This;
561     }
562     else
563     {
564         *ppv = NULL;
565         return E_NOINTERFACE;
566     }
567
568     IUnknown_AddRef((IUnknown*)*ppv);
569     return S_OK;
570 }
571
572 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
573 {
574     ComponentEnum *This = (ComponentEnum*)iface;
575     ULONG ref = InterlockedIncrement(&This->ref);
576
577     TRACE("(%p) refcount=%u\n", iface, ref);
578
579     return ref;
580 }
581
582 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
583 {
584     ComponentEnum *This = (ComponentEnum*)iface;
585     ULONG ref = InterlockedDecrement(&This->ref);
586     ComponentEnumItem *cursor, *cursor2;
587
588     TRACE("(%p) refcount=%u\n", iface, ref);
589
590     if (ref == 0)
591     {
592         LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
593         {
594             IUnknown_Release(cursor->unk);
595             list_remove(&cursor->entry);
596             HeapFree(GetProcessHeap(), 0, cursor);
597         }
598         HeapFree(GetProcessHeap(), 0, This);
599     }
600
601     return ref;
602 }
603
604 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
605     IUnknown **rgelt, ULONG *pceltFetched)
606 {
607     ComponentEnum *This = (ComponentEnum*)iface;
608     int num_fetched=0;
609     ComponentEnumItem *item;
610
611     TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
612
613     while (num_fetched<celt)
614     {
615         if (!This->cursor)
616         {
617             *pceltFetched = num_fetched;
618             return S_FALSE;
619         }
620         item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
621         IUnknown_AddRef(item->unk);
622         rgelt[num_fetched] = item->unk;
623         num_fetched++;
624         This->cursor = list_next(&This->objects, This->cursor);
625     }
626     *pceltFetched = num_fetched;
627     return S_OK;
628 }
629
630 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
631 {
632     ComponentEnum *This = (ComponentEnum*)iface;
633     int i;
634
635     TRACE("(%p,%u)\n", iface, celt);
636
637     for (i=0; i<celt; i++)
638     {
639         if (!This->cursor)
640             return S_FALSE;
641         This->cursor = list_next(&This->objects, This->cursor);
642     }
643     return S_OK;
644 }
645
646 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
647 {
648     ComponentEnum *This = (ComponentEnum*)iface;
649
650     TRACE("(%p)\n", iface);
651
652     This->cursor = list_head(&This->objects);
653     return S_OK;
654 }
655
656 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
657 {
658     ComponentEnum *This = (ComponentEnum*)iface;
659     ComponentEnum *new_enum;
660     ComponentEnumItem *old_item, *new_item;
661     HRESULT ret=S_OK;
662
663     new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
664     if (!new_enum)
665     {
666         *ppenum = NULL;
667         return E_OUTOFMEMORY;
668     }
669
670     new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
671     new_enum->ref = 1;
672     new_enum->cursor = NULL;
673
674     list_init(&new_enum->objects);
675     LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
676     {
677         new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
678         if (!new_item)
679         {
680             ret = E_OUTOFMEMORY;
681             break;
682         }
683         new_item->unk = old_item->unk;
684         list_add_tail(&new_enum->objects, &new_item->entry);
685         IUnknown_AddRef(new_item->unk);
686         if (&old_item->entry == This->cursor) new_enum->cursor = &new_item->entry;
687     }
688
689     if (FAILED(ret))
690     {
691         IUnknown_Release((IUnknown*)new_enum);
692         *ppenum = NULL;
693     }
694     else
695         *ppenum = (IEnumUnknown*)new_enum;
696
697     return ret;
698 }
699
700 static const IEnumUnknownVtbl ComponentEnumVtbl = {
701     ComponentEnum_QueryInterface,
702     ComponentEnum_AddRef,
703     ComponentEnum_Release,
704     ComponentEnum_Next,
705     ComponentEnum_Skip,
706     ComponentEnum_Reset,
707     ComponentEnum_Clone
708 };
709
710 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
711 {
712     ComponentEnum *This;
713     ComponentEnumItem *item;
714     const struct category *category;
715     HKEY clsidkey, catidkey, instancekey;
716     WCHAR guidstring[39];
717     LONG res;
718     int i;
719     HRESULT hr=S_OK;
720     CLSID clsid;
721
722     if (options) FIXME("ignoring flags %x\n", options);
723
724     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
725     if (res != ERROR_SUCCESS)
726         return HRESULT_FROM_WIN32(res);
727
728     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
729     if (!This)
730     {
731         RegCloseKey(clsidkey);
732         return E_OUTOFMEMORY;
733     }
734
735     This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
736     This->ref = 1;
737     list_init(&This->objects);
738
739     for (category=categories; category->type && hr == S_OK; category++)
740     {
741         if ((category->type & componentTypes) == 0) continue;
742         StringFromGUID2(category->catid, guidstring, 39);
743         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
744         if (res == ERROR_SUCCESS)
745         {
746             res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
747             if (res == ERROR_SUCCESS)
748             {
749                 i=0;
750                 for (;;i++)
751                 {
752                     DWORD guidstring_size = 39;
753                     res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
754                     if (res != ERROR_SUCCESS) break;
755
756                     item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
757                     if (!item) { hr = E_OUTOFMEMORY; break; }
758
759                     hr = CLSIDFromString(guidstring, &clsid);
760                     if (SUCCEEDED(hr))
761                     {
762                         hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
763                         if (SUCCEEDED(hr))
764                             list_add_tail(&This->objects, &item->entry);
765                     }
766
767                     if (!SUCCEEDED(hr))
768                     {
769                         HeapFree(GetProcessHeap(), 0, item);
770                         hr = S_OK;
771                     }
772                 }
773                 RegCloseKey(instancekey);
774             }
775             RegCloseKey(catidkey);
776         }
777         if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
778             hr = HRESULT_FROM_WIN32(res);
779     }
780     RegCloseKey(clsidkey);
781
782     if (SUCCEEDED(hr))
783     {
784         IEnumUnknown_Reset((IEnumUnknown*)This);
785         *ppIEnumUnknown = (IEnumUnknown*)This;
786     }
787     else
788     {
789         *ppIEnumUnknown = NULL;
790         IUnknown_Release((IUnknown*)This);
791     }
792
793     return hr;
794 }