windowscodecs: Implement ComponentFactory::CreateEncoderPropertyBag.
[wine] / dlls / windowscodecs / bmpencode.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 "wingdi.h"
29 #include "objbase.h"
30 #include "wincodec.h"
31
32 #include "wincodecs_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37
38 struct bmp_pixelformat {
39     const WICPixelFormatGUID *guid;
40     UINT bpp;
41     DWORD compression;
42     DWORD redmask;
43     DWORD greenmask;
44     DWORD bluemask;
45     DWORD alphamask;
46 };
47
48 static const struct bmp_pixelformat formats[] = {
49     {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
50     {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
51     {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
52     {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
53 #if 0
54     /* Windows doesn't seem to support this one. */
55     {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
56 #endif
57     {NULL}
58 };
59
60 typedef struct BmpFrameEncode {
61     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
62     LONG ref;
63     IStream *stream;
64     BOOL initialized;
65     UINT width, height;
66     BYTE *bits;
67     const struct bmp_pixelformat *format;
68     double xres, yres;
69     UINT lineswritten;
70     UINT stride;
71     BOOL committed;
72 } BmpFrameEncode;
73
74 static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
75 {
76     return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
77 }
78
79 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
80     void **ppv)
81 {
82     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
83     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
84
85     if (!ppv) return E_INVALIDARG;
86
87     if (IsEqualIID(&IID_IUnknown, iid) ||
88         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
89     {
90         *ppv = &This->IWICBitmapFrameEncode_iface;
91     }
92     else
93     {
94         *ppv = NULL;
95         return E_NOINTERFACE;
96     }
97
98     IUnknown_AddRef((IUnknown*)*ppv);
99     return S_OK;
100 }
101
102 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
103 {
104     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
105     ULONG ref = InterlockedIncrement(&This->ref);
106
107     TRACE("(%p) refcount=%u\n", iface, ref);
108
109     return ref;
110 }
111
112 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
113 {
114     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
115     ULONG ref = InterlockedDecrement(&This->ref);
116
117     TRACE("(%p) refcount=%u\n", iface, ref);
118
119     if (ref == 0)
120     {
121         if (This->stream) IStream_Release(This->stream);
122         HeapFree(GetProcessHeap(), 0, This->bits);
123         HeapFree(GetProcessHeap(), 0, This);
124     }
125
126     return ref;
127 }
128
129 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
130     IPropertyBag2 *pIEncoderOptions)
131 {
132     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
133     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
134
135     if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
136
137     This->initialized = TRUE;
138
139     return S_OK;
140 }
141
142 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
143     UINT uiWidth, UINT uiHeight)
144 {
145     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
146     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
147
148     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
149
150     This->width = uiWidth;
151     This->height = uiHeight;
152
153     return S_OK;
154 }
155
156 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
157     double dpiX, double dpiY)
158 {
159     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
160     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
161
162     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
163
164     This->xres = dpiX;
165     This->yres = dpiY;
166
167     return S_OK;
168 }
169
170 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
171     WICPixelFormatGUID *pPixelFormat)
172 {
173     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
174     int i;
175     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
176
177     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
178
179     for (i=0; formats[i].guid; i++)
180     {
181         if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
182             break;
183     }
184
185     if (!formats[i].guid) i = 0;
186
187     This->format = &formats[i];
188     memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
189
190     return S_OK;
191 }
192
193 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
194     UINT cCount, IWICColorContext **ppIColorContext)
195 {
196     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
197     return E_NOTIMPL;
198 }
199
200 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
201     IWICPalette *pIPalette)
202 {
203     FIXME("(%p,%p): stub\n", iface, pIPalette);
204     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
205 }
206
207 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
208     IWICBitmapSource *pIThumbnail)
209 {
210     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
211     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
212 }
213
214 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
215 {
216     if (!This->bits)
217     {
218         if (!This->initialized || !This->width || !This->height || !This->format)
219             return WINCODEC_ERR_WRONGSTATE;
220
221         This->stride = (((This->width * This->format->bpp)+31)/32)*4;
222         This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
223         if (!This->bits) return E_OUTOFMEMORY;
224     }
225
226     return S_OK;
227 }
228
229 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
230     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
231 {
232     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
233     HRESULT hr;
234     WICRect rc;
235     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
236
237     if (!This->initialized || !This->width || !This->height || !This->format)
238         return WINCODEC_ERR_WRONGSTATE;
239
240     hr = BmpFrameEncode_AllocateBits(This);
241     if (FAILED(hr)) return hr;
242
243     rc.X = 0;
244     rc.Y = 0;
245     rc.Width = This->width;
246     rc.Height = lineCount;
247
248     hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
249         &rc, This->stride, This->stride*(This->height-This->lineswritten),
250         This->bits + This->stride*This->lineswritten);
251
252     if (SUCCEEDED(hr))
253         This->lineswritten += lineCount;
254
255     return hr;
256 }
257
258 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
259     IWICBitmapSource *pIBitmapSource, WICRect *prc)
260 {
261     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
262     HRESULT hr;
263     WICRect rc;
264     WICPixelFormatGUID guid;
265     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
266
267     if (!This->initialized || !This->width || !This->height)
268         return WINCODEC_ERR_WRONGSTATE;
269
270     if (!This->format)
271     {
272         hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
273         if (FAILED(hr)) return hr;
274         hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
275         if (FAILED(hr)) return hr;
276     }
277
278     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
279     if (FAILED(hr)) return hr;
280     if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
281     {
282         /* should use WICConvertBitmapSource to convert, but that's unimplemented */
283         ERR("format %s unsupported\n", debugstr_guid(&guid));
284         return E_FAIL;
285     }
286
287     if (This->xres == 0.0 || This->yres == 0.0)
288     {
289         double xres, yres;
290         hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
291         if (FAILED(hr)) return hr;
292         hr = BmpFrameEncode_SetResolution(iface, xres, yres);
293         if (FAILED(hr)) return hr;
294     }
295
296     if (!prc)
297     {
298         UINT width, height;
299         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
300         if (FAILED(hr)) return hr;
301         rc.X = 0;
302         rc.Y = 0;
303         rc.Width = width;
304         rc.Height = height;
305         prc = &rc;
306     }
307
308     if (prc->Width != This->width) return E_INVALIDARG;
309
310     hr = BmpFrameEncode_AllocateBits(This);
311     if (FAILED(hr)) return hr;
312
313     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
314         This->stride*(This->height-This->lineswritten),
315         This->bits + This->stride*This->lineswritten);
316
317     This->lineswritten += prc->Height;
318
319     return S_OK;
320 }
321
322 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
323 {
324     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
325     BITMAPFILEHEADER bfh;
326     BITMAPV5HEADER bih;
327     UINT info_size;
328     LARGE_INTEGER pos;
329     ULONG byteswritten;
330     HRESULT hr;
331
332     TRACE("(%p)\n", iface);
333
334     if (!This->bits || This->committed || This->height != This->lineswritten)
335         return WINCODEC_ERR_WRONGSTATE;
336
337     bfh.bfType = 0x4d42; /* "BM" */
338     bfh.bfReserved1 = 0;
339     bfh.bfReserved2 = 0;
340
341     bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
342     bih.bV5Width = This->width;
343     bih.bV5Height = -This->height; /* top-down bitmap */
344     bih.bV5Planes = 1;
345     bih.bV5BitCount = This->format->bpp;
346     bih.bV5Compression = This->format->compression;
347     bih.bV5SizeImage = This->stride*This->height;
348     bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
349     bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
350     bih.bV5ClrUsed = 0;
351     bih.bV5ClrImportant = 0;
352
353     if (This->format->compression == BI_BITFIELDS)
354     {
355         if (This->format->alphamask)
356             bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
357         else
358             info_size = sizeof(BITMAPINFOHEADER)+12;
359         bih.bV5RedMask = This->format->redmask;
360         bih.bV5GreenMask = This->format->greenmask;
361         bih.bV5BlueMask = This->format->bluemask;
362         bih.bV5AlphaMask = This->format->alphamask;
363         bih.bV5AlphaMask = LCS_DEVICE_RGB;
364     }
365
366     bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
367     bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
368
369     pos.QuadPart = 0;
370     hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
371     if (FAILED(hr)) return hr;
372
373     hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
374     if (FAILED(hr)) return hr;
375     if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
376
377     hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
378     if (FAILED(hr)) return hr;
379     if (byteswritten != info_size) return E_FAIL;
380
381     hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
382     if (FAILED(hr)) return hr;
383     if (byteswritten != bih.bV5SizeImage) return E_FAIL;
384
385     This->committed = TRUE;
386
387     return S_OK;
388 }
389
390 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
391     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
392 {
393     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
394     return E_NOTIMPL;
395 }
396
397 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
398     BmpFrameEncode_QueryInterface,
399     BmpFrameEncode_AddRef,
400     BmpFrameEncode_Release,
401     BmpFrameEncode_Initialize,
402     BmpFrameEncode_SetSize,
403     BmpFrameEncode_SetResolution,
404     BmpFrameEncode_SetPixelFormat,
405     BmpFrameEncode_SetColorContexts,
406     BmpFrameEncode_SetPalette,
407     BmpFrameEncode_SetThumbnail,
408     BmpFrameEncode_WritePixels,
409     BmpFrameEncode_WriteSource,
410     BmpFrameEncode_Commit,
411     BmpFrameEncode_GetMetadataQueryWriter
412 };
413
414 typedef struct BmpEncoder {
415     IWICBitmapEncoder IWICBitmapEncoder_iface;
416     LONG ref;
417     IStream *stream;
418     BmpFrameEncode *frame;
419 } BmpEncoder;
420
421 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
422 {
423     return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
424 }
425
426 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
427     void **ppv)
428 {
429     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
430     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
431
432     if (!ppv) return E_INVALIDARG;
433
434     if (IsEqualIID(&IID_IUnknown, iid) ||
435         IsEqualIID(&IID_IWICBitmapEncoder, iid))
436     {
437         *ppv = &This->IWICBitmapEncoder_iface;
438     }
439     else
440     {
441         *ppv = NULL;
442         return E_NOINTERFACE;
443     }
444
445     IUnknown_AddRef((IUnknown*)*ppv);
446     return S_OK;
447 }
448
449 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
450 {
451     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
452     ULONG ref = InterlockedIncrement(&This->ref);
453
454     TRACE("(%p) refcount=%u\n", iface, ref);
455
456     return ref;
457 }
458
459 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
460 {
461     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
462     ULONG ref = InterlockedDecrement(&This->ref);
463
464     TRACE("(%p) refcount=%u\n", iface, ref);
465
466     if (ref == 0)
467     {
468         if (This->stream) IStream_Release(This->stream);
469         if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
470         HeapFree(GetProcessHeap(), 0, This);
471     }
472
473     return ref;
474 }
475
476 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
477     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
478 {
479     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
480
481     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
482
483     IStream_AddRef(pIStream);
484     This->stream = pIStream;
485
486     return S_OK;
487 }
488
489 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
490     GUID *pguidContainerFormat)
491 {
492     memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
493     return S_OK;
494 }
495
496 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
497     IWICBitmapEncoderInfo **ppIEncoderInfo)
498 {
499     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
500     return E_NOTIMPL;
501 }
502
503 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
504     UINT cCount, IWICColorContext **ppIColorContext)
505 {
506     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
511 {
512     TRACE("(%p,%p)\n", iface, pIPalette);
513     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
514 }
515
516 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
517 {
518     TRACE("(%p,%p)\n", iface, pIThumbnail);
519     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
520 }
521
522 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
523 {
524     TRACE("(%p,%p)\n", iface, pIPreview);
525     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
526 }
527
528 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
529     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
530 {
531     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
532     BmpFrameEncode *encode;
533     HRESULT hr;
534
535     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
536
537     if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
538
539     if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
540
541     hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions);
542     if (FAILED(hr)) return hr;
543
544     encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
545     if (!encode)
546     {
547         IPropertyBag2_Release(*ppIEncoderOptions);
548         *ppIEncoderOptions = NULL;
549         return E_OUTOFMEMORY;
550     }
551     encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
552     encode->ref = 2;
553     IStream_AddRef(This->stream);
554     encode->stream = This->stream;
555     encode->initialized = FALSE;
556     encode->width = 0;
557     encode->height = 0;
558     encode->bits = NULL;
559     encode->format = NULL;
560     encode->xres = 0.0;
561     encode->yres = 0.0;
562     encode->lineswritten = 0;
563     encode->committed = FALSE;
564
565     *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
566     This->frame = encode;
567
568     return S_OK;
569 }
570
571 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
572 {
573     BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
574     TRACE("(%p)\n", iface);
575
576     if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
577
578     return S_OK;
579 }
580
581 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
582     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
583 {
584     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
585     return E_NOTIMPL;
586 }
587
588 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
589     BmpEncoder_QueryInterface,
590     BmpEncoder_AddRef,
591     BmpEncoder_Release,
592     BmpEncoder_Initialize,
593     BmpEncoder_GetContainerFormat,
594     BmpEncoder_GetEncoderInfo,
595     BmpEncoder_SetColorContexts,
596     BmpEncoder_SetPalette,
597     BmpEncoder_SetThumbnail,
598     BmpEncoder_SetPreview,
599     BmpEncoder_CreateNewFrame,
600     BmpEncoder_Commit,
601     BmpEncoder_GetMetadataQueryWriter
602 };
603
604 HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
605 {
606     BmpEncoder *This;
607     HRESULT ret;
608
609     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
610
611     *ppv = NULL;
612
613     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
614
615     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
616     if (!This) return E_OUTOFMEMORY;
617
618     This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
619     This->ref = 1;
620     This->stream = NULL;
621     This->frame = NULL;
622
623     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
624     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
625
626     return ret;
627 }