iphlpapi: Fix inverted logic in mask comparison.
[wine] / dlls / windowscodecs / icoformat.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 "wingdi.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30
31 #include "wincodecs_private.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36
37 #include "pshpack1.h"
38
39 typedef struct {
40     BYTE bWidth;
41     BYTE bHeight;
42     BYTE bColorCount;
43     BYTE bReserved;
44     WORD wPlanes;
45     WORD wBitCount;
46     DWORD dwDIBSize;
47     DWORD dwDIBOffset;
48 } ICONDIRENTRY;
49
50 typedef struct
51 {
52     WORD idReserved;
53     WORD idType;
54     WORD idCount;
55 } ICONHEADER;
56
57 #include "poppack.h"
58
59 typedef struct {
60     const IWICBitmapDecoderVtbl *lpVtbl;
61     LONG ref;
62     BOOL initialized;
63     IStream *stream;
64     ICONHEADER header;
65     CRITICAL_SECTION lock; /* must be held when accessing stream */
66 } IcoDecoder;
67
68 typedef struct {
69     const IWICBitmapFrameDecodeVtbl *lpVtbl;
70     LONG ref;
71     UINT width, height;
72     BYTE *bits;
73 } IcoFrameDecode;
74
75 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
76     void **ppv)
77 {
78     IcoFrameDecode *This = (IcoFrameDecode*)iface;
79     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
80
81     if (!ppv) return E_INVALIDARG;
82
83     if (IsEqualIID(&IID_IUnknown, iid) ||
84         IsEqualIID(&IID_IWICBitmapSource, iid) ||
85         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
86     {
87         *ppv = This;
88     }
89     else
90     {
91         *ppv = NULL;
92         return E_NOINTERFACE;
93     }
94
95     IUnknown_AddRef((IUnknown*)*ppv);
96     return S_OK;
97 }
98
99 static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
100 {
101     IcoFrameDecode *This = (IcoFrameDecode*)iface;
102     ULONG ref = InterlockedIncrement(&This->ref);
103
104     TRACE("(%p) refcount=%u\n", iface, ref);
105
106     return ref;
107 }
108
109 static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
110 {
111     IcoFrameDecode *This = (IcoFrameDecode*)iface;
112     ULONG ref = InterlockedDecrement(&This->ref);
113
114     TRACE("(%p) refcount=%u\n", iface, ref);
115
116     if (ref == 0)
117     {
118         HeapFree(GetProcessHeap(), 0, This->bits);
119         HeapFree(GetProcessHeap(), 0, This);
120     }
121
122     return ref;
123 }
124
125 static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
126     UINT *puiWidth, UINT *puiHeight)
127 {
128     IcoFrameDecode *This = (IcoFrameDecode*)iface;
129
130     *puiWidth = This->width;
131     *puiHeight = This->height;
132
133     TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
134
135     return S_OK;
136 }
137
138 static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
139     WICPixelFormatGUID *pPixelFormat)
140 {
141     memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
142     return S_OK;
143 }
144
145 static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
146     double *pDpiX, double *pDpiY)
147 {
148     FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
149     return E_NOTIMPL;
150 }
151
152 static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
153     IWICPalette *pIPalette)
154 {
155     TRACE("(%p,%p)\n", iface, pIPalette);
156     return WINCODEC_ERR_PALETTEUNAVAILABLE;
157 }
158
159 static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
160     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
161 {
162     IcoFrameDecode *This = (IcoFrameDecode*)iface;
163     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
164
165     return copy_pixels(32, This->bits, This->width, This->height, This->width * 4,
166         prc, cbStride, cbBufferSize, pbBuffer);
167 }
168
169 static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
170     IWICMetadataQueryReader **ppIMetadataQueryReader)
171 {
172     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
173     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
174 }
175
176 static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
177     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
178 {
179     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
180     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
181 }
182
183 static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
184     IWICBitmapSource **ppIThumbnail)
185 {
186     TRACE("(%p,%p)\n", iface, ppIThumbnail);
187     return WINCODEC_ERR_CODECNOTHUMBNAIL;
188 }
189
190 static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
191     IcoFrameDecode_QueryInterface,
192     IcoFrameDecode_AddRef,
193     IcoFrameDecode_Release,
194     IcoFrameDecode_GetSize,
195     IcoFrameDecode_GetPixelFormat,
196     IcoFrameDecode_GetResolution,
197     IcoFrameDecode_CopyPalette,
198     IcoFrameDecode_CopyPixels,
199     IcoFrameDecode_GetMetadataQueryReader,
200     IcoFrameDecode_GetColorContexts,
201     IcoFrameDecode_GetThumbnail
202 };
203
204 static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
205 {
206     if (transparent) *pixel = 0;
207     else *pixel |= 0xff000000;
208 }
209
210 static HRESULT ReadIcoDib(IStream *stream, IcoFrameDecode *result)
211 {
212     HRESULT hr;
213     IWICBitmapDecoder *decoder;
214     IWICBitmapFrameDecode *framedecode;
215     WICPixelFormatGUID pixelformat;
216     IWICBitmapSource *source;
217     int has_alpha=FALSE; /* if TRUE, alpha data might be in the image data */
218     WICRect rc;
219
220     hr = IcoDibDecoder_CreateInstance(NULL, &IID_IWICBitmapDecoder, (void**)&decoder);
221     if (SUCCEEDED(hr))
222     {
223         hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
224
225         if (SUCCEEDED(hr))
226             hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
227
228         if (SUCCEEDED(hr))
229         {
230             hr = IWICBitmapFrameDecode_GetSize(framedecode, &result->width, &result->height);
231
232             if (SUCCEEDED(hr))
233             {
234                 result->bits = HeapAlloc(GetProcessHeap(), 0, result->width * result->height * 4);
235                 if (!result->bits) hr = E_OUTOFMEMORY;
236             }
237
238             if (SUCCEEDED(hr))
239                 hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &pixelformat);
240
241             if (IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGR) ||
242                 IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGRA))
243             {
244                 source = (IWICBitmapSource*)framedecode;
245                 IWICBitmapSource_AddRef(source);
246                 has_alpha = TRUE;
247             }
248             else
249             {
250                 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA,
251                     (IWICBitmapSource*)framedecode, &source);
252                 has_alpha = FALSE;
253             }
254
255             if (SUCCEEDED(hr))
256             {
257                 rc.X = 0;
258                 rc.Y = 0;
259                 rc.Width = result->width;
260                 rc.Height = result->height;
261                 hr = IWICBitmapSource_CopyPixels(source, &rc, result->width * 4,
262                     result->width * result->height * 4, result->bits);
263
264                 IWICBitmapSource_Release(source);
265             }
266
267             IWICBitmapFrameDecode_Release(framedecode);
268         }
269
270         if (SUCCEEDED(hr) && !has_alpha)
271         {
272             /* set alpha data based on the AND mask */
273             UINT andBytesPerRow = (result->width+31)/32*4;
274             UINT andBytes = andBytesPerRow * result->height;
275             INT andStride;
276             BYTE *tempdata=NULL;
277             BYTE *andRow;
278             BYTE *bitsRow;
279             UINT bitsStride = result->width * 4;
280             UINT x, y;
281             ULONG offset;
282             ULONG bytesread;
283             LARGE_INTEGER seek;
284             int topdown;
285
286             BmpDecoder_FindIconMask(decoder, &offset, &topdown);
287
288             if (offset)
289             {
290                 seek.QuadPart = offset;
291
292                 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, 0);
293
294                 if (SUCCEEDED(hr))
295                 {
296                     tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
297                     if (!tempdata) hr = E_OUTOFMEMORY;
298                 }
299
300                 if (SUCCEEDED(hr))
301                     hr = IStream_Read(stream, tempdata, andBytes, &bytesread);
302
303                 if (SUCCEEDED(hr) && bytesread == andBytes)
304                 {
305                     if (topdown)
306                     {
307                         andStride = andBytesPerRow;
308                         andRow = tempdata;
309                     }
310                     else
311                     {
312                         andStride = -andBytesPerRow;
313                         andRow = tempdata + (result->height-1)*andBytesPerRow;
314                     }
315
316                     bitsRow = result->bits;
317                     for (y=0; y<result->height; y++) {
318                         BYTE *andByte=andRow;
319                         DWORD *bitsPixel=(DWORD*)bitsRow;
320                         for (x=0; x<result->width; x+=8) {
321                             BYTE andVal=*andByte++;
322                             pixel_set_trans(bitsPixel++, andVal>>7&1);
323                             if (x+1 < result->width) pixel_set_trans(bitsPixel++, andVal>>6&1);
324                             if (x+2 < result->width) pixel_set_trans(bitsPixel++, andVal>>5&1);
325                             if (x+3 < result->width) pixel_set_trans(bitsPixel++, andVal>>4&1);
326                             if (x+4 < result->width) pixel_set_trans(bitsPixel++, andVal>>3&1);
327                             if (x+5 < result->width) pixel_set_trans(bitsPixel++, andVal>>2&1);
328                             if (x+6 < result->width) pixel_set_trans(bitsPixel++, andVal>>1&1);
329                             if (x+7 < result->width) pixel_set_trans(bitsPixel++, andVal&1);
330                         }
331                         andRow += andStride;
332                         bitsRow += bitsStride;
333                     }
334                 }
335
336                 HeapFree(GetProcessHeap(), 0, tempdata);
337             }
338         }
339
340         IWICBitmapDecoder_Release(decoder);
341     }
342
343     return hr;
344 }
345
346 static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
347     void **ppv)
348 {
349     IcoDecoder *This = (IcoDecoder*)iface;
350     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
351
352     if (!ppv) return E_INVALIDARG;
353
354     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
355     {
356         *ppv = This;
357     }
358     else
359     {
360         *ppv = NULL;
361         return E_NOINTERFACE;
362     }
363
364     IUnknown_AddRef((IUnknown*)*ppv);
365     return S_OK;
366 }
367
368 static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
369 {
370     IcoDecoder *This = (IcoDecoder*)iface;
371     ULONG ref = InterlockedIncrement(&This->ref);
372
373     TRACE("(%p) refcount=%u\n", iface, ref);
374
375     return ref;
376 }
377
378 static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
379 {
380     IcoDecoder *This = (IcoDecoder*)iface;
381     ULONG ref = InterlockedDecrement(&This->ref);
382
383     TRACE("(%p) refcount=%u\n", iface, ref);
384
385     if (ref == 0)
386     {
387         This->lock.DebugInfo->Spare[0] = 0;
388         DeleteCriticalSection(&This->lock);
389         if (This->stream) IStream_Release(This->stream);
390         HeapFree(GetProcessHeap(), 0, This);
391     }
392
393     return ref;
394 }
395
396 static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
397     DWORD *pdwCapability)
398 {
399     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
400     return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
404     WICDecodeOptions cacheOptions)
405 {
406     IcoDecoder *This = (IcoDecoder*)iface;
407     LARGE_INTEGER seek;
408     HRESULT hr;
409     ULONG bytesread;
410     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
411
412     EnterCriticalSection(&This->lock);
413
414     if (This->initialized)
415     {
416         hr = WINCODEC_ERR_WRONGSTATE;
417         goto end;
418     }
419
420     seek.QuadPart = 0;
421     hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
422     if (FAILED(hr)) goto end;
423
424     hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread);
425     if (FAILED(hr)) goto end;
426     if (bytesread != sizeof(ICONHEADER) ||
427         This->header.idReserved != 0 ||
428         This->header.idType != 1)
429     {
430         hr = E_FAIL;
431         goto end;
432     }
433
434     This->initialized = TRUE;
435     This->stream = pIStream;
436     IStream_AddRef(pIStream);
437
438 end:
439
440     LeaveCriticalSection(&This->lock);
441
442     return hr;
443 }
444
445 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
446     GUID *pguidContainerFormat)
447 {
448     FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
449     return E_NOTIMPL;
450 }
451
452 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
453     IWICBitmapDecoderInfo **ppIDecoderInfo)
454 {
455     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
456     return E_NOTIMPL;
457 }
458
459 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
460     IWICPalette *pIPalette)
461 {
462     TRACE("(%p,%p)\n", iface, pIPalette);
463     return WINCODEC_ERR_PALETTEUNAVAILABLE;
464 }
465
466 static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
467     IWICMetadataQueryReader **ppIMetadataQueryReader)
468 {
469     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
470     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
471 }
472
473 static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface,
474     IWICBitmapSource **ppIBitmapSource)
475 {
476     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
477     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
478 }
479
480 static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface,
481     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
482 {
483     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
484     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
485 }
486
487 static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface,
488     IWICBitmapSource **ppIThumbnail)
489 {
490     TRACE("(%p,%p)\n", iface, ppIThumbnail);
491     return WINCODEC_ERR_CODECNOTHUMBNAIL;
492 }
493
494 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
495     UINT *pCount)
496 {
497     IcoDecoder *This = (IcoDecoder*)iface;
498     TRACE("(%p,%p)\n", iface, pCount);
499
500     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
501
502     *pCount = This->header.idCount;
503     TRACE("<-- %u\n", *pCount);
504
505     return S_OK;
506 }
507
508 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
509     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
510 {
511     IcoDecoder *This = (IcoDecoder*)iface;
512     IcoFrameDecode *result=NULL;
513     LARGE_INTEGER seek;
514     ULARGE_INTEGER offset, length;
515     HRESULT hr;
516     ULONG bytesread;
517     ICONDIRENTRY entry;
518     IWICStream *substream=NULL;
519     DWORD magic;
520     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
521
522     EnterCriticalSection(&This->lock);
523
524     if (!This->initialized)
525     {
526         hr = WINCODEC_ERR_NOTINITIALIZED;
527         goto fail;
528     }
529
530     if (This->header.idCount < index)
531     {
532         hr = E_INVALIDARG;
533         goto fail;
534     }
535
536     result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode));
537     if (!result)
538     {
539         hr = E_OUTOFMEMORY;
540         goto fail;
541     }
542
543     result->lpVtbl = &IcoFrameDecode_Vtbl;
544     result->ref = 1;
545     result->bits = NULL;
546
547     /* read the icon entry */
548     seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index;
549     hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
550     if (FAILED(hr)) goto fail;
551
552     hr = IStream_Read(This->stream, &entry, sizeof(ICONDIRENTRY), &bytesread);
553     if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail;
554
555     /* create a stream object for this icon */
556     hr = StreamImpl_Create(&substream);
557     if (FAILED(hr)) goto fail;
558
559     offset.QuadPart = entry.dwDIBOffset;
560     length.QuadPart = entry.dwDIBSize;
561     hr = IWICStream_InitializeFromIStreamRegion(substream, This->stream, offset, length);
562     if (FAILED(hr)) goto fail;
563
564     /* read the bitmapinfo size or magic number */
565     hr = IWICStream_Read(substream, &magic, sizeof(magic), &bytesread);
566     if (FAILED(hr) || bytesread != sizeof(magic)) goto fail;
567
568     /* forward to the appropriate decoding function based on the magic number */
569     switch (magic)
570     {
571     case sizeof(BITMAPCOREHEADER):
572     case 64: /* sizeof(BITMAPCOREHEADER2) */
573     case sizeof(BITMAPINFOHEADER):
574     case sizeof(BITMAPV4HEADER):
575     case sizeof(BITMAPV5HEADER):
576         hr = ReadIcoDib((IStream*)substream, result);
577         break;
578     case 0x474e5089:
579         FIXME("PNG decoding not supported\n");
580         hr = E_FAIL;
581         break;
582     default:
583         FIXME("Unrecognized ICO frame magic: %x\n", magic);
584         hr = E_FAIL;
585         break;
586     }
587     if (FAILED(hr)) goto fail;
588
589     *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
590
591     LeaveCriticalSection(&This->lock);
592
593     return S_OK;
594
595 fail:
596     LeaveCriticalSection(&This->lock);
597     HeapFree(GetProcessHeap(), 0, result);
598     if (substream) IStream_Release(substream);
599     if (SUCCEEDED(hr)) hr = E_FAIL;
600     TRACE("<-- %x\n", hr);
601     return hr;
602 }
603
604 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = {
605     IcoDecoder_QueryInterface,
606     IcoDecoder_AddRef,
607     IcoDecoder_Release,
608     IcoDecoder_QueryCapability,
609     IcoDecoder_Initialize,
610     IcoDecoder_GetContainerFormat,
611     IcoDecoder_GetDecoderInfo,
612     IcoDecoder_CopyPalette,
613     IcoDecoder_GetMetadataQueryReader,
614     IcoDecoder_GetPreview,
615     IcoDecoder_GetColorContexts,
616     IcoDecoder_GetThumbnail,
617     IcoDecoder_GetFrameCount,
618     IcoDecoder_GetFrame
619 };
620
621 HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
622 {
623     IcoDecoder *This;
624     HRESULT ret;
625
626     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
627
628     *ppv = NULL;
629
630     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
631
632     This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder));
633     if (!This) return E_OUTOFMEMORY;
634
635     This->lpVtbl = &IcoDecoder_Vtbl;
636     This->ref = 1;
637     This->stream = NULL;
638     This->initialized = FALSE;
639     InitializeCriticalSection(&This->lock);
640     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock");
641
642     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
643     IUnknown_Release((IUnknown*)This);
644
645     return ret;
646 }