[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[reactos.git] / dll / win32 / windowscodecs / regsvr.c
index c5828a6..aba6c0a 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define NONAMELESSUNION
-#define NONAMELESSSTRUCT
-#define COBJMACROS
-#include <stdarg.h>
-#include <string.h>
+#include "wincodecs_private.h"
 
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winreg.h"
-#include "winerror.h"
-
-#include "objbase.h"
-#include "ocidl.h"
-#include "wincodec.h"
-
-#include "wine/debug.h"
-#include "wine/unicode.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+#include <shlwapi.h>
 
 /***********************************************************************
  *             interface for self-registering
  */
-struct regsvr_coclass
-{
-    CLSID const *clsid;                /* NULL for end of list */
-    LPCSTR name;               /* can be NULL to omit */
-    LPCSTR ips;                        /* can be NULL to omit */
-    LPCSTR ips32;              /* can be NULL to omit */
-    LPCSTR ips32_tmodel;       /* can be NULL to omit */
-    LPCSTR progid;             /* can be NULL to omit */
-    LPCSTR viprogid;           /* can be NULL to omit */
-    LPCSTR progid_extra;       /* can be NULL to omit */
-};
-
-static HRESULT register_coclasses(struct regsvr_coclass const *list);
-static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
-
 struct decoder_pattern
 {
     DWORD length;    /* 0 for end of list */
@@ -72,6 +39,7 @@ struct regsvr_decoder
     LPCSTR friendlyname;
     LPCSTR version;
     GUID const *vendor;
+    GUID const *container_format;
     LPCSTR mimetypes;
     LPCSTR extensions;
     GUID const * const *formats;
@@ -81,6 +49,22 @@ struct regsvr_decoder
 static HRESULT register_decoders(struct regsvr_decoder const *list);
 static HRESULT unregister_decoders(struct regsvr_decoder const *list);
 
+struct regsvr_encoder
+{
+    CLSID const *clsid;         /* NULL for end of list */
+    LPCSTR author;
+    LPCSTR friendlyname;
+    LPCSTR version;
+    GUID const *vendor;
+    GUID const *container_format;
+    LPCSTR mimetypes;
+    LPCSTR extensions;
+    GUID const * const *formats;
+};
+
+static HRESULT register_encoders(struct regsvr_encoder const *list);
+static HRESULT unregister_encoders(struct regsvr_encoder const *list);
+
 struct regsvr_converter
 {
     CLSID const *clsid;         /* NULL for end of list */
@@ -94,196 +78,326 @@ struct regsvr_converter
 static HRESULT register_converters(struct regsvr_converter const *list);
 static HRESULT unregister_converters(struct regsvr_converter const *list);
 
+struct metadata_pattern
+{
+    DWORD position;
+    DWORD length;
+    const BYTE *pattern;
+    const BYTE *mask;
+    DWORD data_offset;
+};
+
+struct reader_containers
+{
+    GUID const *format;
+    const struct metadata_pattern *patterns;
+};
+
+struct regsvr_metadatareader
+{
+    CLSID const *clsid;         /* NULL for end of list */
+    LPCSTR author;
+    LPCSTR friendlyname;
+    LPCSTR version;
+    LPCSTR specversion;
+    GUID const *vendor;
+    GUID const *metadata_format;
+    DWORD requires_fullstream;
+    DWORD supports_padding;
+    DWORD requires_fixedsize;
+    const struct reader_containers *containers;
+};
+
+static HRESULT register_metadatareaders(struct regsvr_metadatareader const *list);
+static HRESULT unregister_metadatareaders(struct regsvr_metadatareader const *list);
+
+struct regsvr_pixelformat
+{
+    CLSID const *clsid;         /* NULL for end of list */
+    LPCSTR author;
+    LPCSTR friendlyname;
+    LPCSTR version;
+    GUID const *vendor;
+    UINT bitsperpixel;
+    UINT channelcount;
+    BYTE const * const *channelmasks;
+    WICPixelFormatNumericRepresentation numericrepresentation;
+    UINT supportsalpha;
+};
+
+static HRESULT register_pixelformats(struct regsvr_pixelformat const *list);
+static HRESULT unregister_pixelformats(struct regsvr_pixelformat const *list);
+
 /***********************************************************************
  *             static string constants
  */
-static WCHAR const clsid_keyname[6] = {
+static const WCHAR clsid_keyname[] = {
     'C', 'L', 'S', 'I', 'D', 0 };
-static WCHAR const curver_keyname[7] = {
-    'C', 'u', 'r', 'V', 'e', 'r', 0 };
-static WCHAR const ips_keyname[13] = {
-    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
-    0 };
-static WCHAR const ips32_keyname[15] = {
-    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
-    '3', '2', 0 };
-static WCHAR const progid_keyname[7] = {
-    'P', 'r', 'o', 'g', 'I', 'D', 0 };
-static WCHAR const viprogid_keyname[25] = {
-    'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
-    'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
-    0 };
-static char const tmodel_valuename[] = "ThreadingModel";
-static char const author_valuename[] = "Author";
-static char const friendlyname_valuename[] = "FriendlyName";
-static WCHAR const vendor_valuename[] = {'V','e','n','d','o','r',0};
-static char const version_valuename[] = "Version";
-static char const mimetypes_valuename[] = "MimeTypes";
-static char const extensions_valuename[] = "FileExtensions";
-static WCHAR const formats_keyname[] = {'F','o','r','m','a','t','s',0};
-static WCHAR const patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
-static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
-static WCHAR const clsid_valuename[] = {'C','L','S','I','D',0};
-static char const length_valuename[] = "Length";
-static char const position_valuename[] = "Position";
-static char const pattern_valuename[] = "Pattern";
-static char const mask_valuename[] = "Mask";
-static char const endofstream_valuename[] = "EndOfStream";
-static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
-
-/***********************************************************************
- *             static helper functions
- */
-static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
-                                  WCHAR const *value);
-static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
-                                  char const *value);
-static LONG register_progid(WCHAR const *clsid,
-                           char const *progid, char const *curver_progid,
-                           char const *name, char const *extra);
+static const char author_valuename[] = "Author";
+static const char friendlyname_valuename[] = "FriendlyName";
+static const WCHAR vendor_valuename[] = {'V','e','n','d','o','r',0};
+static const WCHAR containerformat_valuename[] = {'C','o','n','t','a','i','n','e','r','F','o','r','m','a','t',0};
+static const char version_valuename[] = "Version";
+static const char mimetypes_valuename[] = "MimeTypes";
+static const char extensions_valuename[] = "FileExtensions";
+static const WCHAR formats_keyname[] = {'F','o','r','m','a','t','s',0};
+static const WCHAR patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
+static const WCHAR instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
+static const WCHAR clsid_valuename[] = {'C','L','S','I','D',0};
+static const char length_valuename[] = "Length";
+static const char position_valuename[] = "Position";
+static const char pattern_valuename[] = "Pattern";
+static const char mask_valuename[] = "Mask";
+static const char endofstream_valuename[] = "EndOfStream";
+static const WCHAR pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
+static const WCHAR metadataformat_valuename[] = {'M','e','t','a','d','a','t','a','F','o','r','m','a','t',0};
+static const char specversion_valuename[] = "SpecVersion";
+static const char requiresfullstream_valuename[] = "RequiresFullStream";
+static const char supportspadding_valuename[] = "SupportsPadding";
+static const char requiresfixedsize_valuename[] = "FixedSize";
+static const WCHAR containers_keyname[] = {'C','o','n','t','a','i','n','e','r','s',0};
+static const char dataoffset_valuename[] = "DataOffset";
+static const char bitsperpixel_valuename[] = "BitLength";
+static const char channelcount_valuename[] = "ChannelCount";
+static const char numericrepresentation_valuename[] = "NumericRepresentation";
+static const char supportstransparency_valuename[] = "SupportsTransparency";
+static const WCHAR channelmasks_keyname[] = {'C','h','a','n','n','e','l','M','a','s','k','s',0};
 
 /***********************************************************************
- *             register_coclasses
+ *             register_decoders
  */
-static HRESULT register_coclasses(struct regsvr_coclass const *list)
+static HRESULT register_decoders(struct regsvr_decoder const *list)
 {
     LONG res = ERROR_SUCCESS;
     HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY decoders_key;
+    HKEY instance_key;
 
     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
                          KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
     if (res != ERROR_SUCCESS) goto error_return;
 
     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
-       WCHAR buf[39];
        HKEY clsid_key;
+       HKEY instance_clsid_key;
 
        StringFromGUID2(list->clsid, buf, 39);
        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
                              KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
        if (res != ERROR_SUCCESS) goto error_close_coclass_key;
 
-       if (list->name) {
-           res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
-                                (CONST BYTE*)(list->name),
-                                strlen(list->name) + 1);
-           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+       if (res == ERROR_SUCCESS) {
+           res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+           RegCloseKey(instance_clsid_key);
        }
+       if (res != ERROR_SUCCESS) goto error_close_clsid_key;
 
-       if (list->ips) {
-           res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+        if (list->author) {
+           res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->author,
+                                strlen(list->author) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-       }
-
-       if (list->ips32) {
-           HKEY ips32_key;
+        }
 
-           res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
-                                 KEY_READ | KEY_WRITE, NULL,
-                                 &ips32_key, NULL);
+        if (list->friendlyname) {
+           res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->friendlyname,
+                                strlen(list->friendlyname) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
 
-           res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
-                                (CONST BYTE*)list->ips32,
-                                lstrlenA(list->ips32) + 1);
-           if (res == ERROR_SUCCESS && list->ips32_tmodel)
-               res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
-                                    (CONST BYTE*)list->ips32_tmodel,
-                                    strlen(list->ips32_tmodel) + 1);
-           RegCloseKey(ips32_key);
+        if (list->vendor) {
+            StringFromGUID2(list->vendor, buf, 39);
+           res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-       }
+        }
 
-       if (list->progid) {
-           res = register_key_defvalueA(clsid_key, progid_keyname,
-                                        list->progid);
+        if (list->container_format) {
+            StringFromGUID2(list->container_format, buf, 39);
+           res = RegSetValueExW(clsid_key, containerformat_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
 
-           res = register_progid(buf, list->progid, NULL,
-                                 list->name, list->progid_extra);
+        if (list->version) {
+           res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->version,
+                                strlen(list->version) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-       }
+        }
 
-       if (list->viprogid) {
-           res = register_key_defvalueA(clsid_key, viprogid_keyname,
-                                        list->viprogid);
+        if (list->mimetypes) {
+           res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->mimetypes,
+                                strlen(list->mimetypes) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
 
-           res = register_progid(buf, list->viprogid, list->progid,
-                                 list->name, list->progid_extra);
+        if (list->extensions) {
+           res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->extensions,
+                                strlen(list->extensions) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-       }
+        }
+
+        if (list->formats) {
+            HKEY formats_key;
+            GUID const * const *format;
+
+            res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (format=list->formats; *format; ++format)
+            {
+                HKEY format_key;
+                StringFromGUID2(*format, buf, 39);
+                res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+                RegCloseKey(format_key);
+            }
+            RegCloseKey(formats_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->patterns) {
+            HKEY patterns_key;
+            int i;
+
+            res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (i=0; list->patterns[i].length; i++)
+            {
+                HKEY pattern_key;
+                static const WCHAR int_format[] = {'%','i',0};
+                snprintfW(buf, 39, int_format, i);
+                res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+               res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
+                                     (const BYTE*)&list->patterns[i].length, 4);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
+                                         (const BYTE*)&list->patterns[i].position, 4);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
+                                        list->patterns[i].pattern,
+                                        list->patterns[i].length);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
+                                        list->patterns[i].mask,
+                                        list->patterns[i].length);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
+                                         (const BYTE*)&list->patterns[i].endofstream, 4);
+                RegCloseKey(pattern_key);
+            }
+            RegCloseKey(patterns_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
 
     error_close_clsid_key:
        RegCloseKey(clsid_key);
     }
 
 error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(decoders_key);
     RegCloseKey(coclass_key);
 error_return:
     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
 }
 
 /***********************************************************************
- *             unregister_coclasses
+ *             unregister_decoders
  */
