2 * Copyright 2009 Vincent Povirk
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.
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.
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
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 struct FormatConverter;
57 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
58 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
60 struct pixelformatinfo {
61 enum pixelformat format;
62 const WICPixelFormatGUID *guid;
63 copyfunc copy_function;
66 typedef struct FormatConverter {
67 const IWICFormatConverterVtbl *lpVtbl;
69 IWICBitmapSource *source;
70 const struct pixelformatinfo *dst_format, *src_format;
71 WICBitmapDitherType dither;
72 double alpha_threshold;
73 WICBitmapPaletteType palette_type;
76 static void make_grayscale_palette(WICColor *colors, UINT num_colors)
79 for (i=0; i<num_colors; i++)
81 v = i * 255 / (num_colors-1);
82 colors[i] = 0xff000000 | v<<16 | v<<8 | v;
86 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
87 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
89 switch (source_format)
91 case format_1bppIndexed:
92 case format_BlackWhite:
98 UINT srcstride, srcdatasize;
104 IWICPalette *palette;
107 if (source_format == format_1bppIndexed)
109 res = PaletteImpl_Create(&palette);
110 if (FAILED(res)) return res;
112 res = IWICBitmapSource_CopyPalette(This->source, palette);
114 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
116 IWICPalette_Release(palette);
118 if (FAILED(res)) return res;
122 colors[0] = 0xff000000;
123 colors[1] = 0xffffffff;
126 srcstride = (prc->Width+7)/8;
127 srcdatasize = srcstride * prc->Height;
129 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
130 if (!srcdata) return E_OUTOFMEMORY;
132 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
138 for (y=0; y<prc->Height; y++) {
139 srcbyte=(const BYTE*)srcrow;
140 dstpixel=(DWORD*)dstrow;
141 for (x=0; x<prc->Width; x+=8) {
144 *dstpixel++ = colors[srcval>>7&1];
145 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
146 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
147 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
148 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
149 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
150 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
151 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
158 HeapFree(GetProcessHeap(), 0, srcdata);
163 case format_2bppIndexed:
164 case format_2bppGray:
170 UINT srcstride, srcdatasize;
176 IWICPalette *palette;
179 if (source_format == format_2bppIndexed)
181 res = PaletteImpl_Create(&palette);
182 if (FAILED(res)) return res;
184 res = IWICBitmapSource_CopyPalette(This->source, palette);
186 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
188 IWICPalette_Release(palette);
190 if (FAILED(res)) return res;
193 make_grayscale_palette(colors, 4);
195 srcstride = (prc->Width+3)/4;
196 srcdatasize = srcstride * prc->Height;
198 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
199 if (!srcdata) return E_OUTOFMEMORY;
201 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
207 for (y=0; y<prc->Height; y++) {
208 srcbyte=(const BYTE*)srcrow;
209 dstpixel=(DWORD*)dstrow;
210 for (x=0; x<prc->Width; x+=4) {
213 *dstpixel++ = colors[srcval>>6];
214 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
215 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
216 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
223 HeapFree(GetProcessHeap(), 0, srcdata);
228 case format_4bppIndexed:
229 case format_4bppGray:
235 UINT srcstride, srcdatasize;
241 IWICPalette *palette;
244 if (source_format == format_4bppIndexed)
246 res = PaletteImpl_Create(&palette);
247 if (FAILED(res)) return res;
249 res = IWICBitmapSource_CopyPalette(This->source, palette);
251 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
253 IWICPalette_Release(palette);
255 if (FAILED(res)) return res;
258 make_grayscale_palette(colors, 16);
260 srcstride = (prc->Width+1)/2;
261 srcdatasize = srcstride * prc->Height;
263 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
264 if (!srcdata) return E_OUTOFMEMORY;
266 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
272 for (y=0; y<prc->Height; y++) {
273 srcbyte=(const BYTE*)srcrow;
274 dstpixel=(DWORD*)dstrow;
275 for (x=0; x<prc->Width; x+=2) {
278 *dstpixel++ = colors[srcval>>4];
279 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
286 HeapFree(GetProcessHeap(), 0, srcdata);
291 case format_8bppGray:
297 UINT srcstride, srcdatasize;
303 srcstride = prc->Width;
304 srcdatasize = srcstride * prc->Height;
306 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
307 if (!srcdata) return E_OUTOFMEMORY;
309 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
315 for (y=0; y<prc->Height; y++) {
316 srcbyte=(const BYTE*)srcrow;
317 dstpixel=(DWORD*)dstrow;
318 for (x=0; x<prc->Width; x++)
320 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
328 HeapFree(GetProcessHeap(), 0, srcdata);
333 case format_8bppIndexed:
339 UINT srcstride, srcdatasize;
344 WICColor colors[256];
345 IWICPalette *palette;
348 res = PaletteImpl_Create(&palette);
349 if (FAILED(res)) return res;
351 res = IWICBitmapSource_CopyPalette(This->source, palette);
353 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
355 IWICPalette_Release(palette);
357 if (FAILED(res)) return res;
359 srcstride = prc->Width;
360 srcdatasize = srcstride * prc->Height;
362 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
363 if (!srcdata) return E_OUTOFMEMORY;
365 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
371 for (y=0; y<prc->Height; y++) {
372 srcbyte=(const BYTE*)srcrow;
373 dstpixel=(DWORD*)dstrow;
374 for (x=0; x<prc->Width; x++)
375 *dstpixel++ = colors[*srcbyte++];
381 HeapFree(GetProcessHeap(), 0, srcdata);
386 case format_16bppGray:
392 UINT srcstride, srcdatasize;
398 srcstride = prc->Width * 2;
399 srcdatasize = srcstride * prc->Height;
401 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
402 if (!srcdata) return E_OUTOFMEMORY;
404 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
410 for (y=0; y<prc->Height; y++) {
411 srcbyte=(const BYTE*)srcrow;
412 dstpixel=(DWORD*)dstrow;
413 for (x=0; x<prc->Width; x++)
415 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
423 HeapFree(GetProcessHeap(), 0, srcdata);
428 case format_16bppBGR555:
434 UINT srcstride, srcdatasize;
436 const WORD *srcpixel;
440 srcstride = 2 * prc->Width;
441 srcdatasize = srcstride * prc->Height;
443 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
444 if (!srcdata) return E_OUTOFMEMORY;
446 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
452 for (y=0; y<prc->Height; y++) {
453 srcpixel=(const WORD*)srcrow;
454 dstpixel=(DWORD*)dstrow;
455 for (x=0; x<prc->Width; x++) {
458 *dstpixel++=0xff000000 | /* constant 255 alpha */
459 ((srcval << 9) & 0xf80000) | /* r */
460 ((srcval << 4) & 0x070000) | /* r - 3 bits */
461 ((srcval << 6) & 0x00f800) | /* g */
462 ((srcval << 1) & 0x000700) | /* g - 3 bits */
463 ((srcval << 3) & 0x0000f8) | /* b */
464 ((srcval >> 2) & 0x000007); /* b - 3 bits */
471 HeapFree(GetProcessHeap(), 0, srcdata);
476 case format_16bppBGR565:
482 UINT srcstride, srcdatasize;
484 const WORD *srcpixel;
488 srcstride = 2 * prc->Width;
489 srcdatasize = srcstride * prc->Height;
491 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
492 if (!srcdata) return E_OUTOFMEMORY;
494 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
500 for (y=0; y<prc->Height; y++) {
501 srcpixel=(const WORD*)srcrow;
502 dstpixel=(DWORD*)dstrow;
503 for (x=0; x<prc->Width; x++) {
506 *dstpixel++=0xff000000 | /* constant 255 alpha */
507 ((srcval << 8) & 0xf80000) | /* r */
508 ((srcval << 3) & 0x070000) | /* r - 3 bits */
509 ((srcval << 5) & 0x00fc00) | /* g */
510 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
511 ((srcval << 3) & 0x0000f8) | /* b */
512 ((srcval >> 2) & 0x000007); /* b - 3 bits */
519 HeapFree(GetProcessHeap(), 0, srcdata);
524 case format_24bppBGR:
530 UINT srcstride, srcdatasize;
532 const BYTE *srcpixel;
536 srcstride = 3 * prc->Width;
537 srcdatasize = srcstride * prc->Height;
539 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
540 if (!srcdata) return E_OUTOFMEMORY;
542 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
548 for (y=0; y<prc->Height; y++) {
551 for (x=0; x<prc->Width; x++) {
552 *dstpixel++=*srcpixel++; /* blue */
553 *dstpixel++=*srcpixel++; /* green */
554 *dstpixel++=*srcpixel++; /* red */
555 *dstpixel++=255; /* alpha */
562 HeapFree(GetProcessHeap(), 0, srcdata);
567 case format_32bppBGR:
573 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
574 if (FAILED(res)) return res;
576 /* set all alpha values to 255 */
577 for (y=0; y<prc->Height; y++)
578 for (x=0; x<prc->Width; x++)
579 pbBuffer[cbStride*y+4*x+3] = 0xff;
582 case format_32bppBGRA:
584 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
586 case format_48bppRGB:
592 UINT srcstride, srcdatasize;
594 const BYTE *srcpixel;
598 srcstride = 6 * prc->Width;
599 srcdatasize = srcstride * prc->Height;
601 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
602 if (!srcdata) return E_OUTOFMEMORY;
604 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
610 for (y=0; y<prc->Height; y++) {
612 dstpixel=(DWORD*)dstrow;
613 for (x=0; x<prc->Width; x++) {
614 BYTE red, green, blue;
615 red = *srcpixel++; srcpixel++;
616 green = *srcpixel++; srcpixel++;
617 blue = *srcpixel++; srcpixel++;
618 *dstpixel++=0xff000000|red<<16|green<<8|blue;
625 HeapFree(GetProcessHeap(), 0, srcdata);
630 case format_64bppRGBA:
636 UINT srcstride, srcdatasize;
638 const BYTE *srcpixel;
642 srcstride = 8 * prc->Width;
643 srcdatasize = srcstride * prc->Height;
645 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
646 if (!srcdata) return E_OUTOFMEMORY;
648 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
654 for (y=0; y<prc->Height; y++) {
656 dstpixel=(DWORD*)dstrow;
657 for (x=0; x<prc->Width; x++) {
658 BYTE red, green, blue, alpha;
659 red = *srcpixel++; srcpixel++;
660 green = *srcpixel++; srcpixel++;
661 blue = *srcpixel++; srcpixel++;
662 alpha = *srcpixel++; srcpixel++;
663 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
670 HeapFree(GetProcessHeap(), 0, srcdata);
676 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
680 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
681 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
683 switch (source_format)
685 case format_32bppBGR:
686 case format_32bppBGRA:
688 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
691 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
695 static const struct pixelformatinfo supported_formats[] = {
696 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
697 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
698 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
699 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
700 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
701 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
702 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
703 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
704 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
705 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
706 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
707 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
708 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
709 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
710 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
711 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
715 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
719 for (i=0; supported_formats[i].guid; i++)
720 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
725 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
728 FormatConverter *This = (FormatConverter*)iface;
729 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
731 if (!ppv) return E_INVALIDARG;
733 if (IsEqualIID(&IID_IUnknown, iid) ||
734 IsEqualIID(&IID_IWICBitmapSource, iid) ||
735 IsEqualIID(&IID_IWICFormatConverter, iid))
742 return E_NOINTERFACE;
745 IUnknown_AddRef((IUnknown*)*ppv);
749 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
751 FormatConverter *This = (FormatConverter*)iface;
752 ULONG ref = InterlockedIncrement(&This->ref);
754 TRACE("(%p) refcount=%u\n", iface, ref);
759 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
761 FormatConverter *This = (FormatConverter*)iface;
762 ULONG ref = InterlockedDecrement(&This->ref);
764 TRACE("(%p) refcount=%u\n", iface, ref);
768 if (This->source) IWICBitmapSource_Release(This->source);
769 HeapFree(GetProcessHeap(), 0, This);
775 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
776 UINT *puiWidth, UINT *puiHeight)
778 FormatConverter *This = (FormatConverter*)iface;
780 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
783 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
785 return WINCODEC_ERR_NOTINITIALIZED;
788 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
789 WICPixelFormatGUID *pPixelFormat)
791 FormatConverter *This = (FormatConverter*)iface;
793 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
796 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
798 return WINCODEC_ERR_NOTINITIALIZED;
803 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
804 double *pDpiX, double *pDpiY)
806 FormatConverter *This = (FormatConverter*)iface;
808 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
811 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
813 return WINCODEC_ERR_NOTINITIALIZED;
816 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
817 IWICPalette *pIPalette)
819 FIXME("(%p,%p): stub\n", iface, pIPalette);
823 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
824 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
826 FormatConverter *This = (FormatConverter*)iface;
827 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
830 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
831 pbBuffer, This->src_format->format);
833 return WINCODEC_ERR_NOTINITIALIZED;
836 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
837 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
838 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
840 FormatConverter *This = (FormatConverter*)iface;
841 const struct pixelformatinfo *srcinfo, *dstinfo;
846 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
847 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
849 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
851 if (This->source) return WINCODEC_ERR_WRONGSTATE;
853 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
854 if (FAILED(res)) return res;
856 srcinfo = get_formatinfo(&srcFormat);
857 if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
859 dstinfo = get_formatinfo(dstFormat);
860 if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
862 if (dstinfo->copy_function)
864 IWICBitmapSource_AddRef(pISource);
865 This->source = pISource;
866 This->src_format = srcinfo;
867 This->dst_format = dstinfo;
868 This->dither = dither;
869 This->alpha_threshold = alphaThresholdPercent;
870 This->palette_type = paletteTranslate;
873 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
878 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
879 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
882 FormatConverter *This = (FormatConverter*)iface;
883 const struct pixelformatinfo *srcinfo, *dstinfo;
885 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
886 debugstr_guid(dstPixelFormat), pfCanConvert);
888 srcinfo = get_formatinfo(srcPixelFormat);
889 if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
891 dstinfo = get_formatinfo(dstPixelFormat);
892 if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
894 if (dstinfo->copy_function &&
895 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
896 *pfCanConvert = TRUE;
898 *pfCanConvert = FALSE;
903 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
904 FormatConverter_QueryInterface,
905 FormatConverter_AddRef,
906 FormatConverter_Release,
907 FormatConverter_GetSize,
908 FormatConverter_GetPixelFormat,
909 FormatConverter_GetResolution,
910 FormatConverter_CopyPalette,
911 FormatConverter_CopyPixels,
912 FormatConverter_Initialize,
913 FormatConverter_CanConvert
916 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
918 FormatConverter *This;
921 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
925 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
927 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
928 if (!This) return E_OUTOFMEMORY;
930 This->lpVtbl = &FormatConverter_Vtbl;
934 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
935 IUnknown_Release((IUnknown*)This);