msi: keypath, registry and action work

Aric Stewart aric at codeweavers.com
Thu Feb 24 03:42:11 CST 2005


Add the ExecuteAction handler
Store the keypath, and do refcounting and registration of SharedDLLs
Fix a bug with handing dword values in the registry
Fix bugs with writing registry keys where value == NULL
make use of msidefs.h
lay some groundwork for uninstalls.
-------------- next part --------------
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.91
diff -u -u -r1.91 action.c
--- dlls/msi/action.c	22 Feb 2005 19:31:45 -0000	1.91
+++ dlls/msi/action.c	24 Feb 2005 09:39:31 -0000
@@ -39,6 +39,7 @@
 #include "fdi.h"
 #include "msi.h"
 #include "msiquery.h"
+#include "msidefs.h"
 #include "msvcrt/fcntl.h"
 #include "objbase.h"
 #include "objidl.h"
@@ -96,6 +97,7 @@
 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
 static UINT ACTION_ResolveSource(MSIPACKAGE *package);
+static UINT ACTION_ExecuteAction(MSIPACKAGE *package);
 
  
 /*
@@ -280,8 +282,8 @@
     { szCreateShortcuts, ACTION_CreateShortcuts },
     { szDeleteServices, NULL},
     { szDisableRollback, NULL},
-    { szDuplicateFiles, ACTION_DuplicateFiles},
-    { szExecuteAction, NULL},
+    { szDuplicateFiles, ACTION_DuplicateFiles },
+    { szExecuteAction, ACTION_ExecuteAction },
     { szFileCost, ACTION_FileCost },
     { szFindRelatedProducts, NULL},
     { szForceReboot, ACTION_ForceReboot },
@@ -567,7 +569,9 @@
     if (package->folders && package->loaded_folders > 0)
         HeapFree(GetProcessHeap(),0,package->folders);
 
-    /* no dynamic buffers in components */ 
+    for (i = 0; i < package->loaded_components; i++)
+        HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
+
     if (package->components && package->loaded_components > 0)
         HeapFree(GetProcessHeap(),0,package->components);
 
@@ -816,6 +820,18 @@
         return FALSE;
 }
 
+static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, 
+                                            INSTALLSTATE check )
+{
+    if (package->features[index].Installed == check)
+        return FALSE;
+
+    if (package->features[index].ActionRequest == check)
+        return TRUE;
+    else
+        return FALSE;
+}
+
 
 /****************************************************
  * TOP level entry points 
@@ -832,6 +848,7 @@
     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
 
     MSI_SetPropertyW(package, szAction, szInstall);
+    package->ExecuteSequenceRun = FALSE;
 
     if (szPackagePath)   
     {
@@ -1056,6 +1073,15 @@
        0};
     INT seq = 0;
 
+
+    if (package->ExecuteSequenceRun)
+    {
+        TRACE("Execute Sequence already Run\n");
+        return ERROR_SUCCESS;
+    }
+
+    package->ExecuteSequenceRun = TRUE;
+    
     /* get the sequence number */
     if (UIran)
     {
@@ -3149,7 +3175,6 @@
         }
 
         package->components[component_index].Action = INSTALLSTATE_LOCAL;
-        package->components[component_index].Installed = INSTALLSTATE_LOCAL;
 
         sz=0x100;
         rc = MSI_RecordGetStringW(row,3,file_key,&sz);
@@ -3274,13 +3299,28 @@
         else
         {
             LPWSTR deformated;
+            LPWSTR p;
+            DWORD d = 0;
             deformat_string(package, &value[1], &deformated);
 
             *type=REG_DWORD; 
             *size = sizeof(DWORD);
             data = HeapAlloc(GetProcessHeap(),0,*size);
-            *(LPDWORD)data = atoiW(deformated); 
-            TRACE("DWORD %i\n",*data);
+            p = deformated;
+            if (*p == '-')
+                p++;
+            while (*p)
+            {
+                if ( (*p < '0') || (*p > '9') )
+                    break;
+                d *= 10;
+                d += (*p - '0');
+                p++;
+            }
+            if (deformated[0] == '-')
+                d = -d;
+            *(LPDWORD)data = d;
+            TRACE("DWORD %li\n",*(LPDWORD)data);
 
             HeapFree(GetProcessHeap(),0,deformated);
         }
@@ -3390,20 +3430,27 @@
         }
 
         package->components[component_index].Action = INSTALLSTATE_LOCAL;
-        package->components[component_index].Installed = INSTALLSTATE_LOCAL;
 