-static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+static HRESULT unregister_decoders(struct regsvr_decoder const *list)
 {
     LONG res = ERROR_SUCCESS;
     HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY decoders_key;
+    HKEY instance_key;
 
     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
                        KEY_READ | KEY_WRITE, &coclass_key);
     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
     if (res != ERROR_SUCCESS) goto error_return;
 
     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
-       WCHAR buf[39];
-
        StringFromGUID2(list->clsid, buf, 39);
+
        res = RegDeleteTreeW(coclass_key, buf);
        if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
        if (res != ERROR_SUCCESS) goto error_close_coclass_key;
 
-       if (list->progid) {
-           res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
-           if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
-           if (res != ERROR_SUCCESS) goto error_close_coclass_key;
-       }
-
-       if (list->viprogid) {
-           res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
-           if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
-           if (res != ERROR_SUCCESS) goto error_close_coclass_key;
-       }
+       res = RegDeleteTreeW(instance_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
     }
 
 error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(decoders_key);
     RegCloseKey(coclass_key);
 error_return:
     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
 }
 
 /***********************************************************************
- *             register_decoders
+ *             register_encoders
  */
-static HRESULT register_decoders(struct regsvr_decoder const *list)
+static HRESULT register_encoders(struct regsvr_encoder const *list)
 {
     LONG res = ERROR_SUCCESS;
     HKEY coclass_key;
     WCHAR buf[39];
-    HKEY decoders_key;
+    HKEY encoders_key;
     HKEY instance_key;
 
     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
                          KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
     if (res == ERROR_SUCCESS)  {
-        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
-                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+                             KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
         if (res == ERROR_SUCCESS)
         {
-            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+            res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
                              KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
         }
@@ -306,21 +420,21 @@ static HRESULT register_decoders(struct regsvr_decoder const *list)
                              KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
        if (res == ERROR_SUCCESS) {
            res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(buf), 78);
+                                 (const BYTE*)buf, 78);
            RegCloseKey(instance_clsid_key);
        }
        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
 
         if (list->author) {
            res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->author),
