dinput: COM cleanup - use helper function instead of direct typecast in OS/X joystick.
[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;
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 += rc.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     const IWICBitmapEncoderVtbl *lpVtbl;
416     LONG ref;
417     IStream *stream;
418     BmpFrameEncode *frame;
419 } BmpEncoder;
420
421 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
422     void **ppv)
423 {
424     BmpEncoder *This = (BmpEncoder*)iface;
425     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
426
427     if (!ppv) return E_INVALIDARG;
428
429     if (IsEqualIID(&IID_IUnknown, iid) ||
430         IsEqualIID(&IID_IWICBitmapEncoder, iid))
431     {
432         *ppv = This;
433     }
434     else
435     {
436         *ppv = NULL;
437         return E_NOINTERFACE;
438     }
439
440     IUnknown_AddRef((IUnknown*)*ppv);
441     return S_OK;
442 }
443
444 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
445 {
446     BmpEncoder *This = (BmpEncoder*)iface;
447     ULONG ref = InterlockedIncrement(&This->ref);
448
449     TRACE("(%p) refcount=%u\n", iface, ref);
450
451     return ref;
452 }
453
454 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
455 {
456     BmpEncoder *This = (BmpEncoder*)iface;
457     ULONG ref = InterlockedDecrement(&This->ref);
458
459     TRACE("(%p) refcount=%u\n", iface, ref);
460
461     if (ref == 0)
462     {
463         if (This->stream) IStream_Release(This->stream);
464         if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
465         HeapFree(GetProcessHeap(), 0, This);
466     }
467
468     return ref;
469 }
470
471 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
472     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
473 {
474     BmpEncoder *This = (BmpEncoder*)iface;
475
476     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
477
478     IStream_AddRef(pIStream);
479     This->stream = pIStream;
480
481     return S_OK;
482 }
483
484 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
485     GUID *pguidContainerFormat)
486 {
487     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
492     IWICBitmapEncoderInfo **ppIEncoderInfo)
493 {
494     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
495     return E_NOTIMPL;
496 }
497
498 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
499     UINT cCount, IWICColorContext **ppIColorContext)
500 {
501     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
502     return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
506 {
507     TRACE("(%p,%p)\n", iface, pIPalette);
508     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
509 }
510
511 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
512 {
513     TRACE("(%p,%p)\n", iface, pIThumbnail);
514     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
515 }
516
517 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
518 {
519     TRACE("(%p,%p)\n", iface, pIPreview);
520     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
521 }
522
523 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
524     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
525 {
526     BmpEncoder *This = (BmpEncoder*)iface;
527     BmpFrameEncode *encode;
528     HRESULT hr;
529
530     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
531
532     if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
533
534     if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
535
536     hr = CreatePropertyBag2(ppIEncoderOptions);
537     if (FAILED(hr)) return hr;
538
539     encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
540     if (!encode)
541     {
542         IPropertyBag2_Release(*ppIEncoderOptions);
543         *ppIEncoderOptions = NULL;
544         return E_OUTOFMEMORY;
545     }
546     encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
547     encode->ref = 2;
548     IStream_AddRef(This->stream);
549     encode->stream = This->stream;
550     encode->initialized = FALSE;
551     encode->width = 0;
552     encode->height = 0;
553     encode->bits = NULL;
554     encode->format = NULL;
555     encode->xres = 0.0;
556     encode->yres = 0.0;
557     encode->lineswritten = 0;
558     encode->committed = FALSE;
559
560     *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
561     This->frame = encode;
562
563     return S_OK;
564 }
565
566 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
567 {
568     BmpEncoder *This = (BmpEncoder*)iface;
569     TRACE("(%p)\n", iface);
570
571     if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
572
573     return S_OK;
574 }
575
576 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
577     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
578 {
579     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
580     return E_NOTIMPL;
581 }
582
583 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
584     BmpEncoder_QueryInterface,
585     BmpEncoder_AddRef,
586     BmpEncoder_Release,
587     BmpEncoder_Initialize,
588     BmpEncoder_GetContainerFormat,
589     BmpEncoder_GetEncoderInfo,
590     BmpEncoder_SetColorContexts,
591     BmpEncoder_SetPalette,
592     BmpEncoder_SetThumbnail,
593     BmpEncoder_SetPreview,
594     BmpEncoder_CreateNewFrame,
595     BmpEncoder_Commit,
596     BmpEncoder_GetMetadataQueryWriter
597 };
598
599 HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
600 {
601     BmpEncoder *This;
602     HRESULT ret;
603
604     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
605
606     *ppv = NULL;
607
608     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
609
610     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
611     if (!This) return E_OUTOFMEMORY;
612
613     This->lpVtbl = &BmpEncoder_Vtbl;
614     This->ref = 1;
615     This->stream = NULL;
616     This->frame = NULL;
617
618     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
619     IUnknown_Release((IUnknown*)This);
620
621     return ret;
622 }