[WINDOWSCODECS] Sync with Wine Staging 3.9. CORE-14656
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Jun 2018 02:55:39 +0000 (03:55 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Jun 2018 02:55:39 +0000 (03:55 +0100)
16 files changed:
dll/win32/windowscodecs/bitmap.c
dll/win32/windowscodecs/bmpdecode.c
dll/win32/windowscodecs/bmpencode.c
dll/win32/windowscodecs/converter.c
dll/win32/windowscodecs/gifformat.c
dll/win32/windowscodecs/icoformat.c
dll/win32/windowscodecs/imgfactory.c
dll/win32/windowscodecs/info.c
dll/win32/windowscodecs/jpegformat.c
dll/win32/windowscodecs/main.c
dll/win32/windowscodecs/pngformat.c
dll/win32/windowscodecs/precomp.h
dll/win32/windowscodecs/tgaformat.c
dll/win32/windowscodecs/tiffformat.c
dll/win32/windowscodecs/wincodecs_private.h
media/doc/README.WINE

index 69ec14f..734c211 100644 (file)
@@ -45,7 +45,8 @@ typedef struct BitmapImpl {
     int palette_set;
     LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
     BYTE *data;
-    BOOL is_section; /* TRUE if data is a section created by an application */
+    void *view; /* used if data is a section created by an application */
+    UINT offset; /* offset into view */
     UINT width, height;
     UINT stride;
     UINT bpp;
@@ -288,8 +289,8 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface)
         if (This->palette) IWICPalette_Release(This->palette);
         This->cs.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&This->cs);
-        if (This->is_section)
-            UnmapViewOfFile(This->data);
+        if (This->view)
+            UnmapViewOfFile(This->view);
         else
             HeapFree(GetProcessHeap(), 0, This->data);
         HeapFree(GetProcessHeap(), 0, This);
@@ -805,13 +806,13 @@ static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl =
     IMILUnknown2Impl_unknown3
 };
 
-HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
-    UINT stride, UINT datasize, BYTE *data,
-    REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
+HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasize, void *view,
+    UINT offset, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
     IWICBitmap **ppIBitmap)
 {
     HRESULT hr;
     BitmapImpl *This;
+    BYTE *data;
     UINT bpp;
 
     hr = get_pixelformat_bpp(pixelFormat, &bpp);
@@ -826,18 +827,12 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl));
     if (!This) return E_OUTOFMEMORY;
 
-    if (!data)
+    if (view) data = (BYTE *)view + offset;
+    else if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize)))
     {
-        data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize);
-        if (!data)
-        {
-            HeapFree(GetProcessHeap(), 0, This);
-            return E_OUTOFMEMORY;
-        }
-        This->is_section = FALSE;
+        HeapFree(GetProcessHeap(), 0, This);
+        return E_OUTOFMEMORY;
     }
-    else
-        This->is_section = TRUE;
 
     This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl;
     This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl;
@@ -848,6 +843,8 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
     This->palette_set = 0;
     This->lock = 0;
     This->data = data;
+    This->view = view;
+    This->offset = offset;
     This->width = uiWidth;
     This->height = uiHeight;
     This->stride = stride;
index 47f312f..1b8e4d1 100644 (file)
@@ -1068,20 +1068,9 @@ static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICBmpDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICBmpDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
index cb8b489..a81cc53 100644 (file)
@@ -261,8 +261,10 @@ static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
 {
     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    UINT dstbuffersize, bytesperrow, row;
+    BYTE *dst, *src;
     HRESULT hr;
-    WICRect rc;
+
     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
 
     if (!This->initialized || !This->width || !This->height || !This->format)
@@ -271,19 +273,27 @@ static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
     hr = BmpFrameEncode_AllocateBits(This);
     if (FAILED(hr)) return hr;
 
-    rc.X = 0;
-    rc.Y = 0;
-    rc.Width = This->width;
-    rc.Height = lineCount;
+    bytesperrow = ((This->format->bpp * This->width) + 7) / 8;
 
-    hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
-        &rc, This->stride, This->stride*(This->height-This->lineswritten),
-        This->bits + This->stride*This->lineswritten);
+    if (This->stride < bytesperrow)
+        return E_INVALIDARG;
 
-    if (SUCCEEDED(hr))
-        This->lineswritten += lineCount;
+    dstbuffersize = This->stride * (This->height - This->lineswritten);
+    if ((This->stride * (lineCount - 1)) + bytesperrow > dstbuffersize)
+        return E_INVALIDARG;
 
-    return hr;
+    src = pbPixels;
+    dst = This->bits + This->stride * (This->height - This->lineswritten - 1);
+    for (row = 0; row < lineCount; row++)
+    {
+        memcpy(dst, src, bytesperrow);
+        src += cbStride;
+        dst -= This->stride;
+    }
+
+    This->lineswritten += lineCount;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
@@ -314,11 +324,10 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     BITMAPFILEHEADER bfh;
     BITMAPV5HEADER bih;
-    UINT info_size, i;
+    UINT info_size;
     LARGE_INTEGER pos;
     ULONG byteswritten;
     HRESULT hr;
-    const BYTE *bits;
 
     TRACE("(%p)\n", iface);
 
@@ -331,7 +340,7 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
 
     bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
     bih.bV5Width = This->width;
-    bih.bV5Height = This->height; /* bottom-top bitmap */
+    bih.bV5Height = This->height;
     bih.bV5Planes = 1;
     bih.bV5BitCount = This->format->bpp;
     bih.bV5Compression = This->format->compression;
@@ -378,15 +387,9 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
         if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL;
     }
 
-    /* write the image bits as a bottom-top array */
-    bits = This->bits + bih.bV5SizeImage;
-    for (i = 0; i < This->height; i++)
-    {
-        bits -= This->stride;
-        hr = IStream_Write(This->stream, bits, This->stride, &byteswritten);
-        if (FAILED(hr)) return hr;
-        if (byteswritten != This->stride) return E_FAIL;
-    }
+    hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
+    if (FAILED(hr)) return hr;
+    if (byteswritten != bih.bV5SizeImage) return E_FAIL;
 
     This->committed = TRUE;
 
index c3bcce8..0d3414a 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "wincodecs_private.h"
 
+#include "wine/heap.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
@@ -1087,6 +1088,48 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec
         }
         return S_OK;
 
