msxml3: Accept S_FALSE as a valid callback result when msxml6 is used.
[wine] / dlls / windowscodecs / icnsformat.c
1 /*
2  * Copyright 2010 Damjan Jovanovic
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 #include "wine/port.h"
21
22 #include <stdarg.h>
23
24 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
25 #define GetCurrentProcess GetCurrentProcess_Mac
26 #define GetCurrentThread GetCurrentThread_Mac
27 #define LoadResource LoadResource_Mac
28 #define EqualRect EqualRect_Mac
29 #define FillRect FillRect_Mac
30 #define FrameRect FrameRect_Mac
31 #define GetCursor GetCursor_Mac
32 #define InvertRect InvertRect_Mac
33 #define OffsetRect OffsetRect_Mac
34 #define PtInRect PtInRect_Mac
35 #define SetCursor SetCursor_Mac
36 #define SetRect SetRect_Mac
37 #define ShowCursor ShowCursor_Mac
38 #define UnionRect UnionRect_Mac
39 #include <ApplicationServices/ApplicationServices.h>
40 #undef GetCurrentProcess
41 #undef GetCurrentThread
42 #undef LoadResource
43 #undef EqualRect
44 #undef FillRect
45 #undef FrameRect
46 #undef GetCursor
47 #undef InvertRect
48 #undef OffsetRect
49 #undef PtInRect
50 #undef SetCursor
51 #undef SetRect
52 #undef ShowCursor
53 #undef UnionRect
54 #undef DPRINTF
55 #endif
56
57 #define COBJMACROS
58
59 #include "windef.h"
60 #include "winbase.h"
61 #include "objbase.h"
62 #include "wincodec.h"
63
64 #include "wincodecs_private.h"
65
66 #include "wine/debug.h"
67 #include "wine/library.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
70
71 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
72     MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
73
74 typedef struct IcnsEncoder {
75     IWICBitmapEncoder IWICBitmapEncoder_iface;
76     LONG ref;
77     IStream *stream;
78     IconFamilyHandle icns_family;
79     BOOL any_frame_committed;
80     int outstanding_commits;
81     BOOL committed;
82     CRITICAL_SECTION lock;
83 } IcnsEncoder;
84
85 static inline IcnsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
86 {
87     return CONTAINING_RECORD(iface, IcnsEncoder, IWICBitmapEncoder_iface);
88 }
89
90 typedef struct IcnsFrameEncode {
91     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
92     IcnsEncoder *encoder;
93     LONG ref;
94     BOOL initialized;
95     UINT size;
96     OSType icns_type;
97     BYTE* icns_image;
98     int lines_written;
99     BOOL committed;
100 } IcnsFrameEncode;
101
102 static inline IcnsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
103 {
104     return CONTAINING_RECORD(iface, IcnsFrameEncode, IWICBitmapFrameEncode_iface);
105 }
106
107 static HRESULT WINAPI IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
108     void **ppv)
109 {
110     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
111     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
112
113     if (!ppv) return E_INVALIDARG;
114
115     if (IsEqualIID(&IID_IUnknown, iid) ||
116         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
117     {
118         *ppv = &This->IWICBitmapFrameEncode_iface;
119     }
120     else
121     {
122         *ppv = NULL;
123         return E_NOINTERFACE;
124     }
125
126     IUnknown_AddRef((IUnknown*)*ppv);
127     return S_OK;
128 }
129
130 static ULONG WINAPI IcnsFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
131 {
132     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
133     ULONG ref = InterlockedIncrement(&This->ref);
134
135     TRACE("(%p) refcount=%u\n", iface, ref);
136
137     return ref;
138 }
139
140 static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface)
141 {
142     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
143     ULONG ref = InterlockedDecrement(&This->ref);
144
145     TRACE("(%p) refcount=%u\n", iface, ref);
146
147     if (ref == 0)
148     {
149         if (!This->committed)
150         {
151             EnterCriticalSection(&This->encoder->lock);
152             This->encoder->outstanding_commits--;
153             LeaveCriticalSection(&This->encoder->lock);
154         }
155         if (This->icns_image != NULL)
156             HeapFree(GetProcessHeap(), 0, This->icns_image);
157
158         IUnknown_Release((IUnknown*)This->encoder);
159         HeapFree(GetProcessHeap(), 0, This);
160     }
161
162     return ref;
163 }
164
165 static HRESULT WINAPI IcnsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
166     IPropertyBag2 *pIEncoderOptions)
167 {
168     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
169     HRESULT hr = S_OK;
170
171     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
172
173     EnterCriticalSection(&This->encoder->lock);
174
175     if (This->initialized)
176     {
177         hr = WINCODEC_ERR_WRONGSTATE;
178         goto end;
179     }
180     This->initialized = TRUE;
181
182 end:
183     LeaveCriticalSection(&This->encoder->lock);
184     return hr;
185 }
186
187 static HRESULT WINAPI IcnsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
188     UINT uiWidth, UINT uiHeight)
189 {
190     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
191     HRESULT hr = S_OK;
192
193     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
194
195     EnterCriticalSection(&This->encoder->lock);
196
197     if (!This->initialized || This->icns_image)
198     {
199         hr = WINCODEC_ERR_WRONGSTATE;
200         goto end;
201     }
202
203     if (uiWidth != uiHeight)
204     {
205         WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
206         hr = E_INVALIDARG;
207         goto end;
208     }
209
210     switch (uiWidth)
211     {
212         case 16:
213         case 32:
214         case 48:
215         case 128:
216         case 256:
217         case 512:
218             break;
219         default:
220             WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
221             hr = E_INVALIDARG;
222             goto end;
223     }
224
225     This->size = uiWidth;
226
227 end:
228     LeaveCriticalSection(&This->encoder->lock);
229     return hr;
230 }
231
232 static HRESULT WINAPI IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
233     double dpiX, double dpiY)
234 {
235     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
236     HRESULT hr = S_OK;
237
238     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
239
240     EnterCriticalSection(&This->encoder->lock);
241
242     if (!This->initialized || This->icns_image)
243     {
244         hr = WINCODEC_ERR_WRONGSTATE;
245         goto end;
246     }
247
248 end:
249     LeaveCriticalSection(&This->encoder->lock);
250     return S_OK;
251 }
252
253 static HRESULT WINAPI IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
254     WICPixelFormatGUID *pPixelFormat)
255 {
256     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
257     HRESULT hr = S_OK;
258
259     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
260
261     EnterCriticalSection(&This->encoder->lock);
262
263     if (!This->initialized || This->icns_image)
264     {
265         hr = WINCODEC_ERR_WRONGSTATE;
266         goto end;
267     }
268
269     memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
270
271 end:
272     LeaveCriticalSection(&This->encoder->lock);
273     return S_OK;
274 }
275
276 static HRESULT WINAPI IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
277     UINT cCount, IWICColorContext **ppIColorContext)
278 {
279     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
280     return E_NOTIMPL;
281 }
282
283 static HRESULT WINAPI IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
284     IWICPalette *pIPalette)
285 {
286     FIXME("(%p,%p): stub\n", iface, pIPalette);
287     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
288 }
289
290 static HRESULT WINAPI IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
291     IWICBitmapSource *pIThumbnail)
292 {
293     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
294     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
295 }
296
297 static HRESULT WINAPI IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
298     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
299 {
300     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
301     HRESULT hr = S_OK;
302     UINT i;
303
304     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
305
306     EnterCriticalSection(&This->encoder->lock);
307
308     if (!This->initialized || !This->size)
309     {
310         hr = WINCODEC_ERR_WRONGSTATE;
311         goto end;
312     }
313     if (lineCount == 0 || lineCount + This->lines_written > This->size)
314     {
315         hr = E_INVALIDARG;
316         goto end;
317     }
318
319     if (!This->icns_image)
320     {
321         switch (This->size)
322         {
323             case 16:  This->icns_type = kIconServices16PixelDataARGB;  break;
324             case 32:  This->icns_type = kIconServices32PixelDataARGB;  break;
325             case 48:  This->icns_type = kIconServices48PixelDataARGB;  break;
326             case 128: This->icns_type = kIconServices128PixelDataARGB; break;
327             case 256: This->icns_type = kIconServices256PixelDataARGB; break;
328             case 512: This->icns_type = kIconServices512PixelDataARGB; break;
329             default:
330                 WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
331                 hr = E_INVALIDARG;
332                 goto end;
333         }
334         This->icns_image = HeapAlloc(GetProcessHeap(), 0, This->size * This->size * 4);
335         if (!This->icns_image)
336         {
337             WARN("failed to allocate image buffer\n");
338             hr = E_FAIL;
339             goto end;
340         }
341     }
342
343     for (i = 0; i < lineCount; i++)
344     {
345         BYTE *src_row, *dst_row;
346         UINT j;
347         src_row = pbPixels + cbStride * i;
348         dst_row = This->icns_image + (This->lines_written + i)*(This->size*4);
349         /* swap bgr -> rgb */
350         for (j = 0; j < This->size*4; j += 4)
351         {
352             dst_row[j] = src_row[j+3];
353             dst_row[j+1] = src_row[j+2];
354             dst_row[j+2] = src_row[j+1];
355             dst_row[j+3] = src_row[j];
356         }
357     }
358     This->lines_written += lineCount;
359
360 end:
361     LeaveCriticalSection(&This->encoder->lock);
362     return hr;
363 }
364
365 static HRESULT WINAPI IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
366     IWICBitmapSource *pIBitmapSource, WICRect *prc)
367 {
368     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
369     HRESULT hr;
370     WICRect rc;
371     WICPixelFormatGUID guid;
372     UINT stride;
373     BYTE *pixeldata = NULL;
374
375     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
376
377     if (!This->initialized || !This->size)
378     {
379         hr = WINCODEC_ERR_WRONGSTATE;
380         goto end;
381     }
382
383     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
384     if (FAILED(hr))
385         goto end;
386     if (!IsEqualGUID(&guid, &GUID_WICPixelFormat32bppBGRA))
387     {
388         FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid));
389         hr = E_FAIL;
390         goto end;
391     }
392
393     if (!prc)
394     {
395         UINT width, height;
396         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
397         if (FAILED(hr))
398             goto end;
399         rc.X = 0;
400         rc.Y = 0;
401         rc.Width = width;
402         rc.Height = height;
403         prc = &rc;
404     }
405
406     if (prc->Width != This->size)
407     {
408         hr = E_INVALIDARG;
409         goto end;
410     }
411
412     stride = (32 * This->size + 7)/8;
413     pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
414     if (!pixeldata)
415     {
416         hr = E_OUTOFMEMORY;
417         goto end;
418     }
419
420     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
421         stride*prc->Height, pixeldata);
422     if (SUCCEEDED(hr))
423     {
424         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
425             stride*prc->Height, pixeldata);
426     }
427
428 end:
429     HeapFree(GetProcessHeap(), 0, pixeldata);
430     return hr;
431 }
432
433 static HRESULT WINAPI IcnsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
434 {
435     IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
436     Handle handle;
437     OSErr ret;
438     HRESULT hr = S_OK;
439
440     TRACE("(%p): stub\n", iface);
441
442     EnterCriticalSection(&This->encoder->lock);
443
444     if (!This->icns_image || This->lines_written != This->size || This->committed)
445     {
446         hr = WINCODEC_ERR_WRONGSTATE;
447         goto end;
448     }
449
450     ret = PtrToHand(This->icns_image, &handle, This->size * This->size * 4);
451     if (ret != noErr || !handle)
452     {
453         WARN("PtrToHand failed with error %d\n", ret);
454         hr = E_FAIL;
455         goto end;
456     }
457
458     ret = SetIconFamilyData(This->encoder->icns_family, This->icns_type, handle);
459     DisposeHandle(handle);
460
461     if (ret != noErr)
462         {
463         WARN("SetIconFamilyData failed for image with error %d\n", ret);
464         hr = E_FAIL;
465         goto end;
466         }
467
468     This->committed = TRUE;
469     This->encoder->any_frame_committed = TRUE;
470     This->encoder->outstanding_commits--;
471
472 end:
473     LeaveCriticalSection(&This->encoder->lock);
474     return hr;
475 }
476
477 static HRESULT WINAPI IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
478     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
479 {
480     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
481     return E_NOTIMPL;
482 }
483
484 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl = {
485     IcnsFrameEncode_QueryInterface,
486     IcnsFrameEncode_AddRef,
487     IcnsFrameEncode_Release,
488     IcnsFrameEncode_Initialize,
489     IcnsFrameEncode_SetSize,
490     IcnsFrameEncode_SetResolution,
491     IcnsFrameEncode_SetPixelFormat,
492     IcnsFrameEncode_SetColorContexts,
493     IcnsFrameEncode_SetPalette,
494     IcnsFrameEncode_SetThumbnail,
495     IcnsFrameEncode_WritePixels,
496     IcnsFrameEncode_WriteSource,
497     IcnsFrameEncode_Commit,
498     IcnsFrameEncode_GetMetadataQueryWriter
499 };
500
501 static HRESULT WINAPI IcnsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
502     void **ppv)
503 {
504     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
505     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
506
507     if (!ppv) return E_INVALIDARG;
508
509     if (IsEqualIID(&IID_IUnknown, iid) ||
510         IsEqualIID(&IID_IWICBitmapEncoder, iid))
511     {
512         *ppv = This;
513     }
514     else
515     {
516         *ppv = NULL;
517         return E_NOINTERFACE;
518     }
519
520     IUnknown_AddRef((IUnknown*)*ppv);
521     return S_OK;
522 }
523
524 static ULONG WINAPI IcnsEncoder_AddRef(IWICBitmapEncoder *iface)
525 {
526     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
527     ULONG ref = InterlockedIncrement(&This->ref);
528
529     TRACE("(%p) refcount=%u\n", iface, ref);
530
531     return ref;
532 }
533
534 static ULONG WINAPI IcnsEncoder_Release(IWICBitmapEncoder *iface)
535 {
536     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
537     ULONG ref = InterlockedDecrement(&This->ref);
538
539     TRACE("(%p) refcount=%u\n", iface, ref);
540
541     if (ref == 0)
542     {
543         This->lock.DebugInfo->Spare[0] = 0;
544         DeleteCriticalSection(&This->lock);
545         if (This->icns_family)
546             DisposeHandle((Handle)This->icns_family);
547         if (This->stream)
548             IStream_Release(This->stream);
549         HeapFree(GetProcessHeap(), 0, This);
550     }
551
552     return ref;
553 }
554
555 static HRESULT WINAPI IcnsEncoder_Initialize(IWICBitmapEncoder *iface,
556     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
557 {
558     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
559     HRESULT hr = S_OK;
560
561     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
562
563     EnterCriticalSection(&This->lock);
564
565     if (This->icns_family)
566     {
567         hr = WINCODEC_ERR_WRONGSTATE;
568         goto end;
569     }
570     This->icns_family = (IconFamilyHandle)NewHandle(0);
571     if (!This->icns_family)
572     {
573         WARN("error creating icns family\n");
574         hr = E_FAIL;
575         goto end;
576     }
577     IStream_AddRef(pIStream);
578     This->stream = pIStream;
579
580 end:
581     LeaveCriticalSection(&This->lock);
582
583     return hr;
584 }
585
586 static HRESULT WINAPI IcnsEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
587     GUID *pguidContainerFormat)
588 {
589     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
590     return E_NOTIMPL;
591 }
592
593 static HRESULT WINAPI IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
594     IWICBitmapEncoderInfo **ppIEncoderInfo)
595 {
596     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
597     return E_NOTIMPL;
598 }
599
600 static HRESULT WINAPI IcnsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
601     UINT cCount, IWICColorContext **ppIColorContext)
602 {
603     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
604     return E_NOTIMPL;
605 }
606
607 static HRESULT WINAPI IcnsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
608 {
609     TRACE("(%p,%p)\n", iface, pIPalette);
610     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
611 }
612
613 static HRESULT WINAPI IcnsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
614 {
615     TRACE("(%p,%p)\n", iface, pIThumbnail);
616     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
617 }
618
619 static HRESULT WINAPI IcnsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
620 {
621     TRACE("(%p,%p)\n", iface, pIPreview);
622     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
623 }
624
625 static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
626     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
627 {
628     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
629     HRESULT hr = S_OK;
630     IcnsFrameEncode *frameEncode = NULL;
631
632     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
633
634     EnterCriticalSection(&This->lock);
635
636     if (!This->icns_family)
637     {
638         hr = WINCODEC_ERR_NOTINITIALIZED;
639         goto end;
640     }
641
642     hr = CreatePropertyBag2(ppIEncoderOptions);
643     if (FAILED(hr))
644         goto end;
645
646     frameEncode = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode));
647     if (frameEncode == NULL)
648     {
649         hr = E_OUTOFMEMORY;
650         goto end;
651     }
652     frameEncode->IWICBitmapFrameEncode_iface.lpVtbl = &IcnsEncoder_FrameVtbl;
653     frameEncode->encoder = This;
654     frameEncode->ref = 1;
655     frameEncode->initialized = FALSE;
656     frameEncode->size = 0;
657     frameEncode->icns_image = NULL;
658     frameEncode->lines_written = 0;
659     frameEncode->committed = FALSE;
660     *ppIFrameEncode = &frameEncode->IWICBitmapFrameEncode_iface;
661     This->outstanding_commits++;
662     IUnknown_AddRef((IUnknown*)This);
663
664 end:
665     LeaveCriticalSection(&This->lock);
666
667     return hr;
668 }
669
670 static HRESULT WINAPI IcnsEncoder_Commit(IWICBitmapEncoder *iface)
671 {
672     IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
673     size_t buffer_size;
674     HRESULT hr = S_OK;
675     ULONG byteswritten;
676
677     TRACE("(%p)\n", iface);
678
679     EnterCriticalSection(&This->lock);
680
681     if (!This->any_frame_committed || This->outstanding_commits > 0 || This->committed)
682     {
683         hr = WINCODEC_ERR_WRONGSTATE;
684         goto end;
685     }
686
687     buffer_size = GetHandleSize((Handle)This->icns_family);
688     hr = IStream_Write(This->stream, *This->icns_family, buffer_size, &byteswritten);
689     if (FAILED(hr) || byteswritten != buffer_size)
690     {
691         WARN("writing file failed, hr = 0x%08X\n", hr);
692         hr = E_FAIL;
693         goto end;
694     }
695
696     This->committed = TRUE;
697
698 end:
699     LeaveCriticalSection(&This->lock);
700     return hr;
701 }
702
703 static HRESULT WINAPI IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
704     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
705 {
706     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
707     return E_NOTIMPL;
708 }
709
710 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl = {
711     IcnsEncoder_QueryInterface,
712     IcnsEncoder_AddRef,
713     IcnsEncoder_Release,
714     IcnsEncoder_Initialize,
715     IcnsEncoder_GetContainerFormat,
716     IcnsEncoder_GetEncoderInfo,
717     IcnsEncoder_SetColorContexts,
718     IcnsEncoder_SetPalette,
719     IcnsEncoder_SetThumbnail,
720     IcnsEncoder_SetPreview,
721     IcnsEncoder_CreateNewFrame,
722     IcnsEncoder_Commit,
723     IcnsEncoder_GetMetadataQueryWriter
724 };
725
726 HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
727 {
728     IcnsEncoder *This;
729     HRESULT ret;
730
731     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
732
733     *ppv = NULL;
734
735     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
736
737     This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder));
738     if (!This) return E_OUTOFMEMORY;
739
740     This->IWICBitmapEncoder_iface.lpVtbl = &IcnsEncoder_Vtbl;
741     This->ref = 1;
742     This->stream = NULL;
743     This->icns_family = NULL;
744     This->any_frame_committed = FALSE;
745     This->outstanding_commits = 0;
746     This->committed = FALSE;
747     InitializeCriticalSection(&This->lock);
748     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcnsEncoder.lock");
749
750     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
751     IUnknown_Release((IUnknown*)This);
752
753     return ret;
754 }
755
756 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
757          MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
758
759 HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
760 {
761     ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");
762     return E_FAIL;
763 }
764
765 #endif