MSI: (big) reimplment alot of the Register* actions

Aric Stewart aric at codeweavers.com
Wed May 25 13:20:19 CDT 2005


A big rewrite of the whole RegisterClass, RegisterProgId, RegisterExtension and RegisterMIME actions. We now handle verbs properly, handle dependancies and such properly and keep track of what we need to register and what we do not properly.

-------------- next part --------------
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.121
diff -u -r1.121 action.c
--- dlls/msi/action.c	23 May 2005 16:24:20 -0000	1.121
+++ dlls/msi/action.c	25 May 2005 18:15:29 -0000
@@ -616,6 +616,66 @@
     if (package->files && package->loaded_files > 0)
         HeapFree(GetProcessHeap(),0,package->files);
 
+    /* clean up extension, progid, class and verb structures */
+    for (i = 0; i < package->loaded_classes; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->classes[i].Description);
+        HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
+        HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
+        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
+        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
+        HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
+        HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
+    }
+
+    if (package->classes && package->loaded_classes > 0)
+        HeapFree(GetProcessHeap(),0,package->classes);
+
+    for (i = 0; i < package->loaded_extensions; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
+    }
+
+    if (package->extensions && package->loaded_extensions > 0)
+        HeapFree(GetProcessHeap(),0,package->extensions);
+
+    for (i = 0; i < package->loaded_progids; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
+        HeapFree(GetProcessHeap(),0,package->progids[i].Description);
+        HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
+    }
+
+    if (package->progids && package->loaded_progids > 0)
+        HeapFree(GetProcessHeap(),0,package->progids);
+
+    for (i = 0; i < package->loaded_verbs; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
+    }
+
+    if (package->verbs && package->loaded_verbs > 0)
+        HeapFree(GetProcessHeap(),0,package->verbs);
+
+    for (i = 0; i < package->loaded_mimes; i++)
+        HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
+
+    if (package->mimes && package->loaded_mimes > 0)
+        HeapFree(GetProcessHeap(),0,package->mimes);
+
+    for (i = 0; i < package->loaded_appids; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
+        HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
+        HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
+        HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
+    }
+
+    if (package->appids && package->loaded_appids > 0)
+        HeapFree(GetProcessHeap(),0,package->appids);
+
     for (i = 0; i < package->DeferredActionCount; i++)
         HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
     HeapFree(GetProcessHeap(),0,package->DeferredAction);
@@ -1602,7 +1662,7 @@
 
     memset(&package->components[index],0,sizeof(MSICOMPONENT));
 
-    sz = 96;       
+    sz = IDENTIFIER_SIZE;       
     MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
 
     TRACE("Loading Component %s\n",
@@ -1612,7 +1672,7 @@
     if (!MSI_RecordIsNull(row,2))
         MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
             
-    sz = 96;       
+    sz = IDENTIFIER_SIZE;       
     MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
 
     package->components[index].Attributes = MSI_RecordGetInteger(row,4);
@@ -1620,7 +1680,7 @@
     sz = 0x100;       
     MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
 
-    sz = 96;       
+    sz = IDENTIFIER_SIZE;       
     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
 
     package->components[index].Installed = INSTALLSTATE_ABSENT;
@@ -1666,12 +1726,12 @@
 
     memset(&package->features[index],0,sizeof(MSIFEATURE));
     
-    sz = 96;       
+    sz = IDENTIFIER_SIZE;       
     MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
 
     TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
 
-    sz = 96;
+    sz = IDENTIFIER_SIZE;
     if (!MSI_RecordIsNull(row,2))
         MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
 
@@ -1688,7 +1748,7 @@
   
     package->features[index].Level= MSI_RecordGetInteger(row,6);
 
-     sz = 96;
+     sz = IDENTIFIER_SIZE;
      if (!MSI_RecordIsNull(row,7))
         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
 
@@ -4395,514 +4455,1209 @@
     return rc;
 }
 
-static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
+static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
 {
-    static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    static const WCHAR ExecSeqQuery[] = 
+    DWORD index = package->loaded_appids;
+    DWORD sz;
+    LPWSTR buffer;
+
+    /* fill in the data */
+
+    package->loaded_appids++;
+    if (package->loaded_appids == 1)
+        package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
+    else
+        package->appids = HeapReAlloc(GetProcessHeap(),0,
+            package->appids, package->loaded_appids * sizeof(MSIAPPID));
+
+    memset(&package->appids[index],0,sizeof(MSIAPPID));
+    
+    sz = IDENTIFIER_SIZE;
+    MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
+    TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
+
+    buffer = load_dynamic_stringW(row,2);
+    deformat_string(package,buffer,&package->appids[index].RemoteServerName);
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    package->appids[index].LocalServer = load_dynamic_stringW(row,3);
+    package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
+    package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
+
+    package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
+    package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
+    
+    return index;
+}
+
+static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
+{
+    INT rc;
+    MSIQUERY *view;
+    MSIRECORD *row;
+    INT i;
+    static const WCHAR ExecSeqQuery[] =
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','A','p','p','I' ,'d','`',' ','W','H','E','R','E',' ',
-         '`','A','p','p','I','d','`',' ','=','\'','%','s','\'',0};
-    HKEY hkey2,hkey3;
-    LPWSTR buffer=0;
+         '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
+         '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
+    if (!appid)
+        return -1;
 
-    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
+    /* check for appids already loaded */
+    for (i = 0; i < package->loaded_appids; i++)
+        if (strcmpiW(package->appids[i].AppID,appid)==0)
+        {
+            TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
+            return i;
+        }
+    
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, appid);
     if (rc != ERROR_SUCCESS)
-        return rc;
+        return -1;
 
     rc = MSI_ViewExecute(view, 0);
     if (rc != ERROR_SUCCESS)
     {
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
-        return rc;
+        return -1;
     }
 
-    RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
-    RegCreateKeyW(hkey2,clsid,&hkey3);
-    RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
-                   (strlenW(app)+1)*sizeof(WCHAR));
-
     rc = MSI_ViewFetch(view,&row);
     if (rc != ERROR_SUCCESS)
     {
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
-        return rc;
+        return -1;
     }
 
-    if (!MSI_RecordIsNull(row,2)) 
-    {
-        LPWSTR deformated=0;
-        UINT size; 
-        static const WCHAR szRemoteServerName[] =
-             {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
-              0};
-        buffer = load_dynamic_stringW(row,2);
-        size = deformat_string(package,buffer,&deformated);
-        RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
-                       size);
-        HeapFree(GetProcessHeap(),0,deformated);
-        HeapFree(GetProcessHeap(),0,buffer);
-    }
+    rc = load_appid(package, row);
+    msiobj_release(&row->hdr);
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
 
-    if (!MSI_RecordIsNull(row,3)) 
-    {
-        static const WCHAR szLocalService[] =
-             {'L','o','c','a','l','S','e','r','v','i','c','e',0};
-        UINT size;
-        buffer = load_dynamic_stringW(row,3);
-        size = (strlenW(buffer)+1) * sizeof(WCHAR);
-        RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
-        HeapFree(GetProcessHeap(),0,buffer);
-    }
+    return rc;
+}
 
-    if (!MSI_RecordIsNull(row,4)) 
-    {
-        static const WCHAR szService[] =
-             {'S','e','r','v','i','c','e',
-              'P','a','r','a','m','e','t','e','r','s',0};
-        UINT size;
-        buffer = load_dynamic_stringW(row,4);
-        size = (strlenW(buffer)+1) * sizeof(WCHAR);
-        RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
-        HeapFree(GetProcessHeap(),0,buffer);
-    }
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
 
-    if (!MSI_RecordIsNull(row,5)) 
-    {
-        static const WCHAR szDLL[] =
-             {'D','l','l','S','u','r','r','o','g','a','t','e',0};
-        UINT size;
-        buffer = load_dynamic_stringW(row,5);
-        size = (strlenW(buffer)+1) * sizeof(WCHAR);
-        RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
-        HeapFree(GetProcessHeap(),0,buffer);
-    }
+static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
+{
+    DWORD index = package->loaded_progids;
+    LPWSTR buffer;
 
-    if (!MSI_RecordIsNull(row,6)) 
-    {
-        static const WCHAR szActivate[] =
-             {'A','c','t','i','v','a','t','e','A','s',
-              'S','t','o','r','a','g','e',0};
-        static const WCHAR szY[] = {'Y',0};
+    /* fill in the data */
 
-        if (MSI_RecordGetInteger(row,6))
-            RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
-    }
+    package->loaded_progids++;
+    if (package->loaded_progids == 1)
+        package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
+    else
+        package->progids = HeapReAlloc(GetProcessHeap(),0,
+            package->progids , package->loaded_progids * sizeof(MSIPROGID));
+
+    memset(&package->progids[index],0,sizeof(MSIPROGID));
+
+    package->progids[index].ProgID = load_dynamic_stringW(row,1);
+    TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
+
+    buffer = load_dynamic_stringW(row,2);
+    package->progids[index].ParentIndex = load_given_progid(package,buffer);
+    if (package->progids[index].ParentIndex < 0 && buffer)
+        FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    buffer = load_dynamic_stringW(row,3);
+    package->progids[index].ClassIndex = load_given_class(package,buffer);
+    if (package->progids[index].ClassIndex< 0 && buffer)
+        FIXME("Unknown class %s\n",debugstr_w(buffer));
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    package->progids[index].Description = load_dynamic_stringW(row,4);
 
-    if (!MSI_RecordIsNull(row,7)) 
+    if (!MSI_RecordIsNull(row,6))
     {
-        static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
-        static const WCHAR szUser[] = 
-             {'I','n','t','e','r','a','c','t','i','v','e',' ',
-              'U','s','e','r',0};
+        INT icon_index = MSI_RecordGetInteger(row,6); 
+        LPWSTR FileName = load_dynamic_stringW(row,5);
+        LPWSTR FilePath;
+        static const WCHAR fmt[] = {'%','s',',','%','i',0};
+
+        build_icon_path(package,FileName,&FilePath);
+       
+        package->progids[index].IconPath = 
+                HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
+                                sizeof(WCHAR));
+
+        sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
 
-        if (MSI_RecordGetInteger(row,7))
-            RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
+        HeapFree(GetProcessHeap(),0,FilePath);
+        HeapFree(GetProcessHeap(),0,FileName);
+    }
+    else
+    {
+        buffer = load_dynamic_stringW(row,5);
+        if (buffer)
+            build_icon_path(package,buffer,&(package->progids[index].IconPath));
+        HeapFree(GetProcessHeap(),0,buffer);
     }
 
-    msiobj_release(&row->hdr);
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
-    RegCloseKey(hkey3);
-    RegCloseKey(hkey2);
-    return rc;
+    return index;
 }
 
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
 {
-    /* 
-     * Again I am assuming the words, "Whose key file represents" when referring
-     * to a Component as to meaning that Components KeyPath file
-     *
-     * Also there is a very strong connection between ClassInfo and ProgID
-     * that I am mostly glossing over.  
-     * What would be more propper is to load the ClassInfo and the ProgID info
-     * into memory data structures and then be able to enable and disable them
-     * based on component. 
-     */
-    
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
+    INT rc;
+    MSIQUERY *view;
+    MSIRECORD *row;
+    INT i;
     static const WCHAR ExecSeqQuery[] =
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','C','l','a','s','s','`',0};
-    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-    static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
-    static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
-    static const WCHAR szSpace[] = {' ',0};
-    HKEY hkey,hkey2,hkey3;
-    LPWSTR argument,deformated;
+         '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
+         '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
+    if (!progid)
+        return -1;
 
-    rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
+    /* check for progids already loaded */
+    for (i = 0; i < package->loaded_progids; i++)
+        if (strcmpiW(package->progids[i].ProgID,progid)==0)
+        {
+            TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
+            return i;
+        }
+    
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, progid);
     if (rc != ERROR_SUCCESS)