+    case format_32bppCMYK:
+        if (prc)
+        {
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+
+            srcstride = 4 * prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = heap_alloc(srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+            if (SUCCEEDED(hr))
+            {
+                INT x, y;
+                BYTE *src = srcdata, *dst = pbBuffer;
+
+                for (y = 0; y < prc->Height; y++)
+                {
+                    BYTE *cmyk = src;
+                    BYTE *bgr = dst;
+
+                    for (x = 0; x < prc->Width; x++)
+                    {
+                        BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
+                        bgr[0] = (255 - y) * (255 - k) / 255; /* B */
+                        bgr[1] = (255 - m) * (255 - k) / 255; /* G */
+                        bgr[2] = (255 - c) * (255 - k) / 255; /* R */
+                        cmyk += 4;
+                        bgr += 3;
+                    }
+                    src += srcstride;
+                    dst += cbStride;
+                }
+            }
+
+            heap_free(srcdata);
+            return hr;
+        }
+        return S_OK;
+
     default:
         FIXME("Unimplemented conversion path!\n");
         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
index e898d9c..78ac427 100644 (file)
@@ -1176,20 +1176,9 @@ static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
index 1b1c792..5e38ee0 100644 (file)
@@ -556,20 +556,9 @@ static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICIcoDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICIcoDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
index 88ce00e..180e745 100644 (file)
@@ -477,7 +477,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmap(IWICComponentFactory *iface,
 {
     TRACE("(%p,%u,%u,%s,%u,%p)\n", iface, uiWidth, uiHeight,
         debugstr_guid(pixelFormat), option, ppIBitmap);
-    return BitmapImpl_Create(uiWidth, uiHeight, 0, 0, NULL, pixelFormat, option, ppIBitmap);
+    return BitmapImpl_Create(uiWidth, uiHeight, 0, 0, NULL, 0, pixelFormat, option, ppIBitmap);
 }
 
 static HRESULT WINAPI ComponentFactory_CreateBitmapFromSource(IWICComponentFactory *iface,
@@ -524,7 +524,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromSource(IWICComponentFacto
     }
 
     if (SUCCEEDED(hr))
-        hr = BitmapImpl_Create(width, height, 0, 0, NULL, &pixelformat, option, &result);
+        hr = BitmapImpl_Create(width, height, 0, 0, NULL, 0, &pixelformat, option, &result);
 
     if (SUCCEEDED(hr))
     {
@@ -606,7 +606,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFacto
 
     if (!stride || !size || !buffer || !bitmap) return E_INVALIDARG;
 
-    hr = BitmapImpl_Create(width, height, stride, size, NULL, format, WICBitmapCacheOnLoad, bitmap);
+    hr = BitmapImpl_Create(width, height, stride, size, NULL, 0, format, WICBitmapCacheOnLoad, bitmap);
     if (SUCCEEDED(hr))
     {
         IWICBitmapLock *lock;
@@ -738,7 +738,8 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFact
         return E_INVALIDARG;
     }
 
-    hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, &format, WICBitmapCacheOnLoad, bitmap);
+    hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, 0, &format,
+                           WICBitmapCacheOnLoad, bitmap);
     if (hr != S_OK) return hr;
 
     hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock);
@@ -822,7 +823,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHICON(IWICComponentFactor
     stride = width * 4;
     size = stride * height;
 
-    hr = BitmapImpl_Create(width, height, stride, size, NULL,
+    hr = BitmapImpl_Create(width, height, stride, size, NULL, 0,
                            &GUID_WICPixelFormat32bppBGRA, WICBitmapCacheOnLoad, bitmap);
     if (hr != S_OK) goto failed;
 
@@ -1209,15 +1210,19 @@ HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height,
         REFWICPixelFormatGUID format, HANDLE section, UINT stride,
         UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap)
 {
-    DWORD access;
-    void *buffer;
+    SYSTEM_INFO sysinfo;
+    UINT bpp, access, size, view_offset, view_size;
+    void *view;
     HRESULT hr;
 
-    TRACE("%u,%u,%s,%p,%u,%#x,%#x,%p\n", width, height, debugstr_guid(format),
-        section, stride, offset, wicaccess, bitmap);
+    TRACE("%u,%u,%s,%p,%u,%u,%#x,%p\n", width, height, debugstr_guid(format),
+          section, stride, offset, wicaccess, bitmap);
 
     if (!width || !height || !section || !bitmap) return E_INVALIDARG;
 
+    hr = get_pixelformat_bpp(format, &bpp);
+    if (FAILED(hr)) return hr;
+
     switch (wicaccess)
     {
     case WICSectionAccessLevelReadWrite:
@@ -1233,11 +1238,20 @@ HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height,
         return E_INVALIDARG;
     }
 
-    buffer = MapViewOfFile(section, access, 0, offset, 0);
-    if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
+    if (!stride) stride = (((bpp * width) + 31) / 32) * 4;
+    size = stride * height;
+    if (size / height != stride) return E_INVALIDARG;
+
+    GetSystemInfo(&sysinfo);
+    view_offset = offset - (offset % sysinfo.dwAllocationGranularity);
+    view_size = size + (offset - view_offset);
+
+    view = MapViewOfFile(section, access, 0, view_offset, view_size);
+    if (!view) return HRESULT_FROM_WIN32(GetLastError());
 
-    hr = BitmapImpl_Create(width, height, stride, 0, buffer, format, WICBitmapCacheOnLoad, bitmap);
-    if (FAILED(hr)) UnmapViewOfFile(buffer);
+    offset -= view_offset;
+    hr = BitmapImpl_Create(width, height, stride, 0, view, offset, format, WICBitmapCacheOnLoad, bitmap);
+    if (FAILED(hr)) UnmapViewOfFile(view);
     return hr;
 }
 
index 22a7b83..33d3c30 100644 (file)
@@ -33,6 +33,8 @@
 #include "wine/debug.h"
 #include "wine/unicode.h"
 #include "wine/list.h"
+#include "wine/rbtree.h"
+#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
@@ -56,6 +58,13 @@ static const WCHAR supportspadding_valuename[] = {'S','u','p','p','o','r','t','s
 static const WCHAR fileextensions_valuename[] = {'F','i','l','e','E','x','t','e','n','s','i','o','n','s',0};
 static const WCHAR containers_keyname[] = {'C','o','n','t','a','i','n','e','r','s',0};
 
+typedef struct {
+    IWICComponentInfo IWICComponentInfo_iface;
+    LONG ref;
+    CLSID clsid;
+    struct wine_rb_entry entry;
+} ComponentInfo;
+
 static HRESULT ComponentInfo_GetStringValue(HKEY classkey, LPCWSTR value,
     UINT buffer_size, WCHAR *buffer, UINT *actual_size)
 {
@@ -204,15 +213,16 @@ static HRESULT ComponentInfo_GetGuidList(HKEY classkey, LPCWSTR subkeyname,
 }
 
 typedef struct {
-    IWICBitmapDecoderInfo IWICBitmapDecoderInfo_iface;
-    LONG ref;
+    ComponentInfo base;
     HKEY classkey;
-    CLSID clsid;
+    WICBitmapPattern *patterns;
+    UINT pattern_count;
+    UINT patterns_size;
 } BitmapDecoderInfo;
 
 static inline BitmapDecoderInfo *impl_from_IWICBitmapDecoderInfo(IWICBitmapDecoderInfo *iface)
 {
-    return CONTAINING_RECORD(iface, BitmapDecoderInfo, IWICBitmapDecoderInfo_iface);
+    return CONTAINING_RECORD(iface, BitmapDecoderInfo, base.IWICComponentInfo_iface);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
@@ -228,7 +238,7 @@ static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *if
         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
         IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
     {
-        *ppv = &This->IWICBitmapDecoderInfo_iface;
+        *ppv = &This->base.IWICComponentInfo_iface;
     }
     else
     {
@@ -243,7 +253,7 @@ static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *if
 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
 {
     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -253,13 +263,14 @@ static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
 {
     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
     if (ref == 0)
     {
         RegCloseKey(This->classkey);
+        heap_free(This->patterns);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -283,8 +294,7 @@ static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, C
     if (!pclsid)
         return E_INVALIDARG;
 
-    memcpy(pclsid, &This->clsid, sizeof(CLSID));
-
+    *pclsid = This->base.clsid;
     return S_OK;
 }
 
@@ -445,103 +455,26 @@ static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface
     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
 {
     BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
-    UINT pattern_count=0, patterns_size=0;
-    WCHAR subkeyname[11];
-    LONG res;
-    HKEY patternskey, patternkey;
-    static const WCHAR uintformatW[] = {'%','u',0};
-    static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
-    static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
-    static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
-    static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
-    static const WCHAR maskW[] = {'M','a','s','k',0};
-    static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
-    HRESULT hr=S_OK;
-    UINT i;
-    BYTE *bPatterns=(BYTE*)pPatterns;
-    DWORD length, valuesize;
 
     TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
 
-    res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
-    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
-
-    res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-    if (res == ERROR_SUCCESS)
-    {
-        patterns_size = pattern_count * sizeof(WICBitmapPattern);
-
-        for (i=0; i<pattern_count; i++)
-        {
-            snprintfW(subkeyname, 11, uintformatW, i);
-            res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
-            if (res == ERROR_SUCCESS)
-            {
-                valuesize = sizeof(ULONG);
-                res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
-                    &length, &valuesize);
-                patterns_size += length*2;
-
-                if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
-                {
-                    pPatterns[i].Length = length;
-
-                    pPatterns[i].EndOfStream = 0;
-                    valuesize = sizeof(BOOL);
-                    RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
-                        &pPatterns[i].EndOfStream, &valuesize);
-
-                    pPatterns[i].Position.QuadPart = 0;
-                    valuesize = sizeof(ULARGE_INTEGER);
-                    res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
-                        &pPatterns[i].Position, &valuesize);
-
-                    if (res == ERROR_SUCCESS)
-                    {
-                        pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
-                        valuesize = length;
-                        res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
-                            pPatterns[i].Pattern, &valuesize);
-                    }
-
-                    if (res == ERROR_SUCCESS)
-                    {
-                        pPatterns[i].Mask = bPatterns+patterns_size-length;
-                        valuesize = length;
-                        res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
-                            pPatterns[i].Mask, &valuesize);
-                    }
-                }
-
-                RegCloseKey(patternkey);
-            }
-            if (res != ERROR_SUCCESS)
-            {
-                hr = HRESULT_FROM_WIN32(res);
-                break;
-            }
-        }
-    }
-    else hr = HRESULT_FROM_WIN32(res);
+    if (!pcPatterns || !pcbPatternsActual) return E_INVALIDARG;
 
-    RegCloseKey(patternskey);
-
-    if (hr == S_OK)
+    *pcPatterns = This->pattern_count;
+    *pcbPatternsActual = This->patterns_size;
+    if (pPatterns)
     {
-        *pcPatterns = pattern_count;
-        *pcbPatternsActual = patterns_size;
-        if (pPatterns && cbSizePatterns < patterns_size)
-            hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
+        if (This->patterns_size && cbSizePatterns < This->patterns_size)
+            return WINCODEC_ERR_INSUFFICIENTBUFFER;
+        memcpy(pPatterns, This->patterns, This->patterns_size);
     }
-
-    return hr;
+    return S_OK;
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
     IStream *pIStream, BOOL *pfMatches)
 {
-    WICBitmapPattern *patterns;
-    UINT pattern_count=0, patterns_size=0;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
     HRESULT hr;
     UINT i;
     ULONG pos;
@@ -552,22 +485,13 @@ static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *if
 
     TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
 
-    hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
-    if (FAILED(hr)) return hr;
-
-    patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
-    if (!patterns) return E_OUTOFMEMORY;
-
-    hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
-    if (FAILED(hr)) goto end;
-
-    for (i=0; i<pattern_count; i++)
+    for (i=0; i < This->pattern_count; i++)
     {
-        if (datasize < patterns[i].Length)
+        if (datasize < This->patterns[i].Length)
         {
             HeapFree(GetProcessHeap(), 0, data);
-            datasize = patterns[i].Length;
-            data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
+            datasize = This->patterns[i].Length;
+            data = HeapAlloc(GetProcessHeap(), 0, This->patterns[i].Length);
             if (!data)
             {
                 hr = E_OUTOFMEMORY;
@@ -575,25 +499,25 @@ static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *if
             }
         }
 
-        if (patterns[i].EndOfStream)
-            seekpos.QuadPart = -patterns[i].Position.QuadPart;
+        if (This->patterns[i].EndOfStream)
+            seekpos.QuadPart = -This->patterns[i].Position.QuadPart;
         else
-            seekpos.QuadPart = patterns[i].Position.QuadPart;
-        hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
+            seekpos.QuadPart = This->patterns[i].Position.QuadPart;
+        hr = IStream_Seek(pIStream, seekpos, This->patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
         if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
         if (FAILED(hr)) break;
 
-        hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
-        if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
+        hr = IStream_Read(pIStream, data, This->patterns[i].Length, &bytesread);
+        if (hr == S_FALSE || (hr == S_OK && bytesread != This->patterns[i].Length)) /* past end of stream */
             continue;
         if (FAILED(hr)) break;
 
-        for (pos=0; pos<patterns[i].Length; pos++)
+        for (pos=0; pos < This->patterns[i].Length; pos++)
         {
-            if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
+            if ((data[pos] & This->patterns[i].Mask[pos]) != This->patterns[i].Pattern[pos])
                 break;
         }
-        if (pos == patterns[i].Length) /* matches pattern */
+        if (pos == This->patterns[i].Length) /* matches pattern */
         {
             hr = S_OK;
             *pfMatches = TRUE;
@@ -601,16 +525,13 @@ static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *if
         }
     }
 
-    if (i == pattern_count) /* does not match any pattern */
+    if (i == This->pattern_count) /* does not match any pattern */
     {
         hr = S_OK;
         *pfMatches = FALSE;
     }
 
-end:
-    HeapFree(GetProcessHeap(), 0, patterns);
     HeapFree(GetProcessHeap(), 0, data);
-
     return hr;
 }
 
@@ -621,7 +542,7 @@ static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *if
 
     TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
 
-    return create_instance(&This->clsid, &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
+    return create_instance(&This->base.clsid, &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
 }
 
 static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
@@ -653,36 +574,146 @@ static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
     BitmapDecoderInfo_CreateInstance
 };
 
-static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static void read_bitmap_patterns(BitmapDecoderInfo *info)
+{
+    UINT pattern_count=0, patterns_size=0;
+    WCHAR subkeyname[11];
+    LONG res;
+    HKEY patternskey, patternkey;
+    static const WCHAR uintformatW[] = {'%','u',0};
+    static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
+    static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
+    static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
+    static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
+    static const WCHAR maskW[] = {'M','a','s','k',0};
+    static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
+    UINT i;
+    WICBitmapPattern *patterns;
+    BYTE *patterns_ptr;
+    DWORD length, valuesize;
+
+    res = RegOpenKeyExW(info->classkey, patternsW, 0, KEY_READ, &patternskey);
+    if (res != ERROR_SUCCESS) return;
+
+    res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (res != ERROR_SUCCESS)
+    {
+        RegCloseKey(patternskey);
+        return;
+    }
+
+    patterns_size = pattern_count * sizeof(WICBitmapPattern);
+    patterns = heap_alloc(patterns_size);
+    if (!patterns)
+    {
+        RegCloseKey(patternskey);
+        return;
+    }
+
+    for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
+    {
+        snprintfW(subkeyname, 11, uintformatW, i);
+        res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
+        if (res != ERROR_SUCCESS) break;
+
+        valuesize = sizeof(ULONG);
+        res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL, &length, &valuesize);
+        if (res == ERROR_SUCCESS)
+        {
+            patterns_size += length*2;
+            patterns[i].Length = length;
+
+            valuesize = sizeof(BOOL);
+            res = RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
+                               &patterns[i].EndOfStream, &valuesize);
+            if (res) patterns[i].EndOfStream = 0;
+
+            patterns[i].Position.QuadPart = 0;
+            valuesize = sizeof(ULARGE_INTEGER);
+            res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
+                               &patterns[i].Position, &valuesize);
+        }
+
+        RegCloseKey(patternkey);
+    }
+
+    if (res != ERROR_SUCCESS || !(patterns_ptr = heap_realloc(patterns, patterns_size)))
+    {
+        heap_free(patterns);
+        RegCloseKey(patternskey);
+        return;
+    }
+    patterns = (WICBitmapPattern*)patterns_ptr;
+    patterns_ptr += pattern_count * sizeof(*patterns);
+
+    for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
+    {
+        snprintfW(subkeyname, 11, uintformatW, i);
+        res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
+        if (res != ERROR_SUCCESS) break;
+
+        length = patterns[i].Length;
+        patterns[i].Pattern = patterns_ptr;
+        valuesize = length;
+        res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
+                           patterns[i].Pattern, &valuesize);
+        patterns_ptr += length;
+
+        if (res == ERROR_SUCCESS)
+        {
+            patterns[i].Mask = patterns_ptr;
+            valuesize = length;
+            res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
+                               patterns[i].Mask, &valuesize);
+            patterns_ptr += length;
+        }
+
+        RegCloseKey(patternkey);
+    }
+
+    RegCloseKey(patternskey);
+
+    if (res != ERROR_SUCCESS)
+    {
+        heap_free(patterns);
+        return;
+    }
+
+    info->pattern_count = pattern_count;
+    info->patterns_size = patterns_size;
+    info->patterns = patterns;
+}
+
+static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
 {
     BitmapDecoderInfo *This;
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
+    This = heap_alloc_zero(sizeof(BitmapDecoderInfo));
     if (!This)
     {
         RegCloseKey(classkey);
         return E_OUTOFMEMORY;
     }
 
-    This->IWICBitmapDecoderInfo_iface.lpVtbl = &BitmapDecoderInfo_Vtbl;
-    This->ref = 1;
+    This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&BitmapDecoderInfo_Vtbl;
+    This->base.ref = 1;
     This->classkey = classkey;
-    memcpy(&This->clsid, clsid, sizeof(CLSID));
+    This->base.clsid = *clsid;
+
+    read_bitmap_patterns(This);
 
-    *ppIInfo = (IWICComponentInfo *)&This->IWICBitmapDecoderInfo_iface;
+    *ret = &This->base;
     return S_OK;
 }
 
 typedef struct {
-    IWICBitmapEncoderInfo IWICBitmapEncoderInfo_iface;
-    LONG ref;
+    ComponentInfo base;
     HKEY classkey;
-    CLSID clsid;
 } BitmapEncoderInfo;
 
 static inline BitmapEncoderInfo *impl_from_IWICBitmapEncoderInfo(IWICBitmapEncoderInfo *iface)
 {
-    return CONTAINING_RECORD(iface, BitmapEncoderInfo, IWICBitmapEncoderInfo_iface);
+    return CONTAINING_RECORD(iface, BitmapEncoderInfo, base.IWICComponentInfo_iface);
 }
 
 static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *iface, REFIID iid,