-        /* null values have special meanings during uninstalls and such */
-        
-        if(MSI_RecordIsNull(row,5))
+        name = load_dynamic_stringW(row, 4);
+        if( MSI_RecordIsNull(row,5) && name )
         {
-            msiobj_release(&row->hdr);
-            goto next;
+            /* null values can have special meanings */
+            if (name[0]=='-' && name[1] == 0)
+            {
+                msiobj_release(&row->hdr);
+                goto next;
+            }
+            else if ((name[0]=='+' && name[1] == 0) || 
+                     (name[0] == '*' && name[1] == 0))
+            {
+                HeapFree(GetProcessHeap(),0,name);
+                name = NULL;
+            }
         }
 
         root = MSI_RecordGetInteger(row,2);
         key = load_dynamic_stringW(row, 3);
       
-        name = load_dynamic_stringW(row, 4);
    
         /* get the root key */
         switch (root)
@@ -3448,29 +3495,33 @@
         HeapFree(GetProcessHeap(),0,deformated);
 
         value = load_dynamic_stringW(row,5);
-        value_data = parse_value(package, value, &type, &size); 
+        if (value)
+            value_data = parse_value(package, value, &type, &size); 
+        else
+        {
+            value_data = NULL;
+            size = 0;
+            type = REG_SZ;
+        }
 
         deformat_string(package, name, &deformated);
 
-        if (value_data)
-        {
-            TRACE("Setting value %s\n",debugstr_w(deformated));
-            RegSetValueExW(hkey, deformated, 0, type, value_data, size);
+        TRACE("Setting value %s\n",debugstr_w(deformated));
+        RegSetValueExW(hkey, deformated, 0, type, value_data, size);
 
-            uirow = MSI_CreateRecord(3);
-            MSI_RecordSetStringW(uirow,2,deformated);
-            MSI_RecordSetStringW(uirow,1,uikey);
+        uirow = MSI_CreateRecord(3);
+        MSI_RecordSetStringW(uirow,2,deformated);
+        MSI_RecordSetStringW(uirow,1,uikey);
 
-            if (type == REG_SZ)
-                MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
-            else
-                MSI_RecordSetStringW(uirow,3,value);
+        if (type == REG_SZ)
+            MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
+        else
+            MSI_RecordSetStringW(uirow,3,value);
 
-            ui_actiondata(package,szWriteRegistryValues,uirow);
-            msiobj_release( &uirow->hdr );
+        ui_actiondata(package,szWriteRegistryValues,uirow);
+        msiobj_release( &uirow->hdr );
 
-            HeapFree(GetProcessHeap(),0,value_data);
-        }
+        HeapFree(GetProcessHeap(),0,value_data);
         HeapFree(GetProcessHeap(),0,value);
         HeapFree(GetProcessHeap(),0,deformated);
 
@@ -3610,7 +3661,7 @@
         LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
         return p;
     }
-    if (cmp->Attributes & 0x4)
+    if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
     {
         MSIQUERY * view;
         MSIRECORD * row = 0;
@@ -3621,8 +3672,8 @@
         'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',
 'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '
 ,'`','%','s','`',0 };
-        static const WCHAR fmt[]={'%','0','2','i',':','%','s',0};
-        static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0};
+        static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
+        static const WCHAR fmt2[]={'%','0','2','i',':','\\','%','s','\\','%','s',0};
 
         rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
 
@@ -3672,7 +3723,7 @@
 
         return buffer;
     }
-    else if (cmp->Attributes & 0x20)
+    else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
     {
         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
         return NULL;
@@ -3691,6 +3742,127 @@
     return NULL;
 }
 