-        return ERROR_FUNCTION_FAILED;
+        return -1;
 
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    rc = MSI_ViewExecute(view, 0);
     if (rc != ERROR_SUCCESS)
     {
-        rc = ERROR_SUCCESS;
-        goto end;
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
     }
 
-    rc = MSI_ViewExecute(view, 0);
+    rc = MSI_ViewFetch(view,&row);
     if (rc != ERROR_SUCCESS)
     {
         MSI_ViewClose(view);
         msiobj_release(&view->hdr);
-        goto end;
+        return -1;
     }
 
-    while (1)
-    {
-        WCHAR clsid[0x100];
-        WCHAR buffer[0x100];
-        WCHAR desc[0x100];
-        DWORD sz;
-        INT index;
-        DWORD size;
-     
-        rc = MSI_ViewFetch(view,&row);
-        if (rc != ERROR_SUCCESS)
-        {
-            rc = ERROR_SUCCESS;
-            break;
-        }
+    rc = load_progid(package, row);
+    msiobj_release(&row->hdr);
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
 
-        sz=0x100;
-        MSI_RecordGetStringW(row,3,buffer,&sz);
+    return rc;
+}
 
-        index = get_loaded_component(package,buffer);
+static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
+{
+    DWORD index = package->loaded_classes;
+    DWORD sz,i;
+    LPWSTR buffer;
 
-        if (index < 0)
-        {
-            msiobj_release(&row->hdr);
-            continue;
-        }
+    /* fill in the data */
 
-        if ((!ACTION_VerifyComponentForAction(package, index,
-                                INSTALLSTATE_LOCAL)) &&
-            (!ACTION_VerifyComponentForAction(package, index,
-                                INSTALLSTATE_ADVERTISED)))
-        {
-            TRACE("Skipping class reg due to disabled component\n");
-            msiobj_release(&row->hdr);
+    package->loaded_classes++;
+    if (package->loaded_classes== 1)
+        package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
+    else
+        package->classes = HeapReAlloc(GetProcessHeap(),0,
+            package->classes, package->loaded_classes * sizeof(MSICLASS));
 
-            package->components[index].Action =
-                package->components[index].Installed;
+    memset(&package->classes[index],0,sizeof(MSICLASS));
 
-            continue;
-        }
+    sz = IDENTIFIER_SIZE;
+    MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
+    TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
+    sz = IDENTIFIER_SIZE;
+    MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
+    buffer = load_dynamic_stringW(row,3);
+    package->classes[index].ComponentIndex = get_loaded_component(package, 
+                    buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-        package->components[index].Action = INSTALLSTATE_LOCAL;
+    package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
+    package->classes[index].ProgIDIndex = 
+                load_given_progid(package, package->classes[index].ProgIDText);
+
+    package->classes[index].Description = load_dynamic_stringW(row,5);
+
+    buffer = load_dynamic_stringW(row,6);
+    if (buffer)
+        package->classes[index].AppIDIndex = 
+                load_given_appid(package, buffer);
+    else
+        package->classes[index].AppIDIndex = -1;
+    HeapFree(GetProcessHeap(),0,buffer);
 
-        sz=0x100;
-        MSI_RecordGetStringW(row,1,clsid,&sz);
-        RegCreateKeyW(hkey,clsid,&hkey2);
+    package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
 
-        if (!MSI_RecordIsNull(row,5))
-        {
-            sz=0x100;
-            MSI_RecordGetStringW(row,5,desc,&sz);
+    if (!MSI_RecordIsNull(row,9))
+    {
 
-            RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
-                           (strlenW(desc)+1)*sizeof(WCHAR));
-        }
-        else
-            desc[0]=0;
+        INT icon_index = MSI_RecordGetInteger(row,9); 
+        LPWSTR FileName = load_dynamic_stringW(row,8);
+        LPWSTR FilePath;
+        static const WCHAR fmt[] = {'%','s',',','%','i',0};
 
-        sz=0x100;
-        MSI_RecordGetStringW(row,2,buffer,&sz);
+        build_icon_path(package,FileName,&FilePath);
+       
+        package->classes[index].IconPath = 
+                HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
+                                sizeof(WCHAR));
 
-        RegCreateKeyW(hkey2,buffer,&hkey3);
+        sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
 
-        index = get_loaded_file(package,package->components[index].KeyPath);
+        HeapFree(GetProcessHeap(),0,FilePath);
+        HeapFree(GetProcessHeap(),0,FileName);
+    }
+    else
+    {
+        buffer = load_dynamic_stringW(row,8);
+        if (buffer)
+            build_icon_path(package,buffer,&(package->classes[index].IconPath));
+        HeapFree(GetProcessHeap(),0,buffer);
+    }
+
+    if (!MSI_RecordIsNull(row,10))
+    {
+        i = MSI_RecordGetInteger(row,10);
+        if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
+        {
+            static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
+            static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
 
-        argument = load_dynamic_stringW(row,11); 
-        size = deformat_string(package,argument,&deformated);
-        if (deformated)
-            size+=sizeof(WCHAR);
-        HeapFree(GetProcessHeap(),0,argument);
-        size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR);
-
-        argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR));
-        strcpyW(argument,package->files[index].TargetPath);
-        if (deformated)
+            switch(i)
+            {
+                case 1:
+                    package->classes[index].DefInprocHandler = strdupW(ole2);
+                    break;
+                case 2:
+                    package->classes[index].DefInprocHandler32 = strdupW(ole32);
+                    break;
+                case 3:
+                    package->classes[index].DefInprocHandler = strdupW(ole2);
+                    package->classes[index].DefInprocHandler32 = strdupW(ole32);
+                    break;
+            }
+        }
+        else
         {
-            strcatW(argument,szSpace);
-            strcatW(argument,deformated);
+            package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
+                            row, 10);
+            reduce_to_longfilename(package->classes[index].DefInprocHandler32);
         }
+    }
+    buffer = load_dynamic_stringW(row,11);
+    deformat_string(package,buffer,&package->classes[index].Argument);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-        RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
-        HeapFree(GetProcessHeap(),0,deformated);
-        HeapFree(GetProcessHeap(),0,argument);
+    buffer = load_dynamic_stringW(row,12);
+    package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-        RegCloseKey(hkey3);
+    package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
+    
+    return index;
+}
 