@@ -698,7 +729,7 @@ static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *if
         IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
         IsEqualIID(&IID_IWICBitmapEncoderInfo ,iid))
     {
-        *ppv = &This->IWICBitmapEncoderInfo_iface;
+        *ppv = &This->base.IWICComponentInfo_iface;
     }
     else
     {
@@ -713,7 +744,7 @@ static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *if
 static ULONG WINAPI BitmapEncoderInfo_AddRef(IWICBitmapEncoderInfo *iface)
 {
     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -723,7 +754,7 @@ static ULONG WINAPI BitmapEncoderInfo_AddRef(IWICBitmapEncoderInfo *iface)
 static ULONG WINAPI BitmapEncoderInfo_Release(IWICBitmapEncoderInfo *iface)
 {
     BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -753,8 +784,7 @@ static HRESULT WINAPI BitmapEncoderInfo_GetCLSID(IWICBitmapEncoderInfo *iface, C
     if (!pclsid)
         return E_INVALIDARG;
 
-    memcpy(pclsid, &This->clsid, sizeof(CLSID));
-
+    *pclsid = This->base.clsid;
     return S_OK;
 }
 
@@ -918,7 +948,7 @@ static HRESULT WINAPI BitmapEncoderInfo_CreateInstance(IWICBitmapEncoderInfo *if
 
     TRACE("(%p,%p)\n", iface, ppIBitmapEncoder);
 
-    return create_instance(&This->clsid, &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder);
+    return create_instance(&This->base.clsid, &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder);
 }
 
 static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = {
@@ -948,7 +978,7 @@ static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = {
     BitmapEncoderInfo_CreateInstance
 };
 
-static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
 {
     BitmapEncoderInfo *This;
 
@@ -959,25 +989,23 @@ static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWIC
         return E_OUTOFMEMORY;
     }
 
-    This->IWICBitmapEncoderInfo_iface.lpVtbl = &BitmapEncoderInfo_Vtbl;
-    This->ref = 1;
+    This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&BitmapEncoderInfo_Vtbl;
+    This->base.ref = 1;
     This->classkey = classkey;
-    memcpy(&This->clsid, clsid, sizeof(CLSID));
+    This->base.clsid = *clsid;
 
-    *ppIInfo = (IWICComponentInfo *)&This->IWICBitmapEncoderInfo_iface;
+    *ret = &This->base;
     return S_OK;
 }
 
 typedef struct {
-    IWICFormatConverterInfo IWICFormatConverterInfo_iface;
-    LONG ref;
+    ComponentInfo base;
     HKEY classkey;
-    CLSID clsid;
 } FormatConverterInfo;
 
 static inline FormatConverterInfo *impl_from_IWICFormatConverterInfo(IWICFormatConverterInfo *iface)
 {
-    return CONTAINING_RECORD(iface, FormatConverterInfo, IWICFormatConverterInfo_iface);
+    return CONTAINING_RECORD(iface, FormatConverterInfo, base.IWICComponentInfo_iface);
 }
 
 static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
@@ -992,7 +1020,7 @@ static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo
         IsEqualIID(&IID_IWICComponentInfo, iid) ||
         IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
     {
-        *ppv = &This->IWICFormatConverterInfo_iface;
+        *ppv = &This->base.IWICComponentInfo_iface;
     }
     else
     {
@@ -1007,7 +1035,7 @@ static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo
 static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
 {
     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -1017,7 +1045,7 @@ static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
 static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
 {
     FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -1047,8 +1075,7 @@ static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *ifac
     if (!pclsid)
         return E_INVALIDARG;
 
-    memcpy(pclsid, &This->clsid, sizeof(CLSID));
-
+    *pclsid = This->base.clsid;
     return S_OK;
 }
 
@@ -1125,7 +1152,7 @@ static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo
 
     TRACE("(%p,%p)\n", iface, ppIFormatConverter);
 
-    return create_instance(&This->clsid, &IID_IWICFormatConverter,
+    return create_instance(&This->base.clsid, &IID_IWICFormatConverter,
             (void**)ppIFormatConverter);
 }
 
@@ -1165,7 +1192,7 @@ static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
     FormatConverterInfo_CreateInstance
 };
 
-static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
 {
     FormatConverterInfo *This;
 
@@ -1176,25 +1203,23 @@ static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IW
         return E_OUTOFMEMORY;
     }
 
-    This->IWICFormatConverterInfo_iface.lpVtbl = &FormatConverterInfo_Vtbl;
-    This->ref = 1;
+    This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&FormatConverterInfo_Vtbl;
+    This->base.ref = 1;
     This->classkey = classkey;
-    memcpy(&This->clsid, clsid, sizeof(CLSID));
+    This->base.clsid = *clsid;
 
-    *ppIInfo = (IWICComponentInfo *)&This->IWICFormatConverterInfo_iface;
+    *ret = &This->base;
     return S_OK;
 }
 
 typedef struct {
-    IWICPixelFormatInfo2 IWICPixelFormatInfo2_iface;
-    LONG ref;
+    ComponentInfo base;
     HKEY classkey;
-    CLSID clsid;
 } PixelFormatInfo;
 
 static inline PixelFormatInfo *impl_from_IWICPixelFormatInfo2(IWICPixelFormatInfo2 *iface)
 {
-    return CONTAINING_RECORD(iface, PixelFormatInfo, IWICPixelFormatInfo2_iface);
+    return CONTAINING_RECORD(iface, PixelFormatInfo, base.IWICComponentInfo_iface);
 }
 
 static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface, REFIID iid,
@@ -1210,7 +1235,7 @@ static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface
         IsEqualIID(&IID_IWICPixelFormatInfo, iid) ||
         IsEqualIID(&IID_IWICPixelFormatInfo2 ,iid))
     {
-        *ppv = &This->IWICPixelFormatInfo2_iface;
+        *ppv = &This->base.IWICComponentInfo_iface;
     }
     else
     {
@@ -1225,7 +1250,7 @@ static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface
 static ULONG WINAPI PixelFormatInfo_AddRef(IWICPixelFormatInfo2 *iface)
 {
     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -1235,7 +1260,7 @@ static ULONG WINAPI PixelFormatInfo_AddRef(IWICPixelFormatInfo2 *iface)
 static ULONG WINAPI PixelFormatInfo_Release(IWICPixelFormatInfo2 *iface)
 {
     PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -1265,8 +1290,7 @@ static HRESULT WINAPI PixelFormatInfo_GetCLSID(IWICPixelFormatInfo2 *iface, CLSI
     if (!pclsid)
         return E_INVALIDARG;
 
-    memcpy(pclsid, &This->clsid, sizeof(CLSID));
-
+    *pclsid = This->base.clsid;
     return S_OK;
 }
 
@@ -1345,8 +1369,7 @@ static HRESULT WINAPI PixelFormatInfo_GetFormatGUID(IWICPixelFormatInfo2 *iface,
     if (!pFormat)
         return E_INVALIDARG;
 
-    *pFormat = This->clsid;
-
+    *pFormat = This->base.clsid;
     return S_OK;
 }
 
@@ -1459,7 +1482,7 @@ static const IWICPixelFormatInfo2Vtbl PixelFormatInfo_Vtbl = {
     PixelFormatInfo_GetNumericRepresentation
 };
 
-static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **ret)
 {
     PixelFormatInfo *This;
 
@@ -1470,26 +1493,45 @@ static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICCo
         return E_OUTOFMEMORY;
     }
 
-    This->IWICPixelFormatInfo2_iface.lpVtbl = &PixelFormatInfo_Vtbl;
-    This->ref = 1;
+    This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&PixelFormatInfo_Vtbl;
+    This->base.ref = 1;
     This->classkey = classkey;
-    memcpy(&This->clsid, clsid, sizeof(CLSID));
+    This->base.clsid = *clsid;
 
-    *ppIInfo = (IWICComponentInfo *)&This->IWICPixelFormatInfo2_iface;
+    *ret = &This->base;
     return S_OK;
 }
 
+struct metadata_container
+{
+    WICMetadataPattern *patterns;
+    UINT pattern_count;
+    UINT patterns_size;
+};
+
 typedef struct
 {
-    IWICMetadataReaderInfo IWICMetadataReaderInfo_iface;
-    LONG ref;
+    ComponentInfo base;
     HKEY classkey;
-    CLSID clsid;
+    GUID *container_formats;
+    struct metadata_container *containers;
+    UINT container_count;
 } MetadataReaderInfo;
 
+static struct metadata_container *get_metadata_container(MetadataReaderInfo *info, const GUID *guid)
+{
+    unsigned i;
+
+    for (i = 0; i < info->container_count; i++)
+        if (IsEqualGUID(info->container_formats + i, guid))
+            return info->containers + i;
+
+    return NULL;
+}
+
 static inline MetadataReaderInfo *impl_from_IWICMetadataReaderInfo(IWICMetadataReaderInfo *iface)
 {
-    return CONTAINING_RECORD(iface, MetadataReaderInfo, IWICMetadataReaderInfo_iface);
+    return CONTAINING_RECORD(iface, MetadataReaderInfo, base.IWICComponentInfo_iface);
 }
 
 static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo *iface,
@@ -1506,7 +1548,7 @@ static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo *
         IsEqualIID(&IID_IWICMetadataHandlerInfo, riid) ||
         IsEqualIID(&IID_IWICMetadataReaderInfo, riid))
     {
-        *ppv = &This->IWICMetadataReaderInfo_iface;
+        *ppv = &This->base.IWICComponentInfo_iface;
     }
     else
     {
@@ -1521,7 +1563,7 @@ static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo *
 static ULONG WINAPI MetadataReaderInfo_AddRef(IWICMetadataReaderInfo *iface)
 {
     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    ULONG ref = InterlockedIncrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
     return ref;
@@ -1530,13 +1572,18 @@ static ULONG WINAPI MetadataReaderInfo_AddRef(IWICMetadataReaderInfo *iface)
 static ULONG WINAPI MetadataReaderInfo_Release(IWICMetadataReaderInfo *iface)
 {
     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
+    ULONG ref = InterlockedDecrement(&This->base.ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
     if (!ref)
     {
+        unsigned i;
         RegCloseKey(This->classkey);
+        for (i = 0; i < This->container_count; i++)
+            heap_free(This->containers[i].patterns);
+        heap_free(This->containers);
+        heap_free(This->container_formats);
         HeapFree(GetProcessHeap(), 0, This);
     }
     return ref;
@@ -1560,7 +1607,7 @@ static HRESULT WINAPI MetadataReaderInfo_GetCLSID(IWICMetadataReaderInfo *iface,
     TRACE("(%p,%p)\n", iface, clsid);
 
     if (!clsid) return E_INVALIDARG;
-    *clsid = This->clsid;
+    *clsid = This->base.clsid;
     return S_OK;
 }
 
@@ -1637,10 +1684,20 @@ static HRESULT WINAPI MetadataReaderInfo_GetContainerFormats(IWICMetadataReaderI
     UINT length, GUID *formats, UINT *actual_length)
 {
     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
     TRACE("(%p,%u,%p,%p)\n", iface, length, formats, actual_length);
 
-    return ComponentInfo_GetGuidList(This->classkey, containers_keyname, length,
-        formats, actual_length);
+    if (!actual_length)
+        return E_INVALIDARG;
+
+    *actual_length = This->container_count;
+    if (formats)
+    {
+        if (This->container_count && length < This->container_count)
+            return WINCODEC_ERR_INSUFFICIENTBUFFER;
+        memcpy(formats, This->container_formats, This->container_count);
+    }
+    return S_OK;
 }
 
 static HRESULT WINAPI MetadataReaderInfo_GetDeviceManufacturer(IWICMetadataReaderInfo *iface,
@@ -1681,122 +1738,35 @@ static HRESULT WINAPI MetadataReaderInfo_DoesRequireFixedSize(IWICMetadataReader
 }
 
 static HRESULT WINAPI MetadataReaderInfo_GetPatterns(IWICMetadataReaderInfo *iface,
-    REFGUID container, UINT length, WICMetadataPattern *patterns, UINT *count, UINT *actual_length)
+    REFGUID container_guid, UINT length, WICMetadataPattern *patterns, UINT *count, UINT *actual_length)
 {
     MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
-    HRESULT hr=S_OK;
-    LONG res;
-    UINT pattern_count=0, patterns_size=0;
-    DWORD valuesize, patternsize;
-    BYTE *bPatterns=(BYTE*)patterns;
-    HKEY containers_key, guid_key, pattern_key;
-    WCHAR subkeyname[11];
-    WCHAR guidkeyname[39];
-    int i;
-    static const WCHAR uintformatW[] = {'%','u',0};
-    static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
-    static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
-    static const WCHAR maskW[] = {'M','a','s','k',0};
-    static const WCHAR dataoffsetW[] = {'D','a','t','a','O','f','f','s','e','t',0};
-
-    TRACE("(%p,%s,%u,%p,%p,%p)\n", iface, debugstr_guid(container), length, patterns, count, actual_length);
+    struct metadata_container *container;
 
-    if (!actual_length || !container) return E_INVALIDARG;
-
-    res = RegOpenKeyExW(This->classkey, containers_keyname, 0, KEY_READ, &containers_key);
-    if (res == ERROR_SUCCESS)
-    {
-        StringFromGUID2(container, guidkeyname, 39);
-
-        res = RegOpenKeyExW(containers_key, guidkeyname, 0, KEY_READ, &guid_key);
-        if (res == ERROR_FILE_NOT_FOUND) hr = WINCODEC_ERR_COMPONENTNOTFOUND;
-        else if (res != ERROR_SUCCESS) hr = HRESULT_FROM_WIN32(res);
-
-        RegCloseKey(containers_key);
-    }
-    else if (res == ERROR_FILE_NOT_FOUND) hr = WINCODEC_ERR_COMPONENTNOTFOUND;
-    else hr = HRESULT_FROM_WIN32(res);
-
-    if (SUCCEEDED(hr))
-    {
-        res = RegQueryInfoKeyW(guid_key, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-        if (res != ERROR_SUCCESS) hr = HRESULT_FROM_WIN32(res);
-
-        if (SUCCEEDED(hr))
-        {
-            patterns_size = pattern_count * sizeof(WICMetadataPattern);
+    TRACE("(%p,%s,%u,%p,%p,%p)\n", iface, debugstr_guid(container_guid), length, patterns, count, actual_length);
 
-            for (i=0; i<pattern_count; i++)
-            {
-                snprintfW(subkeyname, 11, uintformatW, i);
-                res = RegOpenKeyExW(guid_key, subkeyname, 0, KEY_READ, &pattern_key);
-                if (res == ERROR_SUCCESS)
-                {
-                    res = RegGetValueW(pattern_key, NULL, patternW, RRF_RT_REG_BINARY, NULL,
-                        NULL, &patternsize);
-                    patterns_size += patternsize*2;
-
-                    if ((length >= patterns_size) && (res == ERROR_SUCCESS))
-                    {
-                        patterns[i].Length = patternsize;
-
-                        patterns[i].DataOffset.QuadPart = 0;
-                        valuesize = sizeof(ULARGE_INTEGER);
-                        RegGetValueW(pattern_key, NULL, dataoffsetW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
-                            &patterns[i].DataOffset, &valuesize);
-
-                        patterns[i].Position.QuadPart = 0;
-                        valuesize = sizeof(ULARGE_INTEGER);
-                        res = RegGetValueW(pattern_key, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
-                            &patterns[i].Position, &valuesize);
-
-                        if (res == ERROR_SUCCESS)
-                        {
-                            patterns[i].Pattern = bPatterns+patterns_size-patternsize*2;
-                            valuesize = patternsize;
-                            res = RegGetValueW(pattern_key, NULL, patternW, RRF_RT_REG_BINARY, NULL,
-                                patterns[i].Pattern, &valuesize);
-                        }
-
-                        if (res == ERROR_SUCCESS)
-                        {
-                            patterns[i].Mask = bPatterns+patterns_size-patternsize;
-                            valuesize = patternsize;
-                            res = RegGetValueW(pattern_key, NULL, maskW, RRF_RT_REG_BINARY, NULL,
-                                patterns[i].Mask, &valuesize);
-                        }
-                    }
-
-                    RegCloseKey(pattern_key);
-                }
-                if (res != ERROR_SUCCESS)
-                {
-                    hr = HRESULT_FROM_WIN32(res);
-                    break;
-                }
-            }
-        }
+    if (!actual_length || !container_guid) return E_INVALIDARG;
 
-        RegCloseKey(guid_key);
-    }
+    if (!(container = get_metadata_container(This, container_guid)))
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
 
-    if (hr == S_OK)
+    *count = container->pattern_count;
+    *actual_length = container->patterns_size;
+    if (patterns)
     {
-        *count = pattern_count;
-        *actual_length = patterns_size;
-        if (patterns && length < patterns_size)
-            hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
+        if (container->patterns_size && length < container->patterns_size)
+            return WINCODEC_ERR_INSUFFICIENTBUFFER;
+        memcpy(patterns, container->patterns, container->patterns_size);
     }
-
-    return hr;
+    return S_OK;
 }
 
 static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *iface,
-    REFGUID container, IStream *stream, BOOL *matches)
+    REFGUID container_guid, IStream *stream, BOOL *matches)
 {
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+    struct metadata_container *container;
     HRESULT hr;
-    WICMetadataPattern *patterns;
-    UINT pattern_count=0, patterns_size=0;
     ULONG datasize=0;
     BYTE *data=NULL;
     ULONG bytesread;
@@ -1804,24 +1774,18 @@ static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *
     LARGE_INTEGER seekpos;
     ULONG pos;
 
-    TRACE("(%p,%s,%p,%p)\n", iface, debugstr_guid(container), stream, matches);
+    TRACE("(%p,%s,%p,%p)\n", iface, debugstr_guid(container_guid), stream, matches);
 
-    hr = MetadataReaderInfo_GetPatterns(iface, container, 0, NULL, &pattern_count, &patterns_size);
-    if (FAILED(hr)) return hr;
-
-    patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
-    if (!patterns) return E_OUTOFMEMORY;
-
-    hr = MetadataReaderInfo_GetPatterns(iface, container, patterns_size, patterns, &pattern_count, &patterns_size);
-    if (FAILED(hr)) goto end;
+    if (!(container = get_metadata_container(This, container_guid)))
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
 
-    for (i=0; i<pattern_count; i++)
+    for (i=0; i < container->pattern_count; i++)
     {
-        if (datasize < patterns[i].Length)
+        if (datasize < container->patterns[i].Length)
         {
             HeapFree(GetProcessHeap(), 0, data);
-            datasize = patterns[i].Length;
-            data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
+            datasize = container->patterns[i].Length;
+            data = HeapAlloc(GetProcessHeap(), 0, container->patterns[i].Length);
             if (!data)
             {
                 hr = E_OUTOFMEMORY;
@@ -1829,21 +1793,21 @@ static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *
             }
         }
 
-        seekpos.QuadPart = patterns[i].Position.QuadPart;
+        seekpos.QuadPart = container->patterns[i].Position.QuadPart;
         hr = IStream_Seek(stream, seekpos, STREAM_SEEK_SET, NULL);
         if (FAILED(hr)) break;
 
-        hr = IStream_Read(stream, data, patterns[i].Length, &bytesread);
-        if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
+        hr = IStream_Read(stream, data, container->patterns[i].Length, &bytesread);
+        if (hr == S_FALSE || (hr == S_OK && bytesread != container->patterns[i].Length)) /* past end of stream */
             continue;
         if (FAILED(hr)) break;
 
-        for (pos=0; pos<patterns[i].Length; pos++)
+        for (pos=0; pos < container->patterns[i].Length; pos++)
         {
-            if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
+            if ((data[pos] & container->patterns[i].Mask[pos]) != container->patterns[i].Pattern[pos])
                 break;
         }
-        if (pos == patterns[i].Length) /* matches pattern */
+        if (pos == container->patterns[i].Length) /* matches pattern */
         {
             hr = S_OK;
             *matches = TRUE;
@@ -1851,14 +1815,12 @@ static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *
         }
     }
 
-    if (i == pattern_count) /* does not match any pattern */
+    if (i == container->pattern_count) /* does not match any pattern */
     {
         hr = S_OK;
         *matches = FALSE;
     }
 
-end:
-    HeapFree(GetProcessHeap(), 0, patterns);
     HeapFree(GetProcessHeap(), 0, data);
 
     return hr;
@@ -1871,7 +1833,7 @@ static HRESULT WINAPI MetadataReaderInfo_CreateInstance(IWICMetadataReaderInfo *
 
     TRACE("(%p,%p)\n", iface, reader);
 
-    return create_instance(&This->clsid, &IID_IWICMetadataReader, (void **)reader);
+    return create_instance(&This->base.clsid, &IID_IWICMetadataReader, (void **)reader);
 }
 
 static const IWICMetadataReaderInfoVtbl MetadataReaderInfo_Vtbl = {
@@ -1898,23 +1860,180 @@ static const IWICMetadataReaderInfoVtbl MetadataReaderInfo_Vtbl = {
     MetadataReaderInfo_CreateInstance
 };
 
-static HRESULT MetadataReaderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **info)
+static void read_metadata_patterns(MetadataReaderInfo *info, GUID *container_guid,
+                                   struct metadata_container *container)
+{
+    UINT pattern_count=0, patterns_size=0;
+    WCHAR subkeyname[11], guidkeyname[39];
+    LONG res;
+    HKEY containers_key, guid_key, patternkey;
+    static const WCHAR uintformatW[] = {'%','u',0};
+    static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
+    static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
+    static const WCHAR maskW[] = {'M','a','s','k',0};
+    static const WCHAR dataoffsetW[] = {'D','a','t','a','O','f','f','s','e','t',0};
+    UINT i;
+    WICMetadataPattern *patterns;
+    BYTE *patterns_ptr;
+    DWORD length, valuesize;
+
+    res = RegOpenKeyExW(info->classkey, containers_keyname, 0, KEY_READ, &containers_key);
+    if (res != ERROR_SUCCESS) return;
+
+    StringFromGUID2(container_guid, guidkeyname, 39);
+    res = RegOpenKeyExW(containers_key, guidkeyname, 0, KEY_READ, &guid_key);
+    RegCloseKey(containers_key);
+    if (res != ERROR_SUCCESS) return;
+
+    res = RegQueryInfoKeyW(guid_key, NULL, NULL, NULL, &pattern_count,
+                           NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (res != ERROR_SUCCESS)
+    {
+        RegCloseKey(guid_key);
+        return;
+    }
+
+    patterns_size = pattern_count * sizeof(WICMetadataPattern);
+    patterns = heap_alloc(patterns_size);
+    if (!patterns)
+    {
+        RegCloseKey(guid_key);
+        return;
+    }
+
+    for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
+    {
+        snprintfW(subkeyname, 11, uintformatW, i);
+        res = RegOpenKeyExW(guid_key, subkeyname, 0, KEY_READ, &patternkey);
+        if (res != ERROR_SUCCESS) break;
+
+        res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL, NULL, &length);
+        if (res == ERROR_SUCCESS)
+        {
+            patterns_size += length*2;
+            patterns[i].Length = length;
+
+            valuesize = sizeof(DWORD64);
+            res = RegGetValueW(patternkey, NULL, dataoffsetW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
+                               &patterns[i].DataOffset, &valuesize);
+            if (res) patterns[i].DataOffset.QuadPart = 0;
+
+            patterns[i].Position.QuadPart = 0;
+            valuesize = sizeof(DWORD64);
+            res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
+                               &patterns[i].Position, &valuesize);
+        }
+
+        RegCloseKey(patternkey);
+    }
+
+    if (res != ERROR_SUCCESS || !(patterns_ptr = heap_realloc(patterns, patterns_size)))
+    {
+        heap_free(patterns);
+        RegCloseKey(guid_key);
+        return;
+    }
+    patterns = (WICMetadataPattern*)patterns_ptr;
+    patterns_ptr += pattern_count * sizeof(*patterns);
+
+    for (i=0; res == ERROR_SUCCESS && i < pattern_count; i++)
+    {
+        snprintfW(subkeyname, 11, uintformatW, i);
+        res = RegOpenKeyExW(guid_key, subkeyname, 0, KEY_READ, &patternkey);
+        if (res != ERROR_SUCCESS) break;
+
+        length = patterns[i].Length;
+        patterns[i].Pattern = patterns_ptr;
+        valuesize = length;
+        res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
+                           patterns[i].Pattern, &valuesize);
+        patterns_ptr += length;
+
+        if (res == ERROR_SUCCESS)
+        {
+            patterns[i].Mask = patterns_ptr;
+            valuesize = length;
+            res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
+                               patterns[i].Mask, &valuesize);
+            patterns_ptr += length;
+        }
+
+        RegCloseKey(patternkey);
+    }
+
+    RegCloseKey(guid_key);
+
+    if (res != ERROR_SUCCESS)
+    {
+        heap_free(patterns);
+        return;
+    }
+
+    container->pattern_count = pattern_count;
+    container->patterns_size = patterns_size;
+    container->patterns = patterns;
+}
+
+static BOOL read_metadata_info(MetadataReaderInfo *info)
+{
+    UINT format_count;
+    GUID *formats;
+    HRESULT hr;
+
+    hr = ComponentInfo_GetGuidList(info->classkey, containers_keyname, 0, NULL, &format_count);
+    if (FAILED(hr)) return TRUE;
+
+    formats = heap_calloc(format_count, sizeof(*formats));
+    if (!formats) return FALSE;
+
+    hr = ComponentInfo_GetGuidList(info->classkey, containers_keyname, format_count, formats,
+                                   &format_count);
+    if (FAILED(hr))
+    {
+        heap_free(formats);
+        return FALSE;
+    }
+
+    info->container_formats = formats;
+    info->container_count = format_count;
+
+    if (format_count)
+    {
+        unsigned i;
+
+        info->containers = heap_calloc(format_count, sizeof(*info->containers));
+        if (!info->containers) return FALSE;
+
+        for (i = 0; i < format_count; i++)
+            read_metadata_patterns(info, info->container_formats + i, info->containers + i);
+    }
+
+    return TRUE;
+}
+
+static HRESULT MetadataReaderInfo_Constructor(HKEY classkey, REFCLSID clsid, ComponentInfo **info)
 {
     MetadataReaderInfo *This;
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+    This = heap_alloc_zero(sizeof(*This));
     if (!This)
     {
         RegCloseKey(classkey);
         return E_OUTOFMEMORY;
     }
 
-    This->IWICMetadataReaderInfo_iface.lpVtbl = &MetadataReaderInfo_Vtbl;
-    This->ref = 1;
+    This->base.IWICComponentInfo_iface.lpVtbl = (const IWICComponentInfoVtbl*)&MetadataReaderInfo_Vtbl;
+    This->base.ref = 1;
     This->classkey = classkey;
-    This->clsid = *clsid;
+    This->base.clsid = *clsid;
+
+    if (!read_metadata_info(This))
+    {
+        IWICComponentInfo_Release(&This->base.IWICComponentInfo_iface);
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
+    }
 
-    *info = (IWICComponentInfo *)&This->IWICMetadataReaderInfo_iface;
+    *info = &This->base;
     return S_OK;
 }
 
@@ -1924,7 +2043,7 @@ static const WCHAR instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
 struct category {
     WICComponentType type;
     const GUID *catid;
-    HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
+    HRESULT (*constructor)(HKEY,REFCLSID,ComponentInfo**);
 };
 
 static const struct category categories[] = {
@@ -1936,8 +2055,27 @@ static const struct category categories[] = {
     {0}
 };
 
+static int ComponentInfo_Compare(const void *key, const struct wine_rb_entry *entry)
+{
+    ComponentInfo *info = WINE_RB_ENTRY_VALUE(entry, ComponentInfo, entry);
+    return memcmp(key, &info->clsid, sizeof(info->clsid));
+}
+
+static struct wine_rb_tree component_info_cache = { ComponentInfo_Compare };
+
+static CRITICAL_SECTION component_info_cache_cs;
+static CRITICAL_SECTION_DEBUG component_info_cache_cs_dbg =
+{
+    0, 0, &component_info_cache_cs,
+    { &component_info_cache_cs_dbg.ProcessLocksList, &component_info_cache_cs_dbg.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": component_info_cache") }
+};
+static CRITICAL_SECTION component_info_cache_cs = { &component_info_cache_cs_dbg, -1, 0, 0, 0, 0 };
+
 HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
 {
+    struct wine_rb_entry *cache_entry;
+    ComponentInfo *info;
     HKEY clsidkey;
     HKEY classkey;
     HKEY catidkey;
@@ -1948,9 +2086,23 @@ HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
     BOOL found = FALSE;
     HRESULT hr;
 
+    EnterCriticalSection(&component_info_cache_cs);
+
+    cache_entry = wine_rb_get(&component_info_cache, clsid);
+    if(cache_entry)
+    {
+        info = WINE_RB_ENTRY_VALUE(cache_entry, ComponentInfo, entry);
+        IWICComponentInfo_AddRef(*ppIInfo = &info->IWICComponentInfo_iface);
+        LeaveCriticalSection(&component_info_cache_cs);
+        return S_OK;
+    }
+
     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
     if (res != ERROR_SUCCESS)
+    {
+        LeaveCriticalSection(&component_info_cache_cs);
         return HRESULT_FROM_WIN32(res);
+    }
 
     for (category=categories; category->type; category++)
     {
@@ -1979,7 +2131,7 @@ HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
     {
         res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
         if (res == ERROR_SUCCESS)
-            hr = category->constructor(classkey, clsid, ppIInfo);
+            hr = category->constructor(classkey, clsid, &info);
         else
             hr = HRESULT_FROM_WIN32(res);
     }
@@ -1991,6 +2143,35 @@ HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
 
     RegCloseKey(clsidkey);
 
+    if (SUCCEEDED(hr))
+    {
+        wine_rb_put(&component_info_cache, clsid, &info->entry);
+        IWICComponentInfo_AddRef(*ppIInfo = &info->IWICComponentInfo_iface);
+    }
+    LeaveCriticalSection(&component_info_cache_cs);
+    return hr;
+}
+
+void ReleaseComponentInfos(void)
+{
+    ComponentInfo *info, *next_info;
+    WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(info, next_info, &component_info_cache, ComponentInfo, entry)
+        IWICComponentInfo_Release(&info->IWICComponentInfo_iface);
+}
+
+HRESULT get_decoder_info(const CLSID *clsid, IWICBitmapDecoderInfo **info)
+{
+    IWICComponentInfo *compinfo;
+    HRESULT hr;
+
+    hr = CreateComponentInfo(clsid, &compinfo);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void **)info);
+
+    IWICComponentInfo_Release(compinfo);
+
     return hr;
 }
 
index 0069bdf..26dc76c 100644 (file)
@@ -50,6 +50,7 @@
 
 #include "wincodecs_private.h"
 
+#include "wine/heap.h"
 #include "wine/debug.h"
 #include "wine/library.h"
 
@@ -155,6 +156,7 @@ typedef struct {
     struct jpeg_error_mgr jerr;
     struct jpeg_source_mgr source_mgr;
     BYTE source_buffer[1024];
+    UINT bpp, stride;
     BYTE *image_data;
     CRITICAL_SECTION lock;
 } JpegDecoder;
@@ -303,6 +305,8 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
     int ret;
     LARGE_INTEGER seek;
     jmp_buf jmpbuf;
+    UINT data_size, i;
+
     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
 
     EnterCriticalSection(&This->lock);
@@ -381,6 +385,55 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
         return E_FAIL;
     }
 
+    if (This->cinfo.out_color_space == JCS_GRAYSCALE) This->bpp = 8;
+    else if (This->cinfo.out_color_space == JCS_CMYK) This->bpp = 32;
+    else This->bpp = 24;
+
+    This->stride = (This->bpp * This->cinfo.output_width + 7) / 8;
+    data_size = This->stride * This->cinfo.output_height;
+
+    This->image_data = heap_alloc(data_size);
+    if (!This->image_data)
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_OUTOFMEMORY;
+    }
+
+    while (This->cinfo.output_scanline < This->cinfo.output_height)
+    {
+        UINT first_scanline = This->cinfo.output_scanline;
+        UINT max_rows;
+        JSAMPROW out_rows[4];
+        JDIMENSION ret;
+
+        max_rows = min(This->cinfo.output_height-first_scanline, 4);
+        for (i=0; i<max_rows; i++)
+            out_rows[i] = This->image_data + This->stride * (first_scanline+i);
+
+        ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
+        if (ret == 0)
+        {
+            ERR("read_scanlines failed\n");
+            LeaveCriticalSection(&This->lock);
+            return E_FAIL;
+        }
+    }
+
+    if (This->bpp == 24)
+    {
+        /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
+        reverse_bgr8(3, This->image_data,
+            This->cinfo.output_width, This->cinfo.output_height,
+            This->stride);
+    }
+
+    if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
+    {
+        /* Adobe JPEG's have inverted CMYK data. */
+        for (i=0; i<data_size; i++)
+            This->image_data[i] ^= 0xff;
+    }
+
     This->initialized = TRUE;
 
     LeaveCriticalSection(&This->lock);