+                                 (const BYTE*)list->author,
                                 strlen(list->author) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->friendlyname) {
            res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->friendlyname),
+                                 (const BYTE*)list->friendlyname,
                                 strlen(list->friendlyname) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
@@ -328,27 +442,34 @@ static HRESULT register_decoders(struct regsvr_decoder const *list)
         if (list->vendor) {
             StringFromGUID2(list->vendor, buf, 39);
            res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(buf), 78);
+                                 (const BYTE*)buf, 78);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->container_format) {
+            StringFromGUID2(list->container_format, buf, 39);
+           res = RegSetValueExW(clsid_key, containerformat_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->version) {
            res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->version),
+                                 (const BYTE*)list->version,
                                 strlen(list->version) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->mimetypes) {
            res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->mimetypes),
+                                 (const BYTE*)list->mimetypes,
                                 strlen(list->mimetypes) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->extensions) {
            res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->extensions),
+                                 (const BYTE*)list->extensions,
                                 strlen(list->extensions) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
@@ -373,64 +494,27 @@ static HRESULT register_decoders(struct regsvr_decoder const *list)
             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
-        if (list->patterns) {
-            HKEY patterns_key;
-            int i;
-
-            res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
-                                  KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
-            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-            for (i=0; list->patterns[i].length; i++)
-            {
-                HKEY pattern_key;
-                static const WCHAR int_format[] = {'%','i',0};
-                snprintfW(buf, 39, int_format, i);
-                res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
-                                      KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
-                if (res != ERROR_SUCCESS) break;
-               res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
-                                    (CONST BYTE*)(&list->patterns[i].length), 4);
-                if (res == ERROR_SUCCESS)
-                   res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
-                                        (CONST BYTE*)(&list->patterns[i].position), 4);
-                if (res == ERROR_SUCCESS)
-                   res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
-                                        list->patterns[i].pattern,
-                                        list->patterns[i].length);
-                if (res == ERROR_SUCCESS)
-                   res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
-                                        list->patterns[i].mask,
-                                        list->patterns[i].length);
-                if (res == ERROR_SUCCESS)
-                   res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
-                                        (CONST BYTE*)&(list->patterns[i].endofstream), 4);
-                RegCloseKey(pattern_key);
-            }
-            RegCloseKey(patterns_key);
-            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
-        }
-
     error_close_clsid_key:
        RegCloseKey(clsid_key);
     }
 
 error_close_coclass_key:
     RegCloseKey(instance_key);
-    RegCloseKey(decoders_key);
+    RegCloseKey(encoders_key);
     RegCloseKey(coclass_key);
 error_return:
     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
 }
 
 /***********************************************************************
- *             unregister_decoders
+ *             unregister_encoders
  */
-static HRESULT unregister_decoders(struct regsvr_decoder const *list)
+static HRESULT unregister_encoders(struct regsvr_encoder const *list)
 {
     LONG res = ERROR_SUCCESS;
     HKEY coclass_key;
     WCHAR buf[39];
-    HKEY decoders_key;
+    HKEY encoders_key;
     HKEY instance_key;
 
     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
@@ -438,12 +522,12 @@ static HRESULT unregister_decoders(struct regsvr_decoder const *list)
     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
 
     if (res == ERROR_SUCCESS)  {
-        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        StringFromGUID2(&CATID_WICBitmapEncoders, buf, 39);
         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
-                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+                             KEY_READ | KEY_WRITE, NULL, &encoders_key, NULL);
         if (res == ERROR_SUCCESS)
         {
-            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+            res = RegCreateKeyExW(encoders_key, instance_keyname, 0, NULL, 0,
                              KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
         }
@@ -466,7 +550,7 @@ static HRESULT unregister_decoders(struct regsvr_decoder const *list)
 
 error_close_coclass_key:
     RegCloseKey(instance_key);
-    RegCloseKey(decoders_key);
+    RegCloseKey(encoders_key);
     RegCloseKey(coclass_key);
 error_return:
     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
@@ -514,21 +598,21 @@ static HRESULT register_converters(struct regsvr_converter const *list)
                              KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
        if (res == ERROR_SUCCESS) {
            res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(buf), 78);
+                                 (const BYTE*)buf, 78);
            RegCloseKey(instance_clsid_key);
        }
        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
 
         if (list->author) {
            res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->author),
+                                 (const BYTE*)list->author,
                                 strlen(list->author) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->friendlyname) {
            res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->friendlyname),
+                                 (const BYTE*)list->friendlyname,
                                 strlen(list->friendlyname) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
@@ -536,13 +620,13 @@ static HRESULT register_converters(struct regsvr_converter const *list)
         if (list->vendor) {
             StringFromGUID2(list->vendor, buf, 39);
            res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(buf), 78);
+                                 (const BYTE*)buf, 78);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
 
         if (list->version) {
            res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
-                                (CONST BYTE*)(list->version),
+                                 (const BYTE*)list->version,
                                 strlen(list->version) + 1);
            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
         }
@@ -630,166 +714,394 @@ error_return:
 }
 
 /***********************************************************************
- *             register_key_defvalueW
- */
-static LONG register_key_defvalueW(
-    HKEY base,
-    WCHAR const *name,
-    WCHAR const *value)
-{
-    LONG res;
-    HKEY key;
-
-    res = RegCreateKeyExW(base, name, 0, NULL, 0,
-                         KEY_READ | KEY_WRITE, NULL, &key, NULL);
-    if (res != ERROR_SUCCESS) return res;
-    res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
-                        (lstrlenW(value) + 1) * sizeof(WCHAR));
-    RegCloseKey(key);
-    return res;
-}
-
-/***********************************************************************
- *             register_key_defvalueA
+ *             register_metadatareaders
  */
-static LONG register_key_defvalueA(
-    HKEY base,
-    WCHAR const *name,
-    char const *value)
+static HRESULT register_metadatareaders(struct regsvr_metadatareader const *list)
 {
-    LONG res;
-    HKEY key;
-
-    res = RegCreateKeyExW(base, name, 0, NULL, 0,
-                         KEY_READ | KEY_WRITE, NULL, &key, NULL);
-    if (res != ERROR_SUCCESS) return res;
-    res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
-                        lstrlenA(value) + 1);
-    RegCloseKey(key);
-    return res;
-}
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY readers_key;
+    HKEY instance_key;
 