+static HKEY openSharedDLLsKey()
+{
+    HKEY hkey=0;
+    static const WCHAR path[] = {
+'S','o','f','t','w','a','r','e','\\',
+'M','i','c','r','o','s','o','f','t','\\',
+'W','i','n','d','o','w','s','\\',
+'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+'S','h','a','r','e','d','D','L','L','s',0};
+
+    RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
+    return hkey;
+}
+
+static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
+{
+    HKEY hkey;
+    DWORD count=0;
+    DWORD type;
+    DWORD sz = sizeof(count);
+    DWORD rc;
+    
+    hkey = openSharedDLLsKey();
+    rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
+    if (rc != ERROR_SUCCESS)
+        count = 0;
+    RegCloseKey(hkey);
+    return count;
+}
+
+static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
+{
+    HKEY hkey;
+
+    hkey = openSharedDLLsKey();
+    if (count > 0)
+        RegSetValueExW(hkey,path,0,REG_DWORD,
+                    (LPBYTE)&count,sizeof(count));
+    else
+        RegDeleteValueW(hkey,path);
+    RegCloseKey(hkey);
+    return count;
+}
+
+/*
+ * Return TRUE if the count should be written out and FALSE if not
+ */
+static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
+{
+    INT count = 0;
+    BOOL write = FALSE;
+    INT j;
+
+    /* only refcount DLLs */
+    if (package->components[index].KeyPath[0]==0 || 
+        package->components[index].Attributes & 
+            msidbComponentAttributesRegistryKeyPath || 
+        package->components[index].Attributes & 
+            msidbComponentAttributesODBCDataSource)
+        write = FALSE;
+    else
+    {
+        count = ACTION_GetSharedDLLsCount(package->components[index].
+                        FullKeypath);
+        write = (count > 0);
+
+        if (package->components[index].Attributes & 
+                    msidbComponentAttributesSharedDllRefCount)
+            write = TRUE;
+    }
+
+    /* increment counts */
+    for (j = 0; j < package->loaded_features; j++)
+    {
+        int i;
+
+        if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
+            continue;
+
+        for (i = 0; i < package->features[j].ComponentCount; i++)
+        {
+            if (package->features[j].Components[i] == index)
+                count++;
+        }
+    }
+    /* decrement counts */
+    for (j = 0; j < package->loaded_features; j++)
+    {
+        int i;
+        if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
+            continue;
+
+        for (i = 0; i < package->features[j].ComponentCount; i++)
+        {
+            if (package->features[j].Components[i] == index)
+                count--;
+        }
+    }
+
+    /* ref count all the files in the component */
+    if (write)
+        for (j = 0; j < package->loaded_files; j++)
+        {
+            if (package->files[j].Temporary)
+                continue;
+            if (package->files[j].ComponentIndex == index)
+                ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
+        }
+    
+    /* add a count for permenent */
+    if (package->components[index].Attributes &
+                                msidbComponentAttributesPermanent)
+        count ++;
+    
+    package->components[index].RefCount = count;
+
+    if (write)
+        ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
+            package->components[index].RefCount);
+}
+
 /*
  * Ok further analysis makes me think that this work is
  * actually done in the PublishComponents and PublishFeatures
@@ -3735,21 +3907,70 @@
                 continue;
            
             keypath = resolve_keypath(package,i);
-            if (keypath)
+            package->components[i].FullKeypath = keypath;
+
+            /* do the refcounting */
+            ACTION_RefCountComponent( package, i);
+
+            TRACE("Component %s, Keypath=%s, RefCount=%i\n", 
+                            debugstr_w(package->components[i].Component), 
+                            debugstr_w(package->components[i].FullKeypath), 
+                            package->components[i].RefCount);
+            /*
+            * Write the keypath out if the component is to be registered
+            * and delete the key if the component is to be deregistered
+            */
+            if (ACTION_VerifyComponentForAction(package, i,
+                                    INSTALLSTATE_LOCAL))
+            {
+                if (keypath)
+                {
+                    RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
+                                (strlenW(keypath)+1)*sizeof(WCHAR));
+
+                    if (package->components[i].Attributes & 
+                                msidbComponentAttributesPermanent)
+                    {
+                        static const WCHAR szPermKey[] = {
+'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0',
+'0','0','0','0','0','0','0','0','0','0','0','0','0',0};
+
+                        RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
+                                        (LPVOID)keypath,
+                                        (strlenW(keypath)+1)*sizeof(WCHAR));
+                    }
+                    
+                    RegCloseKey(hkey2);
+        
+                    /* UI stuff */
+                    uirow = MSI_CreateRecord(3);
+                    MSI_RecordSetStringW(uirow,1,productcode);
+                    MSI_RecordSetStringW(uirow,2,package->components[i].
+                                                            ComponentId);
+                    MSI_RecordSetStringW(uirow,3,keypath);
+                    ui_actiondata(package,szProcessComponents,uirow);
+                    msiobj_release( &uirow->hdr );
+               }
+            }
+            else if (ACTION_VerifyComponentForAction(package, i,
+                                    INSTALLSTATE_ABSENT))
             {
-                RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
-                            (strlenW(keypath)+1)*sizeof(WCHAR));
+                DWORD res;
+                RegDeleteValueW(hkey2,squished_pc);
+
+                /* if the key is empty delete it */
+                res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
                 RegCloseKey(hkey2);
+                if (res == ERROR_NO_MORE_ITEMS)
+                    RegDeleteKeyW(hkey,squished_cc);
         
                 /* UI stuff */