@@ -398,20 +451,9 @@ static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICJpegDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICJpegDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
@@ -601,104 +643,11 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
     JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
-    UINT bpp;
-    UINT stride;
-    UINT data_size;
-    UINT max_row_needed;
-    jmp_buf jmpbuf;
-    WICRect rect;
-    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
-
-    if (!prc)
-    {
-        rect.X = 0;
-        rect.Y = 0;
-        rect.Width = This->cinfo.output_width;
-        rect.Height = This->cinfo.output_height;
-        prc = &rect;
-    }
-    else
-    {
-        if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->cinfo.output_width ||
-            prc->Y+prc->Height > This->cinfo.output_height)
-            return E_INVALIDARG;
-    }
-
-    if (This->cinfo.out_color_space == JCS_GRAYSCALE) bpp = 8;
-    else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
-    else bpp = 24;
-
-    stride = bpp * This->cinfo.output_width;
-    data_size = stride * This->cinfo.output_height;
 
-    max_row_needed = prc->Y + prc->Height;
-    if (max_row_needed > This->cinfo.output_height) return E_INVALIDARG;
-
-    EnterCriticalSection(&This->lock);
-
-    if (!This->image_data)
-    {
-        This->image_data = HeapAlloc(GetProcessHeap(), 0, data_size);
-        if (!This->image_data)
-        {
-            LeaveCriticalSection(&This->lock);
-            return E_OUTOFMEMORY;
-        }
-    }
-
-    This->cinfo.client_data = jmpbuf;
-
-    if (setjmp(jmpbuf))
-    {
-        LeaveCriticalSection(&This->lock);
-        return E_FAIL;
-    }
-
-    while (max_row_needed > This->cinfo.output_scanline)
-    {
-        UINT first_scanline = This->cinfo.output_scanline;
-        UINT max_rows;
-        JSAMPROW out_rows[4];
-        UINT i;
-        JDIMENSION ret;
-
-        max_rows = min(This->cinfo.output_height-first_scanline, 4);
-        for (i=0; i<max_rows; i++)
-            out_rows[i] = This->image_data + stride * (first_scanline+i);
-
-        ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
-
-        if (ret == 0)
-        {
-            ERR("read_scanlines failed\n");
-            LeaveCriticalSection(&This->lock);
-            return E_FAIL;
-        }
-
-        if (bpp == 24)
-        {
-            /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
-            reverse_bgr8(3, This->image_data + stride * first_scanline,
-                This->cinfo.output_width, This->cinfo.output_scanline - first_scanline,
-                stride);
-        }
-
-        if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
-        {
-            DWORD *pDwordData = (DWORD*) (This->image_data + stride * first_scanline);
-            DWORD *pDwordDataEnd = (DWORD*) (This->image_data + This->cinfo.output_scanline * stride);
-
-            /* Adobe JPEG's have inverted CMYK data. */
-            while(pDwordData < pDwordDataEnd)
-                *pDwordData++ ^= 0xffffffff;
-        }
-
-    }
-
-    LeaveCriticalSection(&This->lock);
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
 