-/***********************************************************************
- *             register_progid
- */
-static LONG register_progid(
-    WCHAR const *clsid,
-    char const *progid,
-    char const *curver_progid,
-    char const *name,
-    char const *extra)
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICMetadataReader, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &readers_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(readers_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       HKEY clsid_key;
+       HKEY instance_clsid_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+       if (res == ERROR_SUCCESS) {
+           res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+           RegCloseKey(instance_clsid_key);
+       }
+       if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        if (list->author) {
+           res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->author,
+                                strlen(list->author) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->friendlyname) {
+           res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->friendlyname,
+                                strlen(list->friendlyname) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->vendor) {
+            StringFromGUID2(list->vendor, buf, 39);
+           res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->metadata_format) {
+            StringFromGUID2(list->metadata_format, buf, 39);
+           res = RegSetValueExW(clsid_key, metadataformat_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->version) {
+           res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->version,
+                                strlen(list->version) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->specversion) {
+           res = RegSetValueExA(clsid_key, specversion_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->version,
+                                strlen(list->version) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        res = RegSetValueExA(clsid_key, requiresfullstream_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->requires_fullstream, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        res = RegSetValueExA(clsid_key, supportspadding_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->supports_padding, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        if (list->requires_fixedsize) {
+           res = RegSetValueExA(clsid_key, requiresfixedsize_valuename, 0, REG_DWORD,
+                                 (const BYTE*)&list->requires_fixedsize, 4);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->containers) {
+            HKEY containers_key;
+            const struct reader_containers *container;
+
+            res = RegCreateKeyExW(clsid_key, containers_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &containers_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (container=list->containers; container->format; ++container)
+            {
+                HKEY format_key;
+                int i;
+                StringFromGUID2(container->format, buf, 39);
+                res = RegCreateKeyExW(containers_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+
+                for (i=0; container->patterns[i].length; i++)
+                {
+                    HKEY pattern_key;
+                    static const WCHAR int_format[] = {'%','i',0};
+                    snprintfW(buf, 39, int_format, i);
+                    res = RegCreateKeyExW(format_key, buf, 0, NULL, 0,
+                                          KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
+                    if (res != ERROR_SUCCESS) break;
+                    res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
+                                         (const BYTE*)&container->patterns[i].position, 4);
+                    if (res == ERROR_SUCCESS)
+                        res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
+                                             container->patterns[i].pattern,
+                                             container->patterns[i].length);
+                    if (res == ERROR_SUCCESS)
+                        res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
+                                             container->patterns[i].mask,
+                                             container->patterns[i].length);
+                    if (res == ERROR_SUCCESS && container->patterns[i].data_offset)
+                        res = RegSetValueExA(pattern_key, dataoffset_valuename, 0, REG_DWORD,
+                                             (const BYTE*)&container->patterns[i].data_offset, 4);
+                    RegCloseKey(pattern_key);
+                }
+
+                RegCloseKey(format_key);
+            }
+            RegCloseKey(containers_key);
+        }
+
+    error_close_clsid_key:
+       RegCloseKey(clsid_key);
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(readers_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             unregister_metadatareaders
+ */
+static HRESULT unregister_metadatareaders(struct regsvr_metadatareader const *list)
 {
-    LONG res;
-    HKEY progid_key;
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY readers_key;
+    HKEY instance_key;
 
-    res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
-                         NULL, 0, KEY_READ | KEY_WRITE, NULL,
-                         &progid_key, NULL);
-    if (res != ERROR_SUCCESS) return res;
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                       KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
 
-    if (name) {
-       res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
-                            (CONST BYTE*)name, strlen(name) + 1);
-       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICMetadataReader, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &readers_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(readers_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
     }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       StringFromGUID2(list->clsid, buf, 39);
+
+       res = RegDeleteTreeW(coclass_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
 
-    if (clsid) {
-       res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
-       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+       res = RegDeleteTreeW(instance_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
     }
 
-    if (curver_progid) {
-       res = register_key_defvalueA(progid_key, curver_keyname,
-                                    curver_progid);
-       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(readers_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *                register_pixelformats
+ */
+static HRESULT register_pixelformats(struct regsvr_pixelformat const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY formats_key;
+    HKEY instance_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                          KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICPixelFormats, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(formats_key, instance_keyname, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
     }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+        HKEY clsid_key;
+        HKEY instance_clsid_key;
+
+        StringFromGUID2(list->clsid, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+        if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+        StringFromGUID2(list->clsid, buf, 39);
+        res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+        if (res == ERROR_SUCCESS) {
+            res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+            RegCloseKey(instance_clsid_key);
+        }
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
 
-    if (extra) {
-       HKEY extra_key;
+        if (list->author) {
+            res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->author,
+                                 strlen(list->author) + 1);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
 
-       res = RegCreateKeyExA(progid_key, extra, 0,
-                             NULL, 0, KEY_READ | KEY_WRITE, NULL,
-                             &extra_key, NULL);
-       if (res == ERROR_SUCCESS)
-           RegCloseKey(extra_key);
+        if (list->friendlyname) {
+            res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->friendlyname,
+                                 strlen(list->friendlyname) + 1);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->vendor) {
+            StringFromGUID2(list->vendor, buf, 39);
+            res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
+                                 (const BYTE*)buf, 78);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->version) {
+            res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
+                                 (const BYTE*)list->version,
+                                 strlen(list->version) + 1);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        res = RegSetValueExA(clsid_key, bitsperpixel_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->bitsperpixel, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        res = RegSetValueExA(clsid_key, channelcount_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->channelcount, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        res = RegSetValueExA(clsid_key, numericrepresentation_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->numericrepresentation, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        res = RegSetValueExA(clsid_key, supportstransparency_valuename, 0, REG_DWORD,
+                             (const BYTE*)&list->supportsalpha, 4);
+        if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        if (list->channelmasks) {
+            HKEY masks_key;
+            UINT i, mask_size;
+            WCHAR mask_valuename[11];
+            const WCHAR valuename_format[] = {'%','d',0};
+
+            mask_size = (list->bitsperpixel + 7)/8;
+
+            res = RegCreateKeyExW(clsid_key, channelmasks_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &masks_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (i=0; i < list->channelcount; i++)
+            {
+                sprintfW(mask_valuename, valuename_format, i);
+                res = RegSetValueExW(masks_key, mask_valuename, 0, REG_BINARY,
+                                     list->channelmasks[i], mask_size);
+                if (res != ERROR_SUCCESS) break;
+            }
+            RegCloseKey(masks_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+    error_close_clsid_key:
+        RegCloseKey(clsid_key);
     }
 
-error_close_progid_key:
-    RegCloseKey(progid_key);
-    return res;
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(formats_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
 }
 
 /***********************************************************************
- *             coclass list
+ *                unregister_pixelformats
  */
-static struct regsvr_coclass const coclass_list[] = {
-    {   &CLSID_WICImagingFactory,
-       "WIC Imaging Factory",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICBmpDecoder,
-       "WIC BMP Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICPngDecoder,
-       "WIC PNG Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICPngEncoder,
-       "WIC PNG Encoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICBmpEncoder,
-       "WIC BMP Encoder",
-       NULL,
-       "windowscodecs.dll",
-       "Apartment"
-    },
-    {   &CLSID_WICGifDecoder,
-       "WIC GIF Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICIcoDecoder,
-       "WIC ICO Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICJpegDecoder,
-       "WIC JPEG Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICTiffDecoder,
-       "WIC TIFF Decoder",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    {   &CLSID_WICDefaultFormatConverter,
-       "WIC Default Format Converter",
-       NULL,
-       "windowscodecs.dll",
-       "Both"
-    },
-    { NULL }                   /* list terminator */
-};
+static HRESULT unregister_pixelformats(struct regsvr_pixelformat const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY formats_key;
+    HKEY instance_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                        KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICPixelFormats, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(formats_key, instance_keyname, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+        StringFromGUID2(list->clsid, buf, 39);
+
+        res = RegDeleteTreeW(coclass_key, buf);
+        if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+        if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+        res = RegDeleteTreeW(instance_key, buf);
+        if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+        if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(formats_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
 
 /***********************************************************************
  *             decoder list
  */
-static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
 
 static const BYTE bmp_magic[] = {0x42,0x4d};
 
@@ -837,16 +1149,17 @@ static struct decoder_pattern const ico_patterns[] = {
     {0}
 };
 
-static const BYTE jpeg_magic[] = {0xff, 0xd8, 0xff, 0xe0};
+static const BYTE jpeg_magic[] = {0xff, 0xd8};
 
 static GUID const * const jpeg_formats[] = {
     &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppCMYK,
     &GUID_WICPixelFormat8bppGray,
     NULL
 };
 
 static struct decoder_pattern const jpeg_patterns[] = {
-    {4,0,jpeg_magic,mask_all,0},
+    {2,0,jpeg_magic,mask_all,0},
     {0}
 };
 
@@ -877,15 +1190,26 @@ static struct decoder_pattern const png_patterns[] = {
 static const BYTE tiff_magic_le[] = {0x49,0x49,42,0};
 static const BYTE tiff_magic_be[] = {0x4d,0x4d,0,42};
 
-static GUID const * const tiff_formats[] = {
+static GUID const * const tiff_decode_formats[] = {
     &GUID_WICPixelFormatBlackWhite,
     &GUID_WICPixelFormat4bppGray,
     &GUID_WICPixelFormat8bppGray,
+    &GUID_WICPixelFormat16bppGray,
+    &GUID_WICPixelFormat32bppGrayFloat,
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat2bppIndexed,
     &GUID_WICPixelFormat4bppIndexed,
     &GUID_WICPixelFormat8bppIndexed,
+    &GUID_WICPixelFormat24bppBGR,
     &GUID_WICPixelFormat32bppBGR,
     &GUID_WICPixelFormat32bppBGRA,
     &GUID_WICPixelFormat32bppPBGRA,
+    &GUID_WICPixelFormat48bppRGB,
+    &GUID_WICPixelFormat64bppRGBA,
+    &GUID_WICPixelFormat64bppPRGBA,
+    &GUID_WICPixelFormat32bppCMYK,
+    &GUID_WICPixelFormat64bppCMYK,
+    &GUID_WICPixelFormat128bppRGBAFloat,
     NULL
 };
 
@@ -895,12 +1219,43 @@ static struct decoder_pattern const tiff_patterns[] = {
     {0}
 };
 
+static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
+
+static const BYTE tga_indexed_magic[18] = {0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0};
+static const BYTE tga_indexed_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff,0xcf};
+
+static const BYTE tga_truecolor_magic[18] = {0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static const BYTE tga_truecolor_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0x87,0xc0};
+
+static const BYTE tga_grayscale_magic[18] = {0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0};
+static const BYTE tga_grayscale_mask[18] = {0,0xff,0xf7,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff,0xcf};
+
+static GUID const * const tga_formats[] = {
+    &GUID_WICPixelFormat8bppGray,
+    &GUID_WICPixelFormat8bppIndexed,
+    &GUID_WICPixelFormat16bppGray,
+    &GUID_WICPixelFormat16bppBGR555,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    &GUID_WICPixelFormat32bppPBGRA,
+    NULL
+};
+
+static struct decoder_pattern const tga_patterns[] = {
+    {18,18,tga_footer_magic,mask_all,1},
+    {18,0,tga_indexed_magic,tga_indexed_mask,0},
+    {18,0,tga_truecolor_magic,tga_truecolor_mask,0},
+    {18,0,tga_grayscale_magic,tga_grayscale_mask,0},
+    {0}
+};
+
 static struct regsvr_decoder const decoder_list[] = {
     {   &CLSID_WICBmpDecoder,
        "The Wine Project",
        "BMP Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatBmp,
        "image/bmp",
        ".bmp,.dib,.rle",
        bmp_formats,
@@ -911,6 +1266,7 @@ static struct regsvr_decoder const decoder_list[] = {
        "GIF Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatGif,
        "image/gif",
        ".gif",
        gif_formats,
@@ -921,6 +1277,7 @@ static struct regsvr_decoder const decoder_list[] = {
        "ICO Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatIco,
        "image/vnd.microsoft.icon",
        ".ico",
        ico_formats,
@@ -931,6 +1288,7 @@ static struct regsvr_decoder const decoder_list[] = {
        "JPEG Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatJpeg,
        "image/jpeg",
        ".jpg;.jpeg;.jfif",
        jpeg_formats,
@@ -941,6 +1299,7 @@ static struct regsvr_decoder const decoder_list[] = {
        "PNG Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatPng,
        "image/png",
        ".png",
        png_formats,
@@ -951,11 +1310,140 @@ static struct regsvr_decoder const decoder_list[] = {
        "TIFF Decoder",
        "1.0.0.0",
        &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatTiff,
        "image/tiff",
        ".tif;.tiff",
-       tiff_formats,
+       tiff_decode_formats,
        tiff_patterns
     },
+    {   &CLSID_WineTgaDecoder,
+       "The Wine Project",
+       "TGA Decoder",
+       "1.0.0.0",
+       &GUID_VendorWine,
+       &GUID_WineContainerFormatTga,
+       "image/x-targa",
+       ".tga;.tpic",
+       tga_formats,
+       tga_patterns
+    },
+    { NULL }                   /* list terminator */
+};
+
+static GUID const * const bmp_encode_formats[] = {
+    &GUID_WICPixelFormat16bppBGR555,
+    &GUID_WICPixelFormat16bppBGR565,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormatBlackWhite,
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat2bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
+    NULL
+};
+
+static GUID const * const png_encode_formats[] = {
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormatBlackWhite,
+    &GUID_WICPixelFormat2bppGray,
+    &GUID_WICPixelFormat4bppGray,
+    &GUID_WICPixelFormat8bppGray,
+    &GUID_WICPixelFormat16bppGray,
+    &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    &GUID_WICPixelFormat48bppRGB,
+    &GUID_WICPixelFormat64bppRGBA,
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat2bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
+    NULL
+};
+
+static GUID const * const tiff_encode_formats[] = {
+    &GUID_WICPixelFormatBlackWhite,
+    &GUID_WICPixelFormat4bppGray,
+    &GUID_WICPixelFormat8bppGray,
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat2bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    &GUID_WICPixelFormat32bppPBGRA,
+    &GUID_WICPixelFormat48bppRGB,
+    &GUID_WICPixelFormat64bppRGBA,
+    &GUID_WICPixelFormat64bppPRGBA,
+    NULL
+};
+
+static GUID const * const icns_encode_formats[] = {
+    &GUID_WICPixelFormat32bppBGRA,
+    NULL
+};
+
+static struct regsvr_encoder const encoder_list[] = {
+    {   &CLSID_WICBmpEncoder,
+       "The Wine Project",
+       "BMP Encoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatBmp,
+       "image/bmp",
+       ".bmp,.dib,.rle",
+       bmp_encode_formats
+    },
+    {   &CLSID_WICGifEncoder,
+       "The Wine Project",
+       "GIF Encoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatGif,
+       "image/gif",
+       ".gif",
+       gif_formats
+    },
+    {   &CLSID_WICJpegEncoder,
+       "The Wine Project",
+       "JPEG Encoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatJpeg,
+       "image/jpeg",
+       ".jpg;.jpeg;.jfif",
+       jpeg_formats
+    },
+    {   &CLSID_WICPngEncoder,
+       "The Wine Project",
+       "PNG Encoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatPng,
+       "image/png",
+       ".png",
+       png_encode_formats
+    },
+    {   &CLSID_WICTiffEncoder,
+       "The Wine Project",
+       "TIFF Encoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       &GUID_ContainerFormatTiff,
+       "image/tiff",
+       ".tif;.tiff",
+       tiff_encode_formats
+    },
+    {   &CLSID_WICIcnsEncoder,
+       "The Wine Project",
+       "ICNS Encoder",
+       "1.0.0.0",
+       &GUID_VendorWine,
+       NULL, /* no container format guid */
+       "image/icns",
+       ".icns",
+       icns_encode_formats
+    },
     { NULL }                   /* list terminator */
 };
 
@@ -971,11 +1459,19 @@ static GUID const * const converter_formats[] = {
     &GUID_WICPixelFormat16bppGray,
     &GUID_WICPixelFormat16bppBGR555,
     &GUID_WICPixelFormat16bppBGR565,
+    &GUID_WICPixelFormat16bppBGRA5551,
     &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat24bppRGB,
     &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormat32bppRGB,
     &GUID_WICPixelFormat32bppBGRA,
+    &GUID_WICPixelFormat32bppRGBA,
+    &GUID_WICPixelFormat32bppPBGRA,
+    &GUID_WICPixelFormat32bppPRGBA,
+    &GUID_WICPixelFormat32bppGrayFloat,
     &GUID_WICPixelFormat48bppRGB,
     &GUID_WICPixelFormat64bppRGBA,
+    &GUID_WICPixelFormat32bppCMYK,
     NULL
 };
 
@@ -990,17 +1486,712 @@ static struct regsvr_converter const converter_list[] = {
     { NULL }                   /* list terminator */
 };
 
+static const BYTE no_magic[1] = { 0 };
+static const BYTE no_mask[1] = { 0 };
+
+static const struct metadata_pattern ifd_metadata_pattern[] = {
+    { 0, 1, no_magic, no_mask, 0 },
+    { 0 }
+};
+
+static const struct reader_containers ifd_containers[] = {
+    {
+        &GUID_ContainerFormatTiff,
+        ifd_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE tEXt[] = "tEXt";
+
+static const struct metadata_pattern pngtext_metadata_pattern[] = {
+    { 4, 4, tEXt, mask_all, 4 },
+    { 0 }
+};
+
+static const struct reader_containers pngtext_containers[] = {
+    {
+        &GUID_ContainerFormatPng,
+        pngtext_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE gAMA[] = "gAMA";
+
+static const struct metadata_pattern pnggama_metadata_pattern[] = {
+    { 4, 4, gAMA, mask_all, 4 },
+    { 0 }
+};
+
+static const struct reader_containers pnggama_containers[] = {
+    {
+        &GUID_ContainerFormatPng,
+        pnggama_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE cHRM[] = "cHRM";
+
+static const struct metadata_pattern pngchrm_metadata_pattern[] = {
+    { 4, 4, cHRM, mask_all, 4 },
+    { 0 }
+};
+
+static const struct reader_containers pngchrm_containers[] = {
+    {
+        &GUID_ContainerFormatPng,
+        pngchrm_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const struct metadata_pattern lsd_metadata_patterns[] = {
+    { 0, 6, gif87a_magic, mask_all, 0 },
+    { 0, 6, gif89a_magic, mask_all, 0 },
+    { 0 }
+};
+
+static const struct reader_containers lsd_containers[] = {
+    {
+        &GUID_ContainerFormatGif,
+        lsd_metadata_patterns
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE imd_magic[] = { 0x2c };
+
+static const struct metadata_pattern imd_metadata_pattern[] = {
+    { 0, 1, imd_magic, mask_all, 1 },
+    { 0 }
+};
+
+static const struct reader_containers imd_containers[] = {
+    {
+        &GUID_ContainerFormatGif,
+        imd_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE gce_magic[] = { 0x21, 0xf9, 0x04 };
+
+static const struct metadata_pattern gce_metadata_pattern[] = {
+    { 0, 3, gce_magic, mask_all, 3 },
+    { 0 }
+};
+
+static const struct reader_containers gce_containers[] = {
+    {
+        &GUID_ContainerFormatGif,
+        gce_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE ape_magic[] = { 0x21, 0xff, 0x0b };
+
+static const struct metadata_pattern ape_metadata_pattern[] = {
+    { 0, 3, ape_magic, mask_all, 0 },
+    { 0 }
+};
+
+static const struct reader_containers ape_containers[] = {
+    {
+        &GUID_ContainerFormatGif,
+        ape_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static const BYTE gif_comment_magic[] = { 0x21, 0xfe };
+
+static const struct metadata_pattern gif_comment_metadata_pattern[] = {
+    { 0, 2, gif_comment_magic, mask_all, 0 },
+    { 0 }
+};
+
+static const struct reader_containers gif_comment_containers[] = {
+    {
+        &GUID_ContainerFormatGif,
+        gif_comment_metadata_pattern
+    },
+    { NULL } /* list terminator */
+};
+
+static struct regsvr_metadatareader const metadatareader_list[] = {
+    {   &CLSID_WICUnknownMetadataReader,
+        "The Wine Project",
+        "Unknown Metadata Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatUnknown,
+        0, 0, 0,
+        NULL
+    },
+    {   &CLSID_WICIfdMetadataReader,
+        "The Wine Project",
+        "Ifd Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatIfd,
+        1, 1, 0,
+        ifd_containers
+    },
+    {   &CLSID_WICPngChrmMetadataReader,
+        "The Wine Project",
+        "Chunk cHRM Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatChunkcHRM,
+        0, 0, 0,
+        pngchrm_containers
+    },
+    {   &CLSID_WICPngGamaMetadataReader,
+        "The Wine Project",
+        "Chunk gAMA Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatChunkgAMA,
+        0, 0, 0,
+        pnggama_containers
+    },
+    {   &CLSID_WICPngTextMetadataReader,
+        "The Wine Project",
+        "Chunk tEXt Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatChunktEXt,
+        0, 0, 0,
+        pngtext_containers
+    },
+    {   &CLSID_WICLSDMetadataReader,
+        "The Wine Project",
+        "Logical Screen Descriptor Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatLSD,
+        0, 0, 0,
+        lsd_containers
+    },
+    {   &CLSID_WICIMDMetadataReader,
+        "The Wine Project",
+        "Image Descriptor Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatIMD,
+        0, 0, 0,
+        imd_containers
+    },
+    {   &CLSID_WICGCEMetadataReader,
+        "The Wine Project",
+        "Graphic Control Extension Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatGCE,
+        0, 0, 0,
+        gce_containers
+    },
+    {   &CLSID_WICAPEMetadataReader,
+        "The Wine Project",
+        "Application Extension Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatAPE,
+        0, 0, 0,
+        ape_containers
+    },
+    {   &CLSID_WICGifCommentMetadataReader,
+        "The Wine Project",
+        "Comment Extension Reader",
+        "1.0.0.0",
+        "1.0.0.0",
+        &GUID_VendorMicrosoft,
+        &GUID_MetadataFormatGifComment,
+        0, 0, 0,
+        gif_comment_containers
+    },
+    { NULL }                   /* list terminator */
+};
+
+static BYTE const channel_mask_1bit[] = { 0x01 };
+static BYTE const channel_mask_2bit[] = { 0x03 };
+static BYTE const channel_mask_4bit[] = { 0x0f };
+
+static BYTE const channel_mask_8bit[] = { 0xff, 0x00, 0x00, 0x00 };
+static BYTE const channel_mask_8bit2[] = { 0x00, 0xff, 0x00, 0x00 };
+static BYTE const channel_mask_8bit3[] = { 0x00, 0x00, 0xff, 0x00 };
+static BYTE const channel_mask_8bit4[] = { 0x00, 0x00, 0x00, 0xff };
+
+static BYTE const channel_mask_16bit[] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static BYTE const channel_mask_16bit2[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
+static BYTE const channel_mask_16bit3[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 };
+static BYTE const channel_mask_16bit4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
+
+static BYTE const channel_mask_32bit[] = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+static BYTE const channel_mask_128bit1[] = { 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+static BYTE const channel_mask_128bit2[] = { 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+static BYTE const channel_mask_128bit3[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 };
+static BYTE const channel_mask_128bit4[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff };
+
+static BYTE const channel_mask_5bit[] = { 0x1f, 0x00 };
+static BYTE const channel_mask_5bit2[] = { 0xe0, 0x03 };
+static BYTE const channel_mask_5bit3[] = { 0x00, 0x7c };
+static BYTE const channel_mask_5bit4[] = { 0x00, 0x80 };
+
+static BYTE const channel_mask_BGR565_2[] = { 0xe0, 0x07 };
+static BYTE const channel_mask_BGR565_3[] = { 0x00, 0xf8 };
+
+static BYTE const * const channel_masks_1bit[] = { channel_mask_1bit };
+static BYTE const * const channel_masks_2bit[] = { channel_mask_2bit };
+static BYTE const * const channel_masks_4bit[] = { channel_mask_4bit };
+static BYTE const * const channel_masks_8bit[] = { channel_mask_8bit,
+    channel_mask_8bit2, channel_mask_8bit3, channel_mask_8bit4 };
+static BYTE const * const channel_masks_16bit[] = { channel_mask_16bit,
+    channel_mask_16bit2, channel_mask_16bit3, channel_mask_16bit4};
+
+static BYTE const * const channel_masks_32bit[] = { channel_mask_32bit };
+static BYTE const * const channel_masks_128bit[] = { channel_mask_128bit1, channel_mask_128bit2, channel_mask_128bit3, channel_mask_128bit4 };
+
+static BYTE const * const channel_masks_BGRA5551[] = { channel_mask_5bit,
+    channel_mask_5bit2, channel_mask_5bit3, channel_mask_5bit4 };
+
+static BYTE const * const channel_masks_BGR565[] = { channel_mask_5bit,
+    channel_mask_BGR565_2, channel_mask_BGR565_3 };
+
+static struct regsvr_pixelformat const pixelformat_list[] = {
+    {   &GUID_WICPixelFormat1bppIndexed,
+        "The Wine Project",
+        "1bpp Indexed",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        1, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_1bit,
+        WICPixelFormatNumericRepresentationIndexed,
+        0
+    },
+    {   &GUID_WICPixelFormat2bppIndexed,
+        "The Wine Project",
+        "2bpp Indexed",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        2, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_2bit,
+        WICPixelFormatNumericRepresentationIndexed,
+        0
+    },
+    {   &GUID_WICPixelFormat4bppIndexed,
+        "The Wine Project",
+        "4bpp Indexed",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        4, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_4bit,
+        WICPixelFormatNumericRepresentationIndexed,
+        0
+    },
+    {   &GUID_WICPixelFormat8bppIndexed,
+        "The Wine Project",
+        "8bpp Indexed",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        8, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationIndexed,
+        0
+    },
+    {   &GUID_WICPixelFormatBlackWhite,
+        "The Wine Project",
+        "Black and White",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        1, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_1bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat2bppGray,
+        "The Wine Project",
+        "2bpp Grayscale",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        2, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_2bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat4bppGray,
+        "The Wine Project",
+        "4bpp Grayscale",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        4, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_4bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat8bppGray,
+        "The Wine Project",
+        "8bpp Grayscale",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        8, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat16bppGray,
+        "The Wine Project",
+        "16bpp Grayscale",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        16, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_16bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat16bppBGR555,
+        "The Wine Project",
+        "16bpp BGR555",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        16, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_BGRA5551,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat16bppBGR565,
+        "The Wine Project",
+        "16bpp BGR565",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        16, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_BGR565,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat16bppBGRA5551,
+        "The Wine Project",
+        "16bpp BGRA5551",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        16, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_BGRA5551,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat24bppBGR,
+        "The Wine Project",
+        "24bpp BGR",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        24, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat24bppRGB,
+        "The Wine Project",
+        "24bpp RGB",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        24, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat32bppBGR,
+        "The Wine Project",
+        "32bpp BGR",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat32bppRGB,
+        "The Wine Project",
+        "32bpp RGB",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat32bppBGRA,
+        "The Wine Project",
+        "32bpp BGRA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat32bppRGBA,
+        "The Wine Project",
+        "32bpp RGBA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat32bppPBGRA,
+        "The Wine Project",
+        "32bpp PBGRA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat32bppPRGBA,
+        "The Wine Project",
+        "32bpp PRGBA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat32bppGrayFloat,
+        "The Wine Project",
+        "32bpp GrayFloat",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        1, /* channel count */
+        channel_masks_32bit,
+        WICPixelFormatNumericRepresentationFloat,
+        0
+    },
+    {   &GUID_WICPixelFormat48bppRGB,
+        "The Wine Project",
+        "48bpp RGB",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        48, /* bitsperpixel */
+        3, /* channel count */
+        channel_masks_16bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat64bppRGBA,
+        "The Wine Project",
+        "64bpp RGBA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        64, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_16bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat64bppPRGBA,
+        "The Wine Project",
+        "64bpp PRGBA",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        64, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_16bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        1
+    },
+    {   &GUID_WICPixelFormat32bppCMYK,
+        "The Wine Project",
+        "32bpp CMYK",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        32, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_8bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat64bppCMYK,
+        "The Wine Project",
+        "64bpp CMYK",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        64, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_16bit,
+        WICPixelFormatNumericRepresentationUnsignedInteger,
+        0
+    },
+    {   &GUID_WICPixelFormat128bppRGBAFloat,
+        "The Wine Project",
+        "128bpp RGBAFloat",
+        NULL, /* no version */
+        &GUID_VendorMicrosoft,
+        128, /* bitsperpixel */
+        4, /* channel count */
+        channel_masks_128bit,
+        WICPixelFormatNumericRepresentationFloat,
+        1
+    },
+    { NULL }                   /* list terminator */
+};
+
+struct regsvr_category
+{
+    const CLSID *clsid; /* NULL for end of list */
+};
+
+static const struct regsvr_category category_list[] = {
+    { &CATID_WICBitmapDecoders },
+    { &CATID_WICBitmapEncoders },
+    { &CATID_WICFormatConverters },
+    { &CATID_WICMetadataReader },
+    { &CATID_WICPixelFormats },
+    { NULL }
+};
+
+static HRESULT register_categories(const struct regsvr_category *list)
+{
+    LONG res;
+    WCHAR buf[39];
+    HKEY coclass_key, categories_key, instance_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                          KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
+    res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                          KEY_READ | KEY_WRITE, NULL, &categories_key, NULL);
+    if (res != ERROR_SUCCESS)
+    {
+        RegCloseKey(coclass_key);
+        return HRESULT_FROM_WIN32(res);
+    }
+
+    res = RegCreateKeyExW(categories_key, instance_keyname, 0, NULL, 0,
+                          KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+
+    for (; res == ERROR_SUCCESS && list->clsid; list++)
+    {
+        HKEY instance_clsid_key;
+
+        StringFromGUID2(list->clsid, buf, 39);
+        res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                              KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                 (const BYTE *)buf, 78);
+            RegCloseKey(instance_clsid_key);
+        }
+    }
+
+    RegCloseKey(instance_key);
+    RegCloseKey(categories_key);
+    RegCloseKey(coclass_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+static HRESULT unregister_categories(const struct regsvr_category *list)
+{
+    LONG res;
+    WCHAR buf[39];
+    HKEY coclass_key, categories_key, instance_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                        KEY_READ | KEY_WRITE, &coclass_key);
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
+    res = RegOpenKeyExW(coclass_key, buf, 0,
+                        KEY_READ | KEY_WRITE, &categories_key);
+    if (res != ERROR_SUCCESS)
+    {
+        if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+        RegCloseKey(coclass_key);
+        return HRESULT_FROM_WIN32(res);
+    }
+
+    res = RegOpenKeyExW(categories_key, instance_keyname, 0,
+                          KEY_READ | KEY_WRITE, &instance_key);
+
+    for (; res == ERROR_SUCCESS && list->clsid; list++)
+    {
+        StringFromGUID2(list->clsid, buf, 39);
+        res = RegDeleteTreeW(instance_key, buf);
+    }
+
+    RegCloseKey(instance_key);
+    RegCloseKey(categories_key);
+
+    StringFromGUID2(&CLSID_WICImagingCategories, buf, 39);
+    res = RegDeleteTreeW(coclass_key, buf);
+
+    RegCloseKey(coclass_key);
+
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+extern HRESULT WINAPI WIC_DllRegisterServer(void) DECLSPEC_HIDDEN;
+extern HRESULT WINAPI WIC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
+
 HRESULT WINAPI DllRegisterServer(void)
 {
     HRESULT hr;
 
     TRACE("\n");
 
-    hr = register_coclasses(coclass_list);
+    hr = WIC_DllRegisterServer();
+    if (SUCCEEDED(hr))
+        hr = register_categories(category_list);
     if (SUCCEEDED(hr))
-        register_decoders(decoder_list);
+        hr = register_decoders(decoder_list);
     if (SUCCEEDED(hr))
-        register_converters(converter_list);
+        hr = register_encoders(encoder_list);
+    if (SUCCEEDED(hr))
+        hr = register_converters(converter_list);
+    if (SUCCEEDED(hr))
+        hr = register_metadatareaders(metadatareader_list);
+    if (SUCCEEDED(hr))
+        hr = register_pixelformats(pixelformat_list);
     return hr;
 }
 
@@ -1010,10 +2201,18 @@ HRESULT WINAPI DllUnregisterServer(void)
 
     TRACE("\n");
 
-    hr = unregister_coclasses(coclass_list);
+    hr = WIC_DllUnregisterServer();
+    if (SUCCEEDED(hr))
+        hr = unregister_categories(category_list);
+    if (SUCCEEDED(hr))
+        hr = unregister_decoders(decoder_list);
+    if (SUCCEEDED(hr))
+        hr = unregister_encoders(encoder_list);
+    if (SUCCEEDED(hr))
+        hr = unregister_converters(converter_list);
     if (SUCCEEDED(hr))
-        unregister_decoders(decoder_list);
+        hr = unregister_metadatareaders(metadatareader_list);
     if (SUCCEEDED(hr))
-        unregister_converters(converter_list);
+        hr = unregister_pixelformats(pixelformat_list);
     return hr;
 }