-        if (!MSI_RecordIsNull(row,4))
-        {
-            sz=0x100;
-            MSI_RecordGetStringW(row,4,buffer,&sz);
+/*
+ * the Class table has 3 primary keys. Generally it is only 
+ * referenced through the first CLSID key. However when loading
+ * all of the classes we need to make sure we do not ignore rows
+ * with other Context and ComponentIndexs 
+ */
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
+{
+    INT rc;
+    MSIQUERY *view;
+    MSIRECORD *row;
+    INT i;
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
+         '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
 
-            RegCreateKeyW(hkey2,szProgID,&hkey3);
-    
-            RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
-                       (strlenW(buffer)+1)*sizeof(WCHAR));
 
-            RegCloseKey(hkey3);
+    if (!classid)
+        return -1;
+    
+    /* check for classes already loaded */
+    for (i = 0; i < package->loaded_classes; i++)
+        if (strcmpiW(package->classes[i].CLSID,classid)==0)
+        {
+            TRACE("found class %s at index %i\n",debugstr_w(classid), i);
+            return i;
         }
+    
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, classid);
+    if (rc != ERROR_SUCCESS)
+        return -1;
 
-        if (!MSI_RecordIsNull(row,6))
-        { 
-            sz=0x100;
-            MSI_RecordGetStringW(row,6,buffer,&sz);
+    rc = MSI_ViewExecute(view, 0);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
+    }
 
-            RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
-                       (strlenW(buffer)+1)*sizeof(WCHAR));
+    rc = MSI_ViewFetch(view,&row);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
+    }
 
-            register_appid(package,buffer,desc);
-        }
+    rc = load_class(package, row);
+    msiobj_release(&row->hdr);
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
 
+    return rc;
+}
 
-        if (!MSI_RecordIsNull(row,7))
-        {
-            FIXME("Process field 7\n");
-        }
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
 
-        if (!MSI_RecordIsNull(row,8))
-        {
-            static const WCHAR szDefaultIcon[] = 
-                {'D','e','f','a','u','l','t','I','c','o','n',0};
+static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
+{
+    DWORD index = package->loaded_mimes;
+    DWORD sz;
+    LPWSTR buffer;
 
-            LPWSTR FileName = load_dynamic_stringW(row,8);
-            LPWSTR FilePath;
-            INT index;
+    /* fill in the data */
 
-            RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
-            build_icon_path(package,FileName,&FilePath);
-            if (!MSI_RecordIsNull(row,9))
-            {
-                static const WCHAR index_fmt[] = {',','%','i',0};
-                WCHAR index_buf[20];
-                index = MSI_RecordGetInteger(row,9);
-                sprintfW(index_buf,index_fmt,index);
-                size = strlenW(FilePath)+strlenW(index_buf)+1;
-                size *= sizeof(WCHAR);
-                HeapReAlloc(GetProcessHeap(),0,FilePath,size);
-            }
-            RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath,
-                           (strlenW(FilePath)+1) * sizeof(WCHAR));
-            HeapFree(GetProcessHeap(),0,FilePath);
-            HeapFree(GetProcessHeap(),0,FileName);
-            RegCloseKey(hkey3);
-        }
+    package->loaded_mimes++;
+    if (package->loaded_mimes== 1)
+        package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
+    else
+        package->mimes= HeapReAlloc(GetProcessHeap(),0,
+            package->mimes, package->loaded_mimes* 
+            sizeof(MSIMIME));
+
+    memset(&package->mimes[index],0,sizeof(MSIMIME));
+
+    package->mimes[index].ContentType = load_dynamic_stringW(row,1); 
+    TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
+
+    buffer = load_dynamic_stringW(row,2);
+    package->mimes[index].ExtensionIndex = load_given_extension(package,
+                    buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-        if (!MSI_RecordIsNull(row,10))
-        {
-            static const WCHAR szInproc32[] =
-                {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
-                 0};
-            static const WCHAR szInproc[] =
-                {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
-            INT i = MSI_RecordGetInteger(row,10);
-            if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
-            {
-                static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
-                static const WCHAR ole32[] =
-                    {'o','l','e','3','2','.','d','l','l',0};
-                switch(i)
-                {
-                    case 1:
-                        size = strlenW(ole2) * sizeof(WCHAR);
-                        RegCreateKeyW(hkey2,szInproc,&hkey3);
-                        RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
-                        RegCloseKey(hkey3);
-                        break;
-                    case 2:
-                        size = strlenW(ole32) * sizeof(WCHAR);
-                        RegCreateKeyW(hkey2,szInproc32,&hkey3);
-                        RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
-                        RegCloseKey(hkey3);
-                        break;
-                    case 3:
-                        size = strlenW(ole2) * sizeof(WCHAR);
-                        RegCreateKeyW(hkey2,szInproc,&hkey3);
-                        RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
-                        RegCloseKey(hkey3);
-                        size = strlenW(ole32) * sizeof(WCHAR);
-                        RegCreateKeyW(hkey2,szInproc32,&hkey3);
-                        RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
-                        RegCloseKey(hkey3);
-                        break;
-                }
-                
-            }
-            else
-            {
-                RegCreateKeyW(hkey2,szInproc32,&hkey3);
-                argument = load_dynamic_stringW(row,10);
-                reduce_to_longfilename(argument);
-                size = strlenW(argument)*sizeof(WCHAR);
+    sz = IDENTIFIER_SIZE;
+    MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
+    package->mimes[index].ClassIndex= load_given_class(package,
+                    package->mimes[index].CLSID);
+    
+    return index;
+}
 
-                RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
-                HeapFree(GetProcessHeap(),0,argument);
+static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
+{
+    INT rc;
+    MSIQUERY *view;
+    MSIRECORD *row;
+    INT i;
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
+         '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
+         '\'','%','s','\'',0};
 
-                RegCloseKey(hkey3);
-            }
+    if (!mime)
+        return -1;
+    
+    /* check for mime already loaded */
+    for (i = 0; i < package->loaded_mimes; i++)
+        if (strcmpiW(package->mimes[i].ContentType,mime)==0)
+        {
+            TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
+            return i;
         }
+    
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, mime);
+    if (rc != ERROR_SUCCESS)
+        return -1;
 
-        RegCloseKey(hkey2);
-
-        ui_actiondata(package,szRegisterClassInfo,row);
+    rc = MSI_ViewExecute(view, 0);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
+    }
 
-        msiobj_release(&row->hdr);
+    rc = MSI_ViewFetch(view,&row);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
     }
+
+    rc = load_mime(package, row);
+    msiobj_release(&row->hdr);
     MSI_ViewClose(view);
     msiobj_release(&view->hdr);
 
-end:
-    RegCloseKey(hkey);
     return rc;
 }
 