-    return copy_pixels(bpp, This->image_data,
-        This->cinfo.output_width, This->cinfo.output_height, stride,
+    return copy_pixels(This->bpp, This->image_data,
+        This->cinfo.output_width, This->cinfo.output_height, This->stride,
         prc, cbStride, cbBufferSize, pbBuffer);
 }
 
index 3bed565..6f781b8 100644 (file)
@@ -42,6 +42,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             break;
+        case DLL_PROCESS_DETACH:
+            ReleaseComponentInfos();
+            break;
     }
 
     return WIC_DllMain(hinstDLL, fdwReason, lpvReserved);
index 54be5ed..42c905c 100644 (file)
@@ -829,20 +829,9 @@ static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICPngDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICPngDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
index 7f4c241..144e085 100644 (file)
@@ -25,6 +25,7 @@
 #include "wincodecs_private.h"
 
 #include <wine/debug.h>
+#include <wine/heap.h>
 #include <wine/library.h>
 
 #endif /* !WINCODECS_PRECOMP_H */
index ec7fa23..b3d9aea 100644 (file)
@@ -360,20 +360,9 @@ static HRESULT WINAPI TgaDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI TgaDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WineTgaDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WineTgaDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI TgaDecoder_CopyPalette(IWICBitmapDecoder *iface,
index c23594f..d1ee440 100644 (file)
@@ -738,20 +738,9 @@ static HRESULT WINAPI TiffDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI TiffDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    HRESULT hr;
-    IWICComponentInfo *compinfo;
-
     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
 
-    hr = CreateComponentInfo(&CLSID_WICTiffDecoder, &compinfo);
-    if (FAILED(hr)) return hr;
-
-    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
-        (void**)ppIDecoderInfo);
-
-    IWICComponentInfo_Release(compinfo);
-
-    return hr;
+    return get_decoder_info(&CLSID_WICTiffDecoder, ppIDecoderInfo);
 }
 
 static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface,
