sync with trunk r46493
[reactos.git] / dll / win32 / 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 pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
40
41 typedef struct {
42 const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl;
43 LONG ref;
44 HKEY classkey;
45 CLSID clsid;
46 } BitmapDecoderInfo;
47
48 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
49 void **ppv)
50 {
51 BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
52 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
53
54 if (!ppv) return E_INVALIDARG;
55
56 if (IsEqualIID(&IID_IUnknown, iid) ||
57 IsEqualIID(&IID_IWICComponentInfo, iid) ||
58 IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
59 IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
60 {
61 *ppv = This;
62 }
63 else
64 {
65 *ppv = NULL;
66 return E_NOINTERFACE;
67 }
68
69 IUnknown_AddRef((IUnknown*)*ppv);
70 return S_OK;
71 }
72
73 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
74 {
75 BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
76 ULONG ref = InterlockedIncrement(&This->ref);
77
78 TRACE("(%p) refcount=%u\n", iface, ref);
79
80 return ref;
81 }
82
83 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
84 {
85 BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
86 ULONG ref = InterlockedDecrement(&This->ref);
87
88 TRACE("(%p) refcount=%u\n", iface, ref);
89
90 if (ref == 0)
91 {
92 RegCloseKey(This->classkey);
93 HeapFree(GetProcessHeap(), 0, This);
94 }
95
96 return ref;
97 }
98
99 static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
100 WICComponentType *pType)
101 {
102 TRACE("(%p,%p)\n", iface, pType);
103 *pType = WICDecoder;
104 return S_OK;
105 }
106
107 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
108 {
109 FIXME("(%p,%p): stub\n", iface, pclsid);
110 return E_NOTIMPL;
111 }
112
113 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
114 {
115 FIXME("(%p,%p): stub\n", iface, pStatus);
116 return E_NOTIMPL;
117 }
118
119 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
120 WCHAR *wzAuthor, UINT *pcchActual)
121 {
122 FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
123 return E_NOTIMPL;
124 }
125
126 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
127 {
128 FIXME("(%p,%p): stub\n", iface, pguidVendor);
129 return E_NOTIMPL;
130 }
131
132 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
133 WCHAR *wzVersion, UINT *pcchActual)
134 {
135 FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
136 return E_NOTIMPL;
137 }
138
139 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
140 WCHAR *wzSpecVersion, UINT *pcchActual)
141 {
142 FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
143 return E_NOTIMPL;
144 }
145
146 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
147 WCHAR *wzFriendlyName, UINT *pcchActual)
148 {
149 FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
150 return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
154 GUID *pguidContainerFormat)
155 {
156 FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
157 return E_NOTIMPL;
158 }
159
160 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
161 UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
162 {
163 FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
164 return E_NOTIMPL;
165 }
166
167 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
168 UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
169 {
170 FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
171 return E_NOTIMPL;
172 }
173
174 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
175 UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
176 {
177 FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
178 return E_NOTIMPL;
179 }
180
181 static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
182 UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
183 {
184 FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
185 return E_NOTIMPL;
186 }
187
188 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
189 UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
190 {
191 FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
192 return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
196 UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
197 {
198 FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
199 return E_NOTIMPL;
200 }
201
202 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
203 BOOL *pfSupportAnimation)
204 {
205 FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
206 return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
210 BOOL *pfSupportChromaKey)
211 {
212 FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
213 return E_NOTIMPL;
214 }
215
216 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
217 BOOL *pfSupportLossless)
218 {
219 FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
220 return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
224 BOOL *pfSupportMultiframe)
225 {
226 FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
227 return E_NOTIMPL;
228 }
229
230 static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
231 LPCWSTR wzMimeType, BOOL *pfMatches)
232 {
233 FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
234 return E_NOTIMPL;
235 }
236
237 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
238 UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
239 {
240 BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
241 UINT pattern_count=0, patterns_size=0;
242 WCHAR subkeyname[11];
243 LONG res;
244 HKEY patternskey, patternkey;
245 static const WCHAR uintformatW[] = {'%','u',0};
246 static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
247 static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
248 static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
249 static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
250 static const WCHAR maskW[] = {'M','a','s','k',0};
251 static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
252 HRESULT hr=S_OK;
253 UINT i;
254 BYTE *bPatterns=(BYTE*)pPatterns;
255 DWORD length, valuesize;
256
257 TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
258
259 res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
260 if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
261
262 res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
263 if (res == ERROR_SUCCESS)
264 {
265 patterns_size = pattern_count * sizeof(WICBitmapPattern);
266
267 for (i=0; i<pattern_count; i++)
268 {
269 snprintfW(subkeyname, 11, uintformatW, i);
270 res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
271 if (res == ERROR_SUCCESS)
272 {
273 valuesize = sizeof(ULONG);
274 res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
275 &length, &valuesize);
276 patterns_size += length*2;
277
278 if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
279 {
280 pPatterns[i].Length = length;
281
282 pPatterns[i].EndOfStream = 0;
283 valuesize = sizeof(BOOL);
284 RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
285 &pPatterns[i].EndOfStream, &valuesize);
286
287 pPatterns[i].Position.QuadPart = 0;
288 valuesize = sizeof(ULARGE_INTEGER);
289 res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
290 &pPatterns[i].Position, &valuesize);
291
292 if (res == ERROR_SUCCESS)
293 {
294 pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
295 valuesize = length;
296 res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
297 pPatterns[i].Pattern, &valuesize);
298 }
299
300 if (res == ERROR_SUCCESS)
301 {
302 pPatterns[i].Mask = bPatterns+patterns_size-length;
303 valuesize = length;
304 res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
305 pPatterns[i].Mask, &valuesize);
306 }
307 }
308
309 RegCloseKey(patternkey);
310 }
311 if (res != ERROR_SUCCESS)
312 {
313 hr = HRESULT_FROM_WIN32(res);
314 break;
315 }
316 }
317 }
318 else hr = HRESULT_FROM_WIN32(res);
319
320 RegCloseKey(patternskey);
321
322 if (hr == S_OK)
323 {
324 *pcPatterns = pattern_count;
325 *pcbPatternsActual = patterns_size;
326 if (pPatterns && cbSizePatterns < patterns_size)
327 hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
328 }
329
330 return hr;
331 }
332
333 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
334 IStream *pIStream, BOOL *pfMatches)
335 {
336 WICBitmapPattern *patterns;
337 UINT pattern_count=0, patterns_size=0;
338 HRESULT hr;
339 int i, pos;
340 BYTE *data=NULL;
341 ULONG datasize=0;
342 ULONG bytesread;
343 LARGE_INTEGER seekpos;
344
345 TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
346
347 hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
348 if (FAILED(hr)) return hr;
349
350 patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
351 if (!patterns) return E_OUTOFMEMORY;
352
353 hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
354 if (FAILED(hr)) goto end;
355
356 for (i=0; i<pattern_count; i++)
357 {
358 if (datasize < patterns[i].Length)
359 {
360 HeapFree(GetProcessHeap(), 0, data);
361 datasize = patterns[i].Length;
362 data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
363 if (!data)
364 {
365 hr = E_OUTOFMEMORY;
366 break;
367 }
368 }
369
370 if (patterns[i].EndOfStream)
371 seekpos.QuadPart = -patterns[i].Position.QuadPart;
372 else
373 seekpos.QuadPart = patterns[i].Position.QuadPart;
374 hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
375 if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
376 if (FAILED(hr)) break;
377
378 hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
379 if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
380 continue;
381 if (FAILED(hr)) break;
382
383 for (pos=0; pos<patterns[i].Length; pos++)
384 {
385 if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
386 break;
387 }
388 if (pos == patterns[i].Length) /* matches pattern */
389 {
390 hr = S_OK;
391 *pfMatches = TRUE;
392 break;
393 }
394 }
395
396 if (i == pattern_count) /* does not match any pattern */
397 {
398 hr = S_OK;
399 *pfMatches = FALSE;
400 }
401
402 end:
403 HeapFree(GetProcessHeap(), 0, patterns);
404 HeapFree(GetProcessHeap(), 0, data);
405
406 return hr;
407 }
408
409 static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
410 IWICBitmapDecoder **ppIBitmapDecoder)
411 {
412 BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
413
414 TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
415
416 return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
417 &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
418 }
419
420 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
421 BitmapDecoderInfo_QueryInterface,
422 BitmapDecoderInfo_AddRef,
423 BitmapDecoderInfo_Release,
424 BitmapDecoderInfo_GetComponentType,
425 BitmapDecoderInfo_GetCLSID,
426 BitmapDecoderInfo_GetSigningStatus,
427 BitmapDecoderInfo_GetAuthor,
428 BitmapDecoderInfo_GetVendorGUID,
429 BitmapDecoderInfo_GetVersion,
430 BitmapDecoderInfo_GetSpecVersion,
431 BitmapDecoderInfo_GetFriendlyName,
432 BitmapDecoderInfo_GetContainerFormat,
433 BitmapDecoderInfo_GetPixelFormats,
434 BitmapDecoderInfo_GetColorManagementVersion,
435 BitmapDecoderInfo_GetDeviceManufacturer,
436 BitmapDecoderInfo_GetDeviceModels,
437 BitmapDecoderInfo_GetMimeTypes,
438 BitmapDecoderInfo_GetFileExtensions,
439 BitmapDecoderInfo_DoesSupportAnimation,
440 BitmapDecoderInfo_DoesSupportChromaKey,
441 BitmapDecoderInfo_DoesSupportLossless,
442 BitmapDecoderInfo_DoesSupportMultiframe,
443 BitmapDecoderInfo_MatchesMimeType,
444 BitmapDecoderInfo_GetPatterns,
445 BitmapDecoderInfo_MatchesPattern,
446 BitmapDecoderInfo_CreateInstance
447 };
448
449 static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
450 {
451 BitmapDecoderInfo *This;
452
453 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
454 if (!This)
455 {
456 RegCloseKey(classkey);
457 return E_OUTOFMEMORY;
458 }
459
460 This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl;
461 This->ref = 1;
462 This->classkey = classkey;
463 memcpy(&This->clsid, clsid, sizeof(CLSID));
464
465 *ppIInfo = (IWICComponentInfo*)This;
466 return S_OK;
467 }
468
469 typedef struct {
470 const IWICFormatConverterInfoVtbl *lpIWICFormatConverterInfoVtbl;
471 LONG ref;
472 HKEY classkey;
473 CLSID clsid;
474 } FormatConverterInfo;
475
476 static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
477 void **ppv)
478 {
479 FormatConverterInfo *This = (FormatConverterInfo*)iface;
480 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
481
482 if (!ppv) return E_INVALIDARG;
483
484 if (IsEqualIID(&IID_IUnknown, iid) ||
485 IsEqualIID(&IID_IWICComponentInfo, iid) ||
486 IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
487 {
488 *ppv = This;
489 }
490 else
491 {
492 *ppv = NULL;
493 return E_NOINTERFACE;
494 }
495
496 IUnknown_AddRef((IUnknown*)*ppv);
497 return S_OK;
498 }
499
500 static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
501 {
502 FormatConverterInfo *This = (FormatConverterInfo*)iface;
503 ULONG ref = InterlockedIncrement(&This->ref);
504
505 TRACE("(%p) refcount=%u\n", iface, ref);
506
507 return ref;
508 }
509
510 static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
511 {
512 FormatConverterInfo *This = (FormatConverterInfo*)iface;
513 ULONG ref = InterlockedDecrement(&This->ref);
514
515 TRACE("(%p) refcount=%u\n", iface, ref);
516
517 if (ref == 0)
518 {
519 RegCloseKey(This->classkey);
520 HeapFree(GetProcessHeap(), 0, This);
521 }
522
523 return ref;
524 }
525
526 static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
527 WICComponentType *pType)
528 {
529 TRACE("(%p,%p)\n", iface, pType);
530 *pType = WICPixelFormatConverter;
531 return S_OK;
532 }
533
534 static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
535 {
536 FIXME("(%p,%p): stub\n", iface, pclsid);
537 return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
541 {
542 FIXME("(%p,%p): stub\n", iface, pStatus);
543 return E_NOTIMPL;
544 }
545
546 static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
547 WCHAR *wzAuthor, UINT *pcchActual)
548 {
549 FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
550 return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
554 {
555 FIXME("(%p,%p): stub\n", iface, pguidVendor);
556 return E_NOTIMPL;
557 }
558
559 static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
560 WCHAR *wzVersion, UINT *pcchActual)
561 {
562 FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
563 return E_NOTIMPL;
564 }
565
566 static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
567 WCHAR *wzSpecVersion, UINT *pcchActual)
568 {
569 FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
570 return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
574 WCHAR *wzFriendlyName, UINT *pcchActual)
575 {
576 FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
577 return E_NOTIMPL;
578 }
579
580 static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
581 UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
582 {
583 FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
584 return E_NOTIMPL;
585 }
586
587 static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
588 IWICFormatConverter **ppIFormatConverter)
589 {
590 FormatConverterInfo *This = (FormatConverterInfo*)iface;
591
592 TRACE("(%p,%p)\n", iface, ppIFormatConverter);
593
594 return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
595 &IID_IWICFormatConverter, (void**)ppIFormatConverter);
596 }
597
598 static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
599 {
600 LONG res;
601 FormatConverterInfo *This = (FormatConverterInfo*)iface;
602 HKEY formats_key, guid_key;
603
604 /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
605 would be O(n). A registry test should do better. */
606
607 res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
608 if (res != ERROR_SUCCESS) return FALSE;
609
610 res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
611 if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
612
613 RegCloseKey(formats_key);
614
615 return (res == ERROR_SUCCESS);
616 }
617
618 static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
619 FormatConverterInfo_QueryInterface,
620 FormatConverterInfo_AddRef,
621 FormatConverterInfo_Release,
622 FormatConverterInfo_GetComponentType,
623 FormatConverterInfo_GetCLSID,
624 FormatConverterInfo_GetSigningStatus,
625 FormatConverterInfo_GetAuthor,
626 FormatConverterInfo_GetVendorGUID,
627 FormatConverterInfo_GetVersion,
628 FormatConverterInfo_GetSpecVersion,
629 FormatConverterInfo_GetFriendlyName,
630 FormatConverterInfo_GetPixelFormats,
631 FormatConverterInfo_CreateInstance
632 };
633
634 static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
635 {
636 FormatConverterInfo *This;
637
638 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
639 if (!This)
640 {
641 RegCloseKey(classkey);
642 return E_OUTOFMEMORY;
643 }
644
645 This->lpIWICFormatConverterInfoVtbl = &FormatConverterInfo_Vtbl;
646 This->ref = 1;
647 This->classkey = classkey;
648 memcpy(&This->clsid, clsid, sizeof(CLSID));
649
650 *ppIInfo = (IWICComponentInfo*)This;
651 return S_OK;
652 }
653
654 static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0};
655 static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
656
657 struct category {
658 WICComponentType type;
659 const GUID *catid;
660 HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
661 };
662
663 static const struct category categories[] = {
664 {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
665 {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
666 {0}
667 };
668
669 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
670 {
671 HKEY clsidkey;
672 HKEY classkey;
673 HKEY catidkey;
674 HKEY instancekey;
675 WCHAR guidstring[39];
676 LONG res;
677 const struct category *category;
678 int found=0;
679 HRESULT hr;
680
681 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
682 if (res != ERROR_SUCCESS)
683 return HRESULT_FROM_WIN32(res);
684
685 for (category=categories; category->type; category++)
686 {
687 StringFromGUID2(category->catid, guidstring, 39);
688 res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
689 if (res == ERROR_SUCCESS)
690 {
691 res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
692 if (res == ERROR_SUCCESS)
693 {
694 StringFromGUID2(clsid, guidstring, 39);
695 res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
696 if (res == ERROR_SUCCESS)
697 {
698 RegCloseKey(classkey);
699 found = 1;
700 }
701 RegCloseKey(instancekey);
702 }
703 RegCloseKey(catidkey);
704 }
705 if (found) break;
706 }
707
708 if (found)
709 {
710 res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
711 if (res == ERROR_SUCCESS)
712 hr = category->constructor(classkey, clsid, ppIInfo);
713 else
714 hr = HRESULT_FROM_WIN32(res);
715 }
716 else
717 hr = E_FAIL;
718
719 RegCloseKey(clsidkey);
720
721 return hr;
722 }
723
724 typedef struct {
725 const IEnumUnknownVtbl *IEnumUnknown_Vtbl;
726 LONG ref;
727 struct list objects;
728 struct list *cursor;
729 CRITICAL_SECTION lock; /* Must be held when reading or writing cursor */
730 } ComponentEnum;
731
732 typedef struct {
733 struct list entry;
734 IUnknown *unk;
735 } ComponentEnumItem;
736
737 static const IEnumUnknownVtbl ComponentEnumVtbl;
738
739 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
740 void **ppv)
741 {
742 ComponentEnum *This = (ComponentEnum*)iface;
743 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
744
745 if (!ppv) return E_INVALIDARG;
746
747 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
748 {
749 *ppv = This;
750 }
751 else
752 {
753 *ppv = NULL;
754 return E_NOINTERFACE;
755 }
756
757 IUnknown_AddRef((IUnknown*)*ppv);
758 return S_OK;
759 }
760
761 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
762 {
763 ComponentEnum *This = (ComponentEnum*)iface;
764 ULONG ref = InterlockedIncrement(&This->ref);
765
766 TRACE("(%p) refcount=%u\n", iface, ref);
767
768 return ref;
769 }
770
771 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
772 {
773 ComponentEnum *This = (ComponentEnum*)iface;
774 ULONG ref = InterlockedDecrement(&This->ref);
775 ComponentEnumItem *cursor, *cursor2;
776
777 TRACE("(%p) refcount=%u\n", iface, ref);
778
779 if (ref == 0)
780 {
781 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
782 {
783 IUnknown_Release(cursor->unk);
784 list_remove(&cursor->entry);
785 HeapFree(GetProcessHeap(), 0, cursor);
786 }
787 This->lock.DebugInfo->Spare[0] = 0;
788 DeleteCriticalSection(&This->lock);
789 HeapFree(GetProcessHeap(), 0, This);
790 }
791
792 return ref;
793 }
794
795 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
796 IUnknown **rgelt, ULONG *pceltFetched)
797 {
798 ComponentEnum *This = (ComponentEnum*)iface;
799 int num_fetched=0;
800 ComponentEnumItem *item;
801 HRESULT hr=S_OK;
802
803 TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
804
805 EnterCriticalSection(&This->lock);
806 while (num_fetched<celt)
807 {
808 if (!This->cursor)
809 {
810 hr = S_FALSE;
811 break;
812 }
813 item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
814 IUnknown_AddRef(item->unk);
815 rgelt[num_fetched] = item->unk;
816 num_fetched++;
817 This->cursor = list_next(&This->objects, This->cursor);
818 }
819 LeaveCriticalSection(&This->lock);
820 *pceltFetched = num_fetched;
821 return hr;
822 }
823
824 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
825 {
826 ComponentEnum *This = (ComponentEnum*)iface;
827 int i;
828 HRESULT hr=S_OK;
829
830 TRACE("(%p,%u)\n", iface, celt);
831
832 EnterCriticalSection(&This->lock);
833 for (i=0; i<celt; i++)
834 {
835 if (!This->cursor)
836 {
837 hr = S_FALSE;
838 break;
839 }
840 This->cursor = list_next(&This->objects, This->cursor);
841 }
842 LeaveCriticalSection(&This->lock);
843 return hr;
844 }
845
846 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
847 {
848 ComponentEnum *This = (ComponentEnum*)iface;
849
850 TRACE("(%p)\n", iface);
851
852 EnterCriticalSection(&This->lock);
853 This->cursor = list_head(&This->objects);
854 LeaveCriticalSection(&This->lock);
855 return S_OK;
856 }
857
858 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
859 {
860 ComponentEnum *This = (ComponentEnum*)iface;
861 ComponentEnum *new_enum;
862 ComponentEnumItem *old_item, *new_item;
863 HRESULT ret=S_OK;
864 struct list *old_cursor;
865
866 new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
867 if (!new_enum)
868 {
869 *ppenum = NULL;
870 return E_OUTOFMEMORY;
871 }
872
873 new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
874 new_enum->ref = 1;
875 new_enum->cursor = NULL;
876 list_init(&new_enum->objects);
877 InitializeCriticalSection(&new_enum->lock);
878 new_enum->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
879
880 EnterCriticalSection(&This->lock);
881 old_cursor = This->cursor;
882 LeaveCriticalSection(&This->lock);
883
884 LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
885 {
886 new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
887 if (!new_item)
888 {
889 ret = E_OUTOFMEMORY;
890 break;
891 }
892 new_item->unk = old_item->unk;
893 list_add_tail(&new_enum->objects, &new_item->entry);
894 IUnknown_AddRef(new_item->unk);
895 if (&old_item->entry == old_cursor) new_enum->cursor = &new_item->entry;
896 }
897
898 if (FAILED(ret))
899 {
900 IUnknown_Release((IUnknown*)new_enum);
901 *ppenum = NULL;
902 }
903 else
904 *ppenum = (IEnumUnknown*)new_enum;
905
906 return ret;
907 }
908
909 static const IEnumUnknownVtbl ComponentEnumVtbl = {
910 ComponentEnum_QueryInterface,
911 ComponentEnum_AddRef,
912 ComponentEnum_Release,
913 ComponentEnum_Next,
914 ComponentEnum_Skip,
915 ComponentEnum_Reset,
916 ComponentEnum_Clone
917 };
918
919 HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
920 {
921 ComponentEnum *This;
922 ComponentEnumItem *item;
923 const struct category *category;
924 HKEY clsidkey, catidkey, instancekey;
925 WCHAR guidstring[39];
926 LONG res;
927 int i;
928 HRESULT hr=S_OK;
929 CLSID clsid;
930
931 if (options) FIXME("ignoring flags %x\n", options);
932
933 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
934 if (res != ERROR_SUCCESS)
935 return HRESULT_FROM_WIN32(res);
936
937 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
938 if (!This)
939 {
940 RegCloseKey(clsidkey);
941 return E_OUTOFMEMORY;
942 }
943
944 This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
945 This->ref = 1;
946 list_init(&This->objects);
947 InitializeCriticalSection(&This->lock);
948 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ComponentEnum.lock");
949
950 for (category=categories; category->type && hr == S_OK; category++)
951 {
952 if ((category->type & componentTypes) == 0) continue;
953 StringFromGUID2(category->catid, guidstring, 39);
954 res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
955 if (res == ERROR_SUCCESS)
956 {
957 res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
958 if (res == ERROR_SUCCESS)
959 {
960 i=0;
961 for (;;i++)
962 {
963 DWORD guidstring_size = 39;
964 res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
965 if (res != ERROR_SUCCESS) break;
966
967 item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
968 if (!item) { hr = E_OUTOFMEMORY; break; }
969
970 hr = CLSIDFromString(guidstring, &clsid);
971 if (SUCCEEDED(hr))
972 {
973 hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
974 if (SUCCEEDED(hr))
975 list_add_tail(&This->objects, &item->entry);
976 }
977
978 if (FAILED(hr))
979 {
980 HeapFree(GetProcessHeap(), 0, item);
981 hr = S_OK;
982 }
983 }
984 RegCloseKey(instancekey);
985 }
986 RegCloseKey(catidkey);
987 }
988 if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
989 hr = HRESULT_FROM_WIN32(res);
990 }
991 RegCloseKey(clsidkey);
992
993 if (SUCCEEDED(hr))
994 {
995 IEnumUnknown_Reset((IEnumUnknown*)This);
996 *ppIEnumUnknown = (IEnumUnknown*)This;
997 }
998 else
999 {
1000 *ppIEnumUnknown = NULL;
1001 IUnknown_Release((IUnknown*)This);
1002 }
1003
1004 return hr;
1005 }
1006
1007 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
1008 {
1009 HRESULT res;
1010 IEnumUnknown *enumconverters;
1011 IUnknown *unkconverterinfo;
1012 IWICFormatConverterInfo *converterinfo=NULL;
1013 IWICFormatConverter *converter=NULL;
1014 GUID srcFormat;
1015 WCHAR srcformatstr[39], dstformatstr[39];
1016 BOOL canconvert;
1017 ULONG num_fetched;
1018
1019 res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
1020 if (FAILED(res)) return res;
1021
1022 if (IsEqualGUID(&srcFormat, dstFormat))
1023 {
1024 IWICBitmapSource_AddRef(pISrc);
1025 *ppIDst = pISrc;
1026 return S_OK;
1027 }
1028
1029 StringFromGUID2(&srcFormat, srcformatstr, 39);
1030 StringFromGUID2(dstFormat, dstformatstr, 39);
1031
1032 res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
1033 if (FAILED(res)) return res;
1034
1035 while (!converter)
1036 {
1037 res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
1038
1039 if (res == S_OK)
1040 {
1041 res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
1042
1043 if (SUCCEEDED(res))
1044 {
1045 canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
1046
1047 if (canconvert)
1048 canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
1049
1050 if (canconvert)
1051 {
1052 res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
1053
1054 if (SUCCEEDED(res))
1055 res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
1056
1057 if (SUCCEEDED(res) && canconvert)
1058 res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
1059 NULL, 0.0, WICBitmapPaletteTypeCustom);
1060
1061 if (FAILED(res) || !canconvert)
1062 {
1063 if (converter)
1064 {
1065 IWICFormatConverter_Release(converter);
1066 converter = NULL;
1067 }
1068 res = S_OK;
1069 }
1070 }
1071
1072 IWICFormatConverterInfo_Release(converterinfo);
1073 }
1074
1075 IUnknown_Release(unkconverterinfo);
1076 }
1077 else
1078 break;
1079 }
1080
1081 IEnumUnknown_Release(enumconverters);
1082
1083 if (converter)
1084 {
1085 *ppIDst = (IWICBitmapSource*)converter;
1086 return S_OK;
1087 }
1088 else
1089 {
1090 FIXME("cannot convert %s to %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1091 *ppIDst = NULL;
1092 return WINCODEC_ERR_COMPONENTNOTFOUND;
1093 }
1094 }