-static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, 
-                                LPWSTR clsid)
+static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
 {
-    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-    static const WCHAR szDefaultIcon[] =
-        {'D','e','f','a','u','l','t','I','c','o','n',0};
-    HKEY hkey,hkey2;
-    WCHAR buffer[0x100];
+    DWORD index = package->loaded_extensions;
     DWORD sz;
+    LPWSTR buffer;
+
+    /* fill in the data */
 
+    package->loaded_extensions++;
+    if (package->loaded_extensions == 1)
+        package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
+    else
+        package->extensions = HeapReAlloc(GetProcessHeap(),0,
+            package->extensions, package->loaded_extensions* 
+            sizeof(MSIEXTENSION));
+
+    memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
+
+    sz = 256;
+    MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
+    TRACE("loading extension %s\n",
+                    debugstr_w(package->extensions[index].Extension));
+
+    buffer = load_dynamic_stringW(row,2);
+    package->extensions[index].ComponentIndex = 
+            get_loaded_component(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-    sz = 0x100;
-    MSI_RecordGetStringW(row,1,buffer,&sz);
-    RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
+    package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
+    package->extensions[index].ProgIDIndex = load_given_progid(package,
+                    package->extensions[index].ProgIDText);
 
-    if (!MSI_RecordIsNull(row,4))
-    {
-        sz = 0x100;
-        MSI_RecordGetStringW(row,4,buffer,&sz);
-        RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
-                       sizeof(WCHAR));
-    }
+    buffer = load_dynamic_stringW(row,4);
+    package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
 
-    if (!MSI_RecordIsNull(row,3))
-    {   
-        sz = 0x100;
+    buffer = load_dynamic_stringW(row,5);
+    package->extensions[index].FeatureIndex = 
+            get_loaded_feature(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    return index;
+}
+
+/*
+ * While the extension table has 2 primary keys, this function is only looking
+ * at the Extension key which is what is referenced as a forign key 
+ */
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
+{
+    INT rc;
+    MSIQUERY *view;
+    MSIRECORD *row;
+    INT i;
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','E','x','t','e','n','s','i','o','n','`',' ',
+         'W','H','E','R','E',' ',
+         '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
+         '\'','%','s','\'',0};
+
+    if (!extension)
+        return -1;
+
+    /* check for extensions already loaded */
+    for (i = 0; i < package->loaded_extensions; i++)
+        if (strcmpiW(package->extensions[i].Extension,extension)==0)
+        {
+            TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
+                            i);
+            return i;
+        }
     
-        MSI_RecordGetStringW(row,3,buffer,&sz);
-        RegCreateKeyW(hkey,szCLSID,&hkey2);
-        RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
-                       sizeof(WCHAR));
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, extension);
+    if (rc != ERROR_SUCCESS)
+        return -1;
 
-        if (clsid)
-            strcpyW(clsid,buffer);
+    rc = MSI_ViewExecute(view, 0);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
+    }
 
-        RegCloseKey(hkey2);
+    rc = MSI_ViewFetch(view,&row);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return -1;
     }
+
+    rc = load_extension(package, row);
+    msiobj_release(&row->hdr);
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
+
+    return rc;
+}
+
+static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
+{
+    MSIPACKAGE* package = (MSIPACKAGE*)param;
+    DWORD index = package->loaded_verbs;
+    LPWSTR buffer;
+
+    /* fill in the data */
+
+    package->loaded_verbs++;
+    if (package->loaded_verbs == 1)
+        package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
     else
+        package->verbs = HeapReAlloc(GetProcessHeap(),0,
+            package->verbs , package->loaded_verbs * sizeof(MSIVERB));
+
+    memset(&package->verbs[index],0,sizeof(MSIVERB));
+
+    buffer = load_dynamic_stringW(row,1);
+    package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
+    if (package->verbs[index].ExtensionIndex < 0 && buffer)
+        ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    package->verbs[index].Verb = load_dynamic_stringW(row,2);
+    TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
+    package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
+
+    buffer = load_dynamic_stringW(row,4);
+    deformat_string(package,buffer,&package->verbs[index].Command);
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    buffer = load_dynamic_stringW(row,5);
+    deformat_string(package,buffer,&package->verbs[index].Argument);
+    HeapFree(GetProcessHeap(),0,buffer);
+
+    /* assosiate the verb with the correct extension */
+    if (package->verbs[index].ExtensionIndex >= 0)
     {
-        FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
-        return ERROR_FUNCTION_FAILED;
+        MSIEXTENSION* extension = &package->extensions[package->verbs[index].
+                ExtensionIndex];
+        int count = extension->VerbCount;
+
+        if (count >= 99)
+            FIXME("Exceeding max verb count! Increase that limit!!!\n");
+        else
+        {
+            extension->VerbCount++;
+            extension->Verbs[count] = index;
+        }
     }
-    if (!MSI_RecordIsNull(row,5))
-    {
-        INT index = MSI_RecordGetInteger(row,6); 
-        LPWSTR FileName = load_dynamic_stringW(row,5);
-        LPWSTR FilePath,IconPath;
-        static const WCHAR fmt[] = {'%','s',',','%','i',0};
+    
+    return ERROR_SUCCESS;
+}
 
-        RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
-        build_icon_path(package,FileName,&FilePath);
-       
-        IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
-                    sizeof(WCHAR));
+static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
+{
+    LPWSTR clsid;
+    LPWSTR context;
+    LPWSTR buffer;
+    INT    component_index;
+    MSIPACKAGE* package =(MSIPACKAGE*)param;
+    INT i;
+    BOOL match = FALSE;
 
-        sprintfW(IconPath,fmt,FilePath,index);
-        RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,
-                           (strlenW(IconPath)+1) * sizeof(WCHAR));
-        HeapFree(GetProcessHeap(),0,FilePath);
-        HeapFree(GetProcessHeap(),0,FileName);
-        RegCloseKey(hkey2);
+    clsid = load_dynamic_stringW(rec,1);
+    context = load_dynamic_stringW(rec,2);
+    buffer = load_dynamic_stringW(rec,3);
+    component_index = get_loaded_component(package,buffer);
+
+    for (i = 0; i < package->loaded_classes; i++)
+    {
+        if (strcmpiW(clsid,package->classes[i].CLSID))
+            continue;
+        if (strcmpW(context,package->classes[i].Context))
+            continue;
+        if (component_index == package->classes[i].ComponentIndex)
+        {
+            match = TRUE;
+            break;
+        }
     }
+    
+    HeapFree(GetProcessHeap(),0,buffer);
+    HeapFree(GetProcessHeap(),0,clsid);
+    HeapFree(GetProcessHeap(),0,context);
+
+    if (!match)
+        load_class(package, rec);
+
     return ERROR_SUCCESS;
 }
 
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
-
-static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, 
-                                   LPWSTR clsid)
+static VOID load_all_classes(MSIPACKAGE *package)
 {
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    static const WCHAR Query_t[] = 
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','P','r','o','g' ,'I','d','`',' ','W','H','E','R','E',' ',
-         '`','P','r','o','g','I','d','`',' ','=',' ','\'' ,'%','s','\'',0};
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY *view;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+         '`','C','l','a','s','s','`',0};
 
-    rc = MSI_OpenQuery(package->db, &view, Query_t, parent);
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
     if (rc != ERROR_SUCCESS)
-        return rc;
+        return;
 
-    rc = MSI_ViewExecute(view, 0);
-    if (rc != ERROR_SUCCESS)
+    rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
+    msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
+{
+    LPWSTR buffer;
+    LPWSTR extension;
+    INT    component_index;
+    MSIPACKAGE* package =(MSIPACKAGE*)param;
+    BOOL match = FALSE;
+    INT i;
+
+    extension = load_dynamic_stringW(rec,1);
+    buffer = load_dynamic_stringW(rec,2);
+    component_index = get_loaded_component(package,buffer);
+
+    for (i = 0; i < package->loaded_extensions; i++)
+    {
+        if (strcmpiW(extension,package->extensions[i].Extension))
+            continue;
+        if (component_index == package->extensions[i].ComponentIndex)
+        {
+            match = TRUE;
+            break;
+        }
+    }
+
+    HeapFree(GetProcessHeap(),0,buffer);
+    HeapFree(GetProcessHeap(),0,extension);
+
+    if (!match)
+        load_extension(package, rec);
+
+    return ERROR_SUCCESS;
+}
+
+static VOID load_all_extensions(MSIPACKAGE *package)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY *view;
+
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','E','x','t','e','n','s','i','o','n','`',0};
+
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    if (rc != ERROR_SUCCESS)
+        return;
+
+    rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
+    msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
+{
+    LPWSTR buffer;
+    MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+    buffer = load_dynamic_stringW(rec,1);
+    load_given_progid(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
+    return ERROR_SUCCESS;
+}
+
+static VOID load_all_progids(MSIPACKAGE *package)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY *view;
+
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
+         'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
+
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    if (rc != ERROR_SUCCESS)
+        return;
+
+    rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
+    msiobj_release(&view->hdr);
+}
+
+static VOID load_all_verbs(MSIPACKAGE *package)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY *view;
+
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','V','e','r','b','`',0};
+
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    if (rc != ERROR_SUCCESS)
+        return;
+
+    rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
+    msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
+{
+    LPWSTR buffer;
+    MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+    buffer = load_dynamic_stringW(rec,1);
+    load_given_mime(package,buffer);
+    HeapFree(GetProcessHeap(),0,buffer);
+    return ERROR_SUCCESS;
+}
+
+static VOID load_all_mimes(MSIPACKAGE *package)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY *view;
+
+    static const WCHAR ExecSeqQuery[] =
+        {'S','E','L','E','C','T',' ',
+         '`','C','o','n','t','e','n','t','T','y','p','e','`',
+         ' ','F','R','O','M',' ',
+         '`','M','I','M','E','`',0};
+
+    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+    if (rc != ERROR_SUCCESS)
+        return;
+
+    rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
+    msiobj_release(&view->hdr);
+}
+
+static void load_classes_and_such(MSIPACKAGE *package)
+{
+    TRACE("Loading all the class info and related tables\n");
+
+    /* check if already loaded */
+    if (package->classes || package->extensions || package->progids || 
+        package->verbs || package->mimes)
+        return;
+
+    load_all_classes(package);
+    load_all_extensions(package);
+    load_all_progids(package);
+    /* these loads must come after the other loads */
+    load_all_verbs(package);
+    load_all_mimes(package);
+}
+
+static void mark_progid_for_install(MSIPACKAGE* package, INT index)
+{
+    MSIPROGID* progid;
+    int i;
+
+    if (index < 0 || index >= package->loaded_progids)
+        return;
+
+    progid = &package->progids[index];
+
+    if (progid->InstallMe == TRUE)
+        return;
+
+    progid->InstallMe = TRUE;
+
+    /* all children if this is a parent also install */
+   for (i = 0; i < package->loaded_progids; i++)
+        if (package->progids[i].ParentIndex == index)
+            mark_progid_for_install(package,i);
+}
+
+static void mark_mime_for_install(MSIPACKAGE* package, INT index)
+{
+    MSIMIME* mime;
+
+    if (index < 0 || index >= package->loaded_mimes)
+        return;
+
+    mime = &package->mimes[index];
+
+    if (mime->InstallMe == TRUE)
+        return;
+
+    mime->InstallMe = TRUE;
+}
+
+static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
+{
+    static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+    HKEY hkey2,hkey3;
+
+    if (!package)
+        return ERROR_INVALID_HANDLE;
+
+    RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
+    RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
+    RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
+                   (strlenW(app)+1)*sizeof(WCHAR));
+
+    if (package->appids[appidIndex].RemoteServerName)
+    {
+        UINT size; 
+        static const WCHAR szRemoteServerName[] =
+             {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
+              0};
+
+        size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * 
+                sizeof(WCHAR);
+
+        RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
+                        (LPVOID)package->appids[appidIndex].RemoteServerName,
+                        size);
+    }
+
+    if (package->appids[appidIndex].LocalServer)
+    {
+        static const WCHAR szLocalService[] =
+             {'L','o','c','a','l','S','e','r','v','i','c','e',0};
+        UINT size;
+        size = (strlenW(package->appids[appidIndex].LocalServer)+1) * 
+                sizeof(WCHAR);
+
+        RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
+                        (LPVOID)package->appids[appidIndex].LocalServer,size);
+    }
+
+    if (package->appids[appidIndex].ServiceParameters)
+    {
+        static const WCHAR szService[] =
+             {'S','e','r','v','i','c','e',
+              'P','a','r','a','m','e','t','e','r','s',0};
+        UINT size;
+        size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * 
+                sizeof(WCHAR);
+        RegSetValueExW(hkey3,szService,0,REG_SZ,
+                        (LPVOID)package->appids[appidIndex].ServiceParameters,
+                        size);
+    }
+
+    if (package->appids[appidIndex].DllSurrogate)
+    {
+        static const WCHAR szDLL[] =
+             {'D','l','l','S','u','r','r','o','g','a','t','e',0};
+        UINT size;
+        size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * 
+                sizeof(WCHAR);
+        RegSetValueExW(hkey3,szDLL,0,REG_SZ,
+                        (LPVOID)package->appids[appidIndex].DllSurrogate,size);
+    }
+
+    if (package->appids[appidIndex].ActivateAtStorage)
+    {
+        static const WCHAR szActivate[] =
+             {'A','c','t','i','v','a','t','e','A','s',
+              'S','t','o','r','a','g','e',0};
+        static const WCHAR szY[] = {'Y',0};
+
+        RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
+    }
+
+    if (package->appids[appidIndex].RunAsInteractiveUser)
+    {
+        static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
+        static const WCHAR szUser[] = 
+             {'I','n','t','e','r','a','c','t','i','v','e',' ',
+              'U','s','e','r',0};
+
+        RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
+    }
+
+    RegCloseKey(hkey3);
+    RegCloseKey(hkey2);
+    return ERROR_SUCCESS;
+}
+
+static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
+{
+    /* 
+     * Again I am assuming the words, "Whose key file represents" when referring
+     * to a Component as to meaning that Components KeyPath file
+     */
+    
+    UINT rc;
+    MSIRECORD *uirow;
+    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+    static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
+    static const WCHAR szVIProgID[] = { '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 const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+    static const WCHAR szSpace[] = {' ',0};
+    HKEY hkey,hkey2,hkey3;
+    int i;
+
+    if (!package)
+        return ERROR_INVALID_HANDLE;
+
+    load_classes_and_such(package);
+    rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
+    if (rc != ERROR_SUCCESS)
+        return ERROR_FUNCTION_FAILED;
+
+    for (i = 0; i < package->loaded_classes; i++)
+    {
+        INT index,f_index;;
+        DWORD size, sz;
+        LPWSTR argument;
+     
+        if (package->classes[i].ComponentIndex < 0)
+        {
+            continue;
+        }
+
+        index = package->classes[i].ComponentIndex;
+        f_index = package->classes[i].FeatureIndex;
+
+        /* 
+         * yes. MSDN says that these are based on _Feature_ not on
+         * Component.  So verify the feature is to be installed
+         */
+        if ((!ACTION_VerifyFeatureForAction(package, f_index,
+                                INSTALLSTATE_LOCAL)) &&
+            (!ACTION_VerifyFeatureForAction(package, f_index,
+                                INSTALLSTATE_ADVERTISED)))
+        {
+            TRACE("Skipping class %s reg due to disabled feature %s\n", 
+                            debugstr_w(package->classes[i].CLSID), 
+                            debugstr_w(package->features[f_index].Feature));
+
+            continue;
+        }
+
+        TRACE("Registering index %i  class %s\n",i,
+                        debugstr_w(package->classes[i].CLSID));
+
+        package->classes[i].Installed = TRUE;
+        if (package->classes[i].ProgIDIndex >= 0)
+            mark_progid_for_install(package, package->classes[i].ProgIDIndex);
+
+        RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
+
+        if (package->classes[i].Description)
+            RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
+                            Description, (strlenW(package->classes[i].
+                                     Description)+1)*sizeof(WCHAR));
+
+        RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
+        index = get_loaded_file(package,package->components[index].KeyPath);
+
+
+        /* the context server is a short path name */
+        sz = 0;
+        sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
+        if (sz == 0)
+        {
+            ERR("Unable to find short path for CLSID COM Server\n");
+        }
+        else
+        {
+             size = sz * sizeof(WCHAR);
+
+            if (package->classes[i].Argument)
+            {
+                size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
+                size += sizeof(WCHAR);
+            }
+
+            argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
+            GetShortPathNameW(package->files[index].TargetPath, argument, sz);
+
+            if (package->classes[i].Argument)
+            {
+                strcatW(argument,szSpace);
+                strcatW(argument,package->classes[i].Argument);
+            }
+
+            RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
+            HeapFree(GetProcessHeap(),0,argument);
+        }
+
+        RegCloseKey(hkey3);
+
+        if (package->classes[i].ProgIDIndex >= 0 || 
+            package->classes[i].ProgIDText)
+        {
+            LPCWSTR progid;
+
+            if (package->classes[i].ProgIDIndex >= 0)
+                progid = package->progids[
+                        package->classes[i].ProgIDIndex].ProgID;
+            else
+                progid = package->classes[i].ProgIDText;
+
+            RegCreateKeyW(hkey2,szProgID,&hkey3);
+            RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
+                            (strlenW(progid)+1) *sizeof(WCHAR));
+            RegCloseKey(hkey3);
+
+            if (package->classes[i].ProgIDIndex >= 0 &&
+                package->progids[package->classes[i].ProgIDIndex].ParentIndex 
+                            >= 0)
+            {
+                progid = package->progids[package->progids[
+                        package->classes[i].ProgIDIndex].ParentIndex].ProgID;
+
+                RegCreateKeyW(hkey2,szVIProgID,&hkey3);
+                RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
+                            (strlenW(progid)+1) *sizeof(WCHAR));
+                RegCloseKey(hkey3);
+            }
+        }
+
+        if (package->classes[i].AppIDIndex >= 0)
+        { 
+            RegSetValueExW(hkey2,szAppID,0,REG_SZ,
+             (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
+             (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
+             *sizeof(WCHAR));
+
+            register_appid(package,package->classes[i].AppIDIndex,
+                            package->classes[i].Description);
+        }
+
+        if (package->classes[i].FileTypeMask)
+        {
+            FIXME("Process field 7\n");
+        }
+
+        if (package->classes[i].IconPath)
+        {
+            static const WCHAR szDefaultIcon[] = 
+                {'D','e','f','a','u','l','t','I','c','o','n',0};
+
+            RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
+
+            RegSetValueExW(hkey3,NULL,0,REG_SZ,
+                           (LPVOID)package->classes[i].IconPath,
+                           (strlenW(package->classes[i].IconPath)+1) * 
+                           sizeof(WCHAR));
+
+            RegCloseKey(hkey3);
+        }
+
+        if (package->classes[i].DefInprocHandler)
+        {
+            static const WCHAR szInproc[] =
+                {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
+
+            size = (strlenW(package->classes[i].DefInprocHandler) + 1) * 
+                    sizeof(WCHAR);
+            RegCreateKeyW(hkey2,szInproc,&hkey3);
+            RegSetValueExW(hkey3,NULL,0,REG_SZ, 
+                            (LPVOID)package->classes[i].DefInprocHandler, size);
+            RegCloseKey(hkey3);
+        }
+
+        if (package->classes[i].DefInprocHandler32)
+        {
+            static const WCHAR szInproc32[] =
+                {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
+                 0};
+            size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * 
+                    sizeof(WCHAR);
+
+            RegCreateKeyW(hkey2,szInproc32,&hkey3);
+            RegSetValueExW(hkey3,NULL,0,REG_SZ, 
+                           (LPVOID)package->classes[i].DefInprocHandler32,size);
+            RegCloseKey(hkey3);
+        }
+        
+        RegCloseKey(hkey2);
+
+        uirow = MSI_CreateRecord(1);
+
+        MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
+        ui_actiondata(package,szRegisterClassInfo,uirow);
+        msiobj_release(&uirow->hdr);
+    }
+
+    RegCloseKey(hkey);
+    return rc;
+}
+
+static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
+                                 LPWSTR clsid)
+{
+    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+    static const WCHAR szDefaultIcon[] =
+        {'D','e','f','a','u','l','t','I','c','o','n',0};
+    HKEY hkey,hkey2;
+
+    RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
+
+    if (progid->Description)
     {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        return rc;
+        RegSetValueExW(hkey,NULL,0,REG_SZ,
+                        (LPVOID)progid->Description, 
+                        (strlenW(progid->Description)+1) *
+                       sizeof(WCHAR));
     }
 
-    rc = MSI_ViewFetch(view,&row);
-    if (rc != ERROR_SUCCESS)
+    if (progid->ClassIndex >= 0)
+    {   
+        RegCreateKeyW(hkey,szCLSID,&hkey2);
+        RegSetValueExW(hkey2,NULL,0,REG_SZ,
+                        (LPVOID)package->classes[progid->ClassIndex].CLSID, 
+                        (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
+                        * sizeof(WCHAR));
+
+        if (clsid)
+            strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
+
+        RegCloseKey(hkey2);
+    }
+    else
     {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        return rc;
+        FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
     }
 
-    register_progid(package,row,clsid);
+    if (progid->IconPath)
+    {
+        RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
 
-    msiobj_release(&row->hdr);
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
-    return rc;
+        RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+                           (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
+        RegCloseKey(hkey2);
+    }
+    return ERROR_SUCCESS;
 }
 
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
+static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
+                LPWSTR clsid)
 {
     UINT rc = ERROR_SUCCESS; 
 
-    if (MSI_RecordIsNull(row,2))
-        rc = register_progid_base(package,row,clsid);
+    if (progid->ParentIndex < 0)
+        rc = register_progid_base(package, progid, clsid);
     else
     {
-        WCHAR buffer[0x1000];
-        DWORD sz, disp;
+        DWORD disp;
         HKEY hkey,hkey2;
         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
         static const WCHAR szDefaultIcon[] =
             {'D','e','f','a','u','l','t','I','c','o','n',0};
 
         /* check if already registered */
-        sz = 0x100;
-        MSI_RecordGetStringW(row,1,buffer,&sz);
-        RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
+        RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
         if (disp == REG_OPENED_EXISTING_KEY)
         {
@@ -4911,9 +5666,11 @@
             return rc;
         }
 
-        sz = 0x100;
-        MSI_RecordGetStringW(row,2,buffer,&sz);
-        rc = register_parent_progid(package,buffer,clsid);
+        TRACE("Registering Parent %s index %i\n",
+                    debugstr_w(package->progids[progid->ParentIndex].ProgID), 
+                    progid->ParentIndex);
+        rc = register_progid(package,&package->progids[progid->ParentIndex],
+                        clsid);
 
         /* clsid is same as parent */
         RegCreateKeyW(hkey,szCLSID,&hkey2);
@@ -4923,24 +5680,17 @@
         RegCloseKey(hkey2);
 
 
-        if (!MSI_RecordIsNull(row,4))
+        if (progid->Description)
         {
-            sz = 0x100;
-            MSI_RecordGetStringW(row,4,buffer,&sz);
-            RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
-                           (strlenW(buffer)+1) * sizeof(WCHAR));
+            RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
+                           (strlenW(progid->Description)+1) * sizeof(WCHAR));
         }
 
-        if (!MSI_RecordIsNull(row,5))
+        if (progid->IconPath)
         {
-            LPWSTR FileName = load_dynamic_stringW(row,5);
-            LPWSTR FilePath;
             RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
-            build_icon_path(package,FileName,&FilePath);
-            RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,
-                           (strlenW(FilePath)+1) * sizeof(WCHAR));
-            HeapFree(GetProcessHeap(),0,FilePath);
-            HeapFree(GetProcessHeap(),0,FileName);
+            RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+                           (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
             RegCloseKey(hkey2);
         }
 
@@ -4951,55 +5701,39 @@
 
 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
 {
-    /* 
-     * Sigh, here I am just brute force registering all progids
-     * this needs to be linked to the Classes that have been registered
-     * but the easiest way to do that is to load all these stuff into
-     * memory for easy checking.
-     *
-     * Gives me something to continue to work toward.
-     */
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    static const WCHAR Query[] =
-        {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
-         '`','P','r','o','g','I','d','`',0};
+    INT i;
+    MSIRECORD *uirow;
 
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
-    if (rc != ERROR_SUCCESS)
-        return ERROR_SUCCESS;
-
-    rc = MSI_ViewExecute(view, 0);
-    if (rc != ERROR_SUCCESS)
-    {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        return rc;
-    }
+    load_classes_and_such(package);
 
-    while (1)
+    for (i = 0; i < package->loaded_progids; i++)
     {
         WCHAR clsid[0x1000];
 
-        rc = MSI_ViewFetch(view,&row);
-        if (rc != ERROR_SUCCESS)
+        /* check if this progid is to be installed */
+
+        if (!package->progids[i].InstallMe)
         {
-            rc = ERROR_SUCCESS;
-            break;
+            TRACE("progid %s not scheduled to be installed\n",
+                             debugstr_w(package->progids[i].ProgID));
+            continue;
         }
-        
-        register_progid(package,row,clsid);
-        ui_actiondata(package,szRegisterProgIdInfo,row);
+       
+        TRACE("Registering progid %s index %i\n",
+                        debugstr_w(package->progids[i].ProgID), i);
 
-        msiobj_release(&row->hdr);
+        register_progid(package,&package->progids[i],clsid);
+
+        uirow = MSI_CreateRecord(1);
+        MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
+        ui_actiondata(package,szRegisterProgIdInfo,uirow);
+        msiobj_release(&uirow->hdr);
     }
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
-    return rc;
+
+    return ERROR_SUCCESS;
 }
 
 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
@@ -5011,9 +5745,10 @@
     UINT rc;
 
     static const WCHAR szInstaller[] = 
-        {'I','n','s','t','a','l','l','e','r','\\',0};
+        {'M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\',0};
     static const WCHAR szFolder[] =
-        {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
+        {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
 
     ProductCode = load_dynamic_property(package,szProductCode,&rc);
     if (!ProductCode)
@@ -5999,102 +6734,229 @@
     return ERROR_SUCCESS;
 }
 
+static LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
+                MSICOMPONENT* component, LPCWSTR feature)
+{
+    LPWSTR productid=NULL;
+    GUID clsid;
+    WCHAR productid_85[21];
+    WCHAR component_85[21];
+    /*
+     * I have a fair bit of confusion as to when a < is used and when a > is
+     * used. I do not think i have it right...
+     *
+     * Ok it appears that the > is used if there is a guid for the compoenent
+     * and the < is used if not.
+     */
+    static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
+    static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
+    LPWSTR output = NULL;
+    DWORD sz = 0;
+
+    memset(productid_85,0,sizeof(productid_85));
+    memset(component_85,0,sizeof(component_85));
+
+    productid = load_dynamic_property(package,szProductCode,NULL);
+    CLSIDFromString(productid, &clsid);
+    
+    encode_base85_guid(&clsid,productid_85);
+
+    CLSIDFromString(component->ComponentId, &clsid);
+    encode_base85_guid(&clsid,component_85);
+
+    TRACE("Doing something with this... %s %s %s\n", 
+            debugstr_w(productid_85), debugstr_w(feature),
+            debugstr_w(component_85));
+ 
+    sz = lstrlenW(productid_85) + lstrlenW(feature);
+    if (component)
+        sz += lstrlenW(component_85);
+
+    sz+=3;
+    sz *= sizeof(WCHAR);
+           
+    output = HeapAlloc(GetProcessHeap(),0,sz);
+    memset(output,0,sz);
+
+    if (component)
+        sprintfW(output,fmt2,productid_85,feature,component_85);
+    else
+        sprintfW(output,fmt1,productid_85,feature);
+
+    HeapFree(GetProcessHeap(),0,productid);
+    
+    return output;
+}
+
+static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
+                MSICOMPONENT* component, MSIEXTENSION* extension,
+                MSIVERB* verb, INT* Sequence )
+{
+    LPWSTR keyname;
+    HKEY key;
+    static const WCHAR szShell[] = {'s','h','e','l','l',0};
+    static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
+    static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
+    static const WCHAR fmt2[] = {'\"','%','s','\"',0};
+    LPWSTR command;
+    DWORD size;
+    LPWSTR advertise;
+
+    keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
+
+    TRACE("Making Key %s\n",debugstr_w(keyname));
+    RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+    size = strlenW(component->FullKeypath);
+    if (verb->Argument)
+        size += strlenW(verb->Argument);
+     size += 4;
+
+     command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+     if (verb->Argument)
+        sprintfW(command, fmt, component->FullKeypath, verb->Argument);
+     else
+        sprintfW(command, fmt2, component->FullKeypath);
+
+     RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
+                     sizeof(WCHAR));
+     HeapFree(GetProcessHeap(),0,command);
+
+     advertise = create_component_advertise_string(package, component, 
+                        package->features[extension->FeatureIndex].Feature);
+
+     size = strlenW(advertise);
+
+     if (verb->Argument)
+        size += strlenW(verb->Argument);
+     size += 4;
+
+     command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+     memset(command,0,size*sizeof(WCHAR));
+
+     strcpyW(command,advertise);
+     if (verb->Argument)
+     {
+        static const WCHAR szSpace[] = {' ',0};
+         strcatW(command,szSpace);
+         strcatW(command,verb->Argument);
+     }
+
+     RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
+                        (strlenW(command)+2)*sizeof(WCHAR));
+     
+     RegCloseKey(key);
+     HeapFree(GetProcessHeap(),0,keyname);
+     HeapFree(GetProcessHeap(),0,advertise);
+     HeapFree(GetProcessHeap(),0,command);
+
+     if (verb->Command)
+     {
+        keyname = build_directory_name(3, progid, szShell, verb->Verb);
+        RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+        RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
+                                    (strlenW(verb->Command)+1) *sizeof(WCHAR));
+        RegCloseKey(key);
+        HeapFree(GetProcessHeap(),0,keyname);
+     }
+
+     if (verb->Sequence != MSI_NULL_INTEGER)
+     {
+        if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
+        {
+            *Sequence = verb->Sequence;
+            keyname = build_directory_name(2, progid, szShell);
+            RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+            RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
+                            (strlenW(verb->Verb)+1) *sizeof(WCHAR));
+            RegCloseKey(key);
+            HeapFree(GetProcessHeap(),0,keyname);
+        }
+    }
+    return ERROR_SUCCESS;
+}
 
 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
 {
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','E','x','t','e','n','s','i','o','n','`',0};
     static const WCHAR szContentType[] = 
         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
     HKEY hkey;
+    INT i;
+    MSIRECORD *uirow;
 
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
-    if (rc != ERROR_SUCCESS)
-    {
-        rc = ERROR_SUCCESS;
-        goto end;
-    }
-
-    rc = MSI_ViewExecute(view, 0);
-    if (rc != ERROR_SUCCESS)
-    {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        goto end;
-    }
+    load_classes_and_such(package);
 
-    while (1)
+    for (i = 0; i < package->loaded_extensions; i++)
     {
-        WCHAR buffer[0x100];
         WCHAR extension[257];
-        LPWSTR exten;
-        DWORD sz;
-        INT index;
+        INT index,f_index;
      
-        rc = MSI_ViewFetch(view,&row);
-        if (rc != ERROR_SUCCESS)
-        {
-            rc = ERROR_SUCCESS;
-            break;
-        }
-
-        sz=0x100;
-        MSI_RecordGetStringW(row,2,buffer,&sz);
-
-        index = get_loaded_component(package,buffer);
+        index = package->extensions[i].ComponentIndex;
+        f_index = package->extensions[i].FeatureIndex;
 
         if (index < 0)
-        {
-            msiobj_release(&row->hdr);
             continue;
-        }
 
-        if ((!ACTION_VerifyComponentForAction(package, index,
+        /* 
+         * yes. MSDN says that these are based on _Feature_ not on
+         * Component.  So verify the feature is to be installed
+         */
+        if ((!ACTION_VerifyFeatureForAction(package, f_index,
                                 INSTALLSTATE_LOCAL)) &&
-            (!ACTION_VerifyComponentForAction(package, index,
+            (!ACTION_VerifyFeatureForAction(package, f_index,
                                 INSTALLSTATE_ADVERTISED)))
         {
-            TRACE("Skipping extension reg due to disabled component\n");
-            msiobj_release(&row->hdr);
-
-            package->components[index].Action =
-                package->components[index].Installed;
+            TRACE("Skipping extension  %s reg due to disabled feature %s\n",
+                            debugstr_w(package->extensions[i].Extension),
+                            debugstr_w(package->features[f_index].Feature));
 
             continue;
         }
 
-        package->components[index].Action = INSTALLSTATE_LOCAL;
+        TRACE("Registering extension %s index %i\n",
+                        debugstr_w(package->extensions[i].Extension), i);
+
+        package->extensions[i].Installed = TRUE;
+
+        if (package->extensions[i].ProgIDIndex >= 0)
+           mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
+
+        if (package->extensions[i].MIMEIndex >= 0)
+           mark_mime_for_install(package, package->extensions[i].MIMEIndex);
 
-        exten = load_dynamic_stringW(row,1);
         extension[0] = '.';
         extension[1] = 0;
-        strcatW(extension,exten);
-        HeapFree(GetProcessHeap(),0,exten);
+        strcatW(extension,package->extensions[i].Extension);
 
         RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
 
-        if (!MSI_RecordIsNull(row,4))
+        if (package->extensions[i].MIMEIndex >= 0)
         {
-            LPWSTR mime = load_dynamic_stringW(row,4);
-            RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime,
-                           (strlenW(mime)+1)*sizeof(WCHAR));
-            HeapFree(GetProcessHeap(),0,mime);
+            RegSetValueExW(hkey,szContentType,0,REG_SZ,
+                            (LPVOID)package->mimes[package->extensions[i].
+                                MIMEIndex].ContentType,
+                           (strlenW(package->mimes[package->extensions[i].
+                                    MIMEIndex].ContentType)+1)*sizeof(WCHAR));
         }
 
-        if (!MSI_RecordIsNull(row,3))
+        if (package->extensions[i].ProgIDIndex >= 0 || 
+            package->extensions[i].ProgIDText)
         {
             static const WCHAR szSN[] = 
                 {'\\','S','h','e','l','l','N','e','w',0};
             HKEY hkey2;
             LPWSTR newkey;
-            LPWSTR progid= load_dynamic_stringW(row,3);
+            LPCWSTR progid;
+            INT v;
+            INT Sequence = MSI_NULL_INTEGER;
+            
+            if (package->extensions[i].ProgIDIndex >= 0)
+                progid = package->progids[package->extensions[i].
+                    ProgIDIndex].ProgID;
+            else
+                progid = package->extensions[i].ProgIDText;
 
             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
                            (strlenW(progid)+1)*sizeof(WCHAR));
@@ -6107,77 +6969,73 @@
             RegCreateKeyW(hkey,newkey,&hkey2);
             RegCloseKey(hkey2);
 
-            HeapFree(GetProcessHeap(),0,progid);
             HeapFree(GetProcessHeap(),0,newkey);
-        }
-
 
+            /* do all the verbs */
+            for (v = 0; v < package->extensions[i].VerbCount; v++)
+                register_verb(package, progid, 
+                              &package->components[index],
+                              &package->extensions[i],
+                              &package->verbs[package->extensions[i].Verbs[v]], 
+                              &Sequence);
+        }
+        
         RegCloseKey(hkey);
 
-        ui_actiondata(package,szRegisterExtensionInfo,row);
-
-        msiobj_release(&row->hdr);
+        uirow = MSI_CreateRecord(1);
+        MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
+        ui_actiondata(package,szRegisterExtensionInfo,uirow);
+        msiobj_release(&uirow->hdr);
     }
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
 
-end:
-    return rc;
+    return ERROR_SUCCESS;
 }
 
 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
 {
-    UINT rc;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    static const WCHAR ExecSeqQuery[] =
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','M','I','M','E','`',0};
     static const WCHAR szExten[] = 
         {'E','x','t','e','n','s','i','o','n',0 };
     HKEY hkey;
+    INT i;
+    MSIRECORD *uirow;
 
     if (!package)
         return ERROR_INVALID_HANDLE;
 
-    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
-    if (rc != ERROR_SUCCESS)
-    {
-        rc = ERROR_SUCCESS;
-        goto end;
-    }
-
-    rc = MSI_ViewExecute(view, 0);
-    if (rc != ERROR_SUCCESS)
-    {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        goto end;
-    }
+    load_classes_and_such(package);
 
-    while (1)
+    for (i = 0; i < package->loaded_mimes; i++)
     {
         WCHAR extension[257];
-        LPWSTR exten;
-        LPWSTR mime;
+        LPCWSTR exten;
+        LPCWSTR mime;
         static const WCHAR fmt[] = 
             {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
              'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
         LPWSTR key;
-     
-        rc = MSI_ViewFetch(view,&row);
-        if (rc != ERROR_SUCCESS)
+
+        /* 
+         * check if the MIME is to be installed. Either as requesed by an
+         * extension or Class
+         */
+        package->mimes[i].InstallMe =  ((package->mimes[i].InstallMe) ||
+              (package->mimes[i].ClassIndex >= 0 &&
+              package->classes[package->mimes[i].ClassIndex].Installed) ||
+              (package->mimes[i].ExtensionIndex >=0 &&
+              package->extensions[package->mimes[i].ExtensionIndex].Installed));
+
+        if (!package->mimes[i].InstallMe)
         {
-            rc = ERROR_SUCCESS;
-            break;
+            TRACE("MIME %s not scheduled to be installed\n",
+                             debugstr_w(package->mimes[i].ContentType));
+            continue;
         }
-
-        mime = load_dynamic_stringW(row,1);
-        exten = load_dynamic_stringW(row,2);
+        
+        mime = package->mimes[i].ContentType;
+        exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
         extension[0] = '.';
         extension[1] = 0;
         strcatW(extension,exten);
-        HeapFree(GetProcessHeap(),0,exten);
 
         key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
                                             sizeof(WCHAR));
@@ -6186,25 +7044,23 @@
         RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
                            (strlenW(extension)+1)*sizeof(WCHAR));
 
-        HeapFree(GetProcessHeap(),0,mime);
         HeapFree(GetProcessHeap(),0,key);
 
-        if (!MSI_RecordIsNull(row,3))
+        if (package->mimes[i].CLSID[0])
         {
             FIXME("Handle non null for field 3\n");
         }
 
         RegCloseKey(hkey);
 
-        ui_actiondata(package,szRegisterMIMEInfo,row);
-
-        msiobj_release(&row->hdr);
+        uirow = MSI_CreateRecord(2);
+        MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
+        MSI_RecordSetStringW(uirow,2,exten);
+        ui_actiondata(package,szRegisterMIMEInfo,uirow);
+        msiobj_release(&uirow->hdr);
     }
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
 