index 2f9f6d0..2645204 100644 (file)
@@ -155,7 +155,7 @@ extern HRESULT IcnsEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDE
 extern HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
 
 extern HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
-    UINT stride, UINT datasize, BYTE *bits,
+    UINT stride, UINT datasize, void *view, UINT offset,
     REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
     IWICBitmap **ppIBitmap) DECLSPEC_HIDDEN;
 extern HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) DECLSPEC_HIDDEN;
@@ -188,7 +188,9 @@ extern HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count,
                                   IPropertyBag2 **property) DECLSPEC_HIDDEN;
 
 extern HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo) DECLSPEC_HIDDEN;
+extern void ReleaseComponentInfos(void) DECLSPEC_HIDDEN;
 extern HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown) DECLSPEC_HIDDEN;
+extern HRESULT get_decoder_info(REFCLSID clsid, IWICBitmapDecoderInfo **info) DECLSPEC_HIDDEN;
 
 typedef struct BmpDecoder BmpDecoder;
 
index b3042fd..f78e35a 100644 (file)
@@ -196,7 +196,7 @@ reactos/dll/win32/version             # Synced to WineStaging-3.9
 reactos/dll/win32/vssapi              # Synced to WineStaging-2.9
 reactos/dll/win32/wbemdisp            # Synced to WineStaging-3.3
 reactos/dll/win32/wbemprox            # Synced to WineStaging-3.9
-reactos/dll/win32/windowscodecs       # Synced to WineStaging-3.3
+reactos/dll/win32/windowscodecs       # Synced to WineStaging-3.9
 reactos/dll/win32/windowscodecsext    # Synced to WineStaging-2.9
 reactos/dll/win32/winemp3.acm         # Synced to WineStaging-3.3
 reactos/dll/win32/wing32              # Synced to WineStaging-3.3