-                uirow = MSI_CreateRecord(3);
+                uirow = MSI_CreateRecord(2);
                 MSI_RecordSetStringW(uirow,1,productcode);
                 MSI_RecordSetStringW(uirow,2,package->components[i].
-                                                        ComponentId);
-                MSI_RecordSetStringW(uirow,3,keypath);
+                                ComponentId);
                 ui_actiondata(package,szProcessComponents,uirow);
                 msiobj_release( &uirow->hdr );
-                HeapFree(GetProcessHeap(),0,keypath);
             }
         }
     } 
@@ -3827,7 +4048,6 @@
         }
 
         package->components[index].Action = INSTALLSTATE_LOCAL;
-        package->components[index].Installed = INSTALLSTATE_LOCAL;
 
         index = get_loaded_file(package,package->components[index].KeyPath); 
    
@@ -4082,7 +4302,6 @@
         }
 
         package->components[index].Action = INSTALLSTATE_LOCAL;
-        package->components[index].Installed = INSTALLSTATE_LOCAL;
 
         sz=0x100;
         MSI_RecordGetStringW(row,1,clsid,&sz);
@@ -4583,7 +4802,6 @@
         }
 
         package->components[index].Action = INSTALLSTATE_LOCAL;
-        package->components[index].Installed = INSTALLSTATE_LOCAL;
 
         ui_actiondata(package,szCreateShortcuts,row);
 
@@ -4631,11 +4849,11 @@
         }
         else
         {
-            FIXME("UNHANDLED shortcut format, advertised shortcut\n");
-            IPersistFile_Release( pf );
-            IShellLinkW_Release( sl );
-            msiobj_release(&row->hdr);
-            continue;
+            LPWSTR keypath;
+            FIXME("poorly handled shortcut format, advertised shortcut\n");
+            keypath = dupstrW(package->components[index].FullKeypath);
+            IShellLinkW_SetPath(sl,keypath);
+            HeapFree(GetProcessHeap(),0,keypath);
         }
 
         if (!MSI_RecordIsNull(row,6))
@@ -4931,7 +5149,6 @@
         }
 
         package->components[component_index].Action = INSTALLSTATE_LOCAL;
-        package->components[component_index].Installed = INSTALLSTATE_LOCAL;
    
         identifier = load_dynamic_stringW(row,1); 
         filename = load_dynamic_stringW(row,2);
@@ -5126,6 +5343,9 @@
         int j;
         INT size;
 
+        if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL))
+            continue;
+
         size = package->features[i].ComponentCount*21;
         size +=1;
         if (package->features[i].Feature_Parent[0])
@@ -5402,6 +5622,8 @@
 
     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
     sprintfW(buffer,install_fmt,productcode,squished_pc);
+
+    size = strlenW(buffer)*sizeof(WCHAR);
     RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
     RegCloseKey(hkey);
 
@@ -5510,7 +5732,6 @@
         }
 
         package->components[index].Action = INSTALLSTATE_LOCAL;
-        package->components[index].Installed = INSTALLSTATE_LOCAL;
 
         exten = load_dynamic_stringW(row,1);
         extension[0] = '.';
@@ -5711,6 +5932,14 @@
     return ERROR_SUCCESS;
 }
 
+
+static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
+{
+    UINT rc;
+    rc = ACTION_ProcessExecSequence(package,TRUE);
+    return rc;
+}
+
 /* Msi functions that seem appropriate here */
 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
 {
@@ -5745,7 +5974,7 @@
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
     if( package )
     {
-        ret = ACTION_PerformAction(package,szAction);
+        ret = ACTION_PerformUIAction(package,szAction);
         msiobj_release( &package->hdr );
     }
     return ret;
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.4
diff -u -u -r1.4 action.h
--- dlls/msi/action.h	1 Feb 2005 18:46:26 -0000	1.4
+++ dlls/msi/action.h	24 Feb 2005 09:39:31 -0000
@@ -53,6 +53,9 @@
 
     BOOL Enabled;
     INT  Cost;
+    INT  RefCount;
+
+    LPWSTR FullKeypath;
 } MSICOMPONENT;
 
 typedef struct tagMSIFOLDER
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.47
diff -u -u -r1.47 msipriv.h
--- dlls/msi/msipriv.h	8 Feb 2005 13:44:25 -0000	1.47
+++ dlls/msi/msipriv.h	24 Feb 2005 09:39:31 -0000
@@ -214,6 +214,8 @@
     UINT CurrentInstallState;
     msi_dialog *dialog;
     LPWSTR next_dialog;
+
+    BOOL ExecuteSequenceRun;
 } MSIPACKAGE;
 
 typedef struct tagMSIPREVIEW


More information about the wine-patches mailing list