-end:
-    return rc;
+    return ERROR_SUCCESS;
 }
 
 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
@@ -6522,101 +7378,71 @@
 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
 {
     MSIPACKAGE *package = (MSIPACKAGE*)param;
-    LPWSTR productid=NULL, compgroupid=NULL;
+    LPWSTR compgroupid=NULL;
     LPWSTR feature=NULL;
     LPWSTR text = NULL;
     LPWSTR qualifier = NULL;
     LPWSTR component = NULL;
-    GUID clsid;
-    WCHAR productid_85[21];
-    WCHAR component_85[21];
+    LPWSTR advertise = NULL;
+    LPWSTR output = NULL;
     HKEY hkey;
     UINT rc = ERROR_SUCCESS;
     UINT index;
-    /*
-     * I have a fair bit of confusion as to when a < is used and when a > is
-     * used. I do not think i have it right...
-     *
-     * Ok it appears that the > is used if there is a guid for the compoenent
-     * and the < is used if not.
-     */
-    static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
-    static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
-    LPWSTR output = NULL;
     DWORD sz = 0;
-    INT component_index;
 
     component = load_dynamic_stringW(rec,3);
-    component_index = get_loaded_component(package,component);
+    index = get_loaded_component(package,component);
 
-    if (!ACTION_VerifyComponentForAction(package, component_index,
+    if (!ACTION_VerifyComponentForAction(package, index,
                             INSTALLSTATE_LOCAL) && 
-       !ACTION_VerifyComponentForAction(package, component_index,
+       !ACTION_VerifyComponentForAction(package, index,
                             INSTALLSTATE_SOURCE) &&
-       !ACTION_VerifyComponentForAction(package, component_index,
+       !ACTION_VerifyComponentForAction(package, index,
                             INSTALLSTATE_ADVERTISED))
     {
         TRACE("Skipping: Component %s not scheduled for install\n",
                         debugstr_w(component));
+
         HeapFree(GetProcessHeap(),0,component);
         return ERROR_SUCCESS;
     }
 
-    memset(productid_85,0,sizeof(productid_85));
-    memset(component_85,0,sizeof(component_85));
     compgroupid = load_dynamic_stringW(rec,1);
 
     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
     
-    productid = load_dynamic_property(package,szProductCode,NULL);
-    CLSIDFromString(productid, &clsid);
-    
-    encode_base85_guid(&clsid,productid_85);
-
     text = load_dynamic_stringW(rec,4);
     qualifier = load_dynamic_stringW(rec,2);
-
     feature = load_dynamic_stringW(rec,5);
   
-    index = get_loaded_component(package, component);
-    CLSIDFromString(package->components[index].ComponentId, &clsid);
-    encode_base85_guid(&clsid,component_85);
+    advertise = create_component_advertise_string(package, 
+                    &package->components[index], feature);
+
+    sz = strlenW(advertise);
 
-    TRACE("Doing something with this... %s = %s %s %s %s\n", 
-            debugstr_w(qualifier), debugstr_w(productid_85),
-            debugstr_w(feature), debugstr_w(text), debugstr_w(component_85));
- 
-    sz = lstrlenW(productid_85) + lstrlenW(feature);
     if (text)
         sz += lstrlenW(text);
-    if (component && index >= 0)
-        sz += lstrlenW(component_85);
 
     sz+=3;
     sz *= sizeof(WCHAR);
            
     output = HeapAlloc(GetProcessHeap(),0,sz);
     memset(output,0,sz);
-
-    if (component && index >= 0)
-        sprintfW(output,fmt2,productid_85,feature,component_85);
-    else
-        sprintfW(output,fmt1,productid_85,feature);
+    strcpyW(output,advertise);
 
     if (text)
         strcatW(output,text);
 
     sz = (lstrlenW(output)+2) * sizeof(WCHAR);
-   RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
+    RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
     
 end:
     RegCloseKey(hkey);
     HeapFree(GetProcessHeap(),0,output);
     HeapFree(GetProcessHeap(),0,compgroupid);
     HeapFree(GetProcessHeap(),0,component);
-    HeapFree(GetProcessHeap(),0,productid);
     HeapFree(GetProcessHeap(),0,feature);
     HeapFree(GetProcessHeap(),0,text);
     HeapFree(GetProcessHeap(),0,qualifier);
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.7
diff -u -r1.7 action.h
--- dlls/msi/action.h	18 May 2005 13:23:52 -0000	1.7
+++ dlls/msi/action.h	25 May 2005 18:15:29 -0000
@@ -18,15 +18,17 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define IDENTIFIER_SIZE 96
+
 typedef struct tagMSIFEATURE
 {
-    WCHAR Feature[96];
-    WCHAR Feature_Parent[96];
+    WCHAR Feature[IDENTIFIER_SIZE];
+    WCHAR Feature_Parent[IDENTIFIER_SIZE];
     WCHAR Title[0x100];
     WCHAR Description[0x100];
     INT Display;
     INT Level;
-    WCHAR Directory[96];
+    WCHAR Directory[IDENTIFIER_SIZE];
     INT Attributes;
     
     INSTALLSTATE Installed;
@@ -40,12 +42,12 @@
 
 typedef struct tagMSICOMPONENT
 {
-    WCHAR Component[96];
-    WCHAR ComponentId[96];
-    WCHAR Directory[96];
+    WCHAR Component[IDENTIFIER_SIZE];
+    WCHAR ComponentId[IDENTIFIER_SIZE];
+    WCHAR Directory[IDENTIFIER_SIZE];
     INT Attributes;
     WCHAR Condition[0x100];
-    WCHAR KeyPath[96];
+    WCHAR KeyPath[IDENTIFIER_SIZE];
 
     INSTALLSTATE Installed;
     INSTALLSTATE ActionRequest;
@@ -56,6 +58,7 @@
     INT  RefCount;
 
     LPWSTR FullKeypath;
+    LPWSTR AdvertiseString;
 } MSICOMPONENT;
 
 typedef struct tagMSIFOLDER
@@ -99,6 +102,81 @@
     LPWSTR  TargetPath;
     BOOL    Temporary; 
 }MSIFILE;
+
+typedef struct tagMSICLASS
+{
+    WCHAR CLSID[IDENTIFIER_SIZE];     /* Primary Key */
+    WCHAR Context[IDENTIFIER_SIZE];   /* Primary Key */
+    INT ComponentIndex;               /* Primary Key */
+    INT ProgIDIndex;
+    LPWSTR ProgIDText;
+    LPWSTR Description;
+    INT AppIDIndex;
+    LPWSTR FileTypeMask;
+    LPWSTR IconPath;
+    LPWSTR DefInprocHandler;
+    LPWSTR DefInprocHandler32;
+    LPWSTR Argument;
+    INT FeatureIndex;
+    INT Attributes;
+    /* not in the table, set during instalation */
+    BOOL Installed;
+} MSICLASS;
+
+typedef struct tagMSIEXTENSION
+{
+    WCHAR Extension[256];  /* Primary Key */
+    INT ComponentIndex;    /* Primary Key */
+    INT ProgIDIndex;
+    LPWSTR ProgIDText;
+    INT MIMEIndex;
+    INT FeatureIndex;
+    /* not in the table, set during instalation */
+    BOOL Installed;
+    INT VerbCount;
+    INT Verbs[100]; /* yes hard coded limit, but relisticly 100 verbs??? */
+} MSIEXTENSION;
+
+typedef struct tagMSIPROGID
+{
+    LPWSTR ProgID;  /* Primary Key */
+    INT ParentIndex;
+    INT ClassIndex;
+    LPWSTR Description;
+    LPWSTR IconPath;
+    /* not in the table, set during instalation */
+    BOOL InstallMe;
+} MSIPROGID;
+
+typedef struct tagMSIVERB
+{
+    INT ExtensionIndex;
+    LPWSTR Verb;
+    INT Sequence;
+    LPWSTR Command;
+    LPWSTR Argument;
+} MSIVERB;
+
+typedef struct tagMSIMIME
+{
+    LPWSTR ContentType;  /* Primary Key */
+    INT ExtensionIndex;
+    WCHAR CLSID[IDENTIFIER_SIZE];
+    INT ClassIndex;
+    /* not in the table, set during instalation */
+    BOOL InstallMe;
+} MSIMIME;
+
+typedef struct tagMSIAPPID
+{
+    WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */
+    LPWSTR RemoteServerName;
+    LPWSTR LocalServer;
+    LPWSTR ServiceParameters;
+    LPWSTR DllSurrogate;
+    BOOL ActivateAtStorage;
+    BOOL RunAsInteractiveUser;
+} MSIAPPID;
 
 
 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.57
diff -u -r1.57 msipriv.h
--- dlls/msi/msipriv.h	23 May 2005 12:08:17 -0000	1.57
+++ dlls/msi/msipriv.h	25 May 2005 18:15:29 -0000
@@ -197,6 +197,19 @@
     LPWSTR ActionFormat;
     LPWSTR LastAction;
 
+    struct tagMSICLASS *classes;
+    UINT loaded_classes;
+    struct tagMSIEXTENSION *extensions;
+    UINT loaded_extensions;
+    struct tagMSIPROGID *progids;
+    UINT loaded_progids;
+    struct tagMSIVERB *verbs;
+    UINT loaded_verbs;
+    struct tagMSIMIME *mimes;
+    UINT loaded_mimes;
+    struct tagMSIAPPID *appids;
+    UINT loaded_appids;
+    
     LPWSTR *DeferredAction;
     UINT DeferredActionCount;
 


More information about the wine-patches mailing list