MSI: rework how we handle Feature and Component States

Mike McCormack mike at codeweavers.com
Fri Dec 24 01:37:11 CST 2004


ChangeLog:
<aric at codeweavers.com>
* rework how we handle Feature and Component States. I have confirmed 
from testing that, although documented nowhere, having ADDLOCAL on the 
install line overrides INSTALLLEVEL.
* track all files extracted from cabinents as tempfiles so they can be 
removed at the end of the install to not leave uninstalled but uncabbed 
files laying around. The best thing would be to only uncab a file if it 
is needed but i need to understand the FDI functions better to do that
-------------- next part --------------
--- dlls/msi/action.c.old	2004-12-24 16:30:02.000000000 +0900
+++ dlls/msi/action.c	2004-12-24 16:34:23.000000000 +0900
@@ -64,8 +64,10 @@
     WCHAR Directory[96];
     INT Attributes;
     
-    INSTALLSTATE State;
-    BOOL Enabled;
+    INSTALLSTATE Installed;
+    INSTALLSTATE ActionRequest;
+    INSTALLSTATE Action;
+
     INT ComponentCount;
     INT Components[1024]; /* yes hardcoded limit.... I am bad */
     INT Cost;
@@ -80,8 +82,10 @@
     WCHAR Condition[0x100];
     WCHAR KeyPath[96];
 
-    INSTALLSTATE State;
-    BOOL FeatureState;
+    INSTALLSTATE Installed;
+    INSTALLSTATE ActionRequest;
+    INSTALLSTATE Action;
+
     BOOL Enabled;
     INT  Cost;
 } MSICOMPONENT;
@@ -411,7 +415,10 @@
     for (i = 0; i < package->loaded_files; i++)
     {
         if (package->files[i].Temporary)
+        {
+            TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
             DeleteFileW(package->files[i].TargetPath);
+        }
 
     }
 }
@@ -1832,9 +1839,11 @@
     sz = 96;       
     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
 
-    package->components[index].State = INSTALLSTATE_ABSENT;
+    package->components[index].Installed = INSTALLSTATE_ABSENT;
+    package->components[index].Action = INSTALLSTATE_UNKNOWN;
+    package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
+
     package->components[index].Enabled = TRUE;
-    package->components[index].FeatureState= FALSE;
 
     return index;
 }
@@ -1894,7 +1903,10 @@
         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
 
     package->features[index].Attributes= MSI_RecordGetInteger(row,8);
-    package->features[index].State = INSTALLSTATE_ABSENT;
+
+    package->features[index].Installed = INSTALLSTATE_ABSENT;
+    package->features[index].Action = INSTALLSTATE_UNKNOWN;
+    package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
 
     /* load feature components */
 
@@ -2372,39 +2384,84 @@
     else
         install_level = 1;
 
-    override = load_dynamic_property(package,szAddLocal,NULL);
-   
-    /*
-     * Components FeatureState defaults to FALSE. The idea is we want to 
-     * enable the component is ANY feature that uses it is enabled to install
+    /* ok hereis the rub
+     * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
+     * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
+     * itnored for all the features. seems strange, epsecially since it is not
+     * documented anywhere, but it is how it works. 
      */
-    for(i = 0; i < package->loaded_features; i++)
+    
+    override = load_dynamic_property(package,szAddLocal,NULL);
+  
+    if (override)
     {
-        BOOL feature_state= ((package->features[i].Level > 0) &&
+        for(i = 0; i < package->loaded_features; i++)
+        {
+            if (strcmpiW(override,all)==0 || 
+                strstrW(override,package->features[i].Feature))
+            {
+                package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
+                package->features[i].Action = INSTALLSTATE_LOCAL;
+            }
+        }
+        HeapFree(GetProcessHeap(),0,override);
+    } 
+    else
+    {
+        for(i = 0; i < package->loaded_features; i++)
+        {
+            BOOL feature_state= ((package->features[i].Level > 0) &&
                              (package->features[i].Level <= install_level));
 
-        if (override && (strcmpiW(override,all)==0 || 
-                         strstrW(override,package->features[i].Feature)))
-        {
-            TRACE("Override of install level found\n");
-            feature_state = TRUE;
+            if (feature_state)
+            {
+                package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
+                package->features[i].Action = INSTALLSTATE_LOCAL;
+            }
         }
-        package->features[i].Enabled = feature_state;
+    }
+
+    /*
+     * now we want to enable or disable components base on feature 
+    */
+
+    for(i = 0; i < package->loaded_features; i++)
+    {
+        MSIFEATURE* feature = &package->features[i];
+        TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
+            debugstr_w(feature->Feature), feature->Installed, feature->Action,
+            feature->ActionRequest);
 
-        TRACE("Feature %s has a state of %i\n",
-               debugstr_w(package->features[i].Feature), feature_state);
-        for( j = 0; j < package->features[i].ComponentCount; j++)
+        for( j = 0; j < feature->ComponentCount; j++)
         {
-            package->components[package->features[i].Components[j]].FeatureState
-            |= feature_state;
+            MSICOMPONENT* component = &package->components[
+                                                    feature->Components[j]];
+
+            if (!component->Enabled)
+            {
+                component->Action = INSTALLSTATE_ABSENT;
+                component->ActionRequest = INSTALLSTATE_ABSENT;
+            }
+            else
+            {
+                if (feature->Action == INSTALLSTATE_LOCAL)
+                    component->Action = INSTALLSTATE_LOCAL;
+                if (feature->ActionRequest == INSTALLSTATE_LOCAL)
+                    component->ActionRequest = INSTALLSTATE_LOCAL;
+            }
         }
     } 
-    if (override)
-        HeapFree(GetProcessHeap(),0,override);
-    /* 
-     * So basically we ONLY want to install a component if its Enabled AND
-     * FeatureState are both TRUE 
-     */
+
+    for(i = 0; i < package->loaded_components; i++)
+    {
+        MSICOMPONENT* component= &package->components[i];
+
+        TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
+            debugstr_w(component->Component), component->Installed, 
+            component->Action, component->ActionRequest);
+    }
+
+
     return ERROR_SUCCESS;
 }
 
@@ -2686,6 +2743,11 @@
 
 
 /* Support functions for FDI functions */
+typedef struct
+{
+    MSIPACKAGE* package;
+    LPCSTR cab_path;
+} CabData;
 
 static void * cabinet_alloc(ULONG cb)
 {
@@ -2758,14 +2820,35 @@
     {
     case fdintCOPY_FILE:
     {
-        ULONG len = strlen((char*)pfdin->pv) + strlen(pfdin->psz1);
+        CabData *data = (CabData*) pfdin->pv;
+        ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
         char *file = cabinet_alloc((len+1)*sizeof(char));
 
-        strcpy(file, (char*)pfdin->pv);
+        LPWSTR trackname;
+        LPWSTR trackpath;
+        LPWSTR tracknametmp;
+        static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
+        
+        strcpy(file, data->cab_path);
         strcat(file, pfdin->psz1);
 
         TRACE("file: %s\n", debugstr_a(file));
 
+        /* track this file so it can be deleted if not installed */
+        trackpath=strdupAtoW(file);
+        tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
+        trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + 
+                                  strlenW(tmpprefix)+1) * sizeof(WCHAR));
+
+        strcpyW(trackname,tmpprefix);
+        strcatW(trackname,tracknametmp);
+
+        track_tempfile(data->package, trackname, trackpath);
+
+        HeapFree(GetProcessHeap(),0,trackpath);
+        HeapFree(GetProcessHeap(),0,trackname);
+        HeapFree(GetProcessHeap(),0,tracknametmp);
+
         return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
     }
     case fdintCLOSE_FILE_INFO:
@@ -2792,13 +2875,15 @@
  *
  * Extract files from a cab file.
  */
-static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
+static BOOL extract_cabinet_file(MSIPACKAGE* package, const WCHAR* source, 
+                                 const WCHAR* path)
 {
     HFDI hfdi;
     ERF erf;
     BOOL ret;
     char *cabinet;
     char *cab_path;
+    CabData data;
 
     TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
 
@@ -2829,7 +2914,10 @@
         return FALSE;
     }
 
-    ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, cab_path);
+    data.package = package;
+    data.cab_path = cab_path;
+
+    ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
 
     if (!ret)
         ERR("FDICopy failed\n");
@@ -2921,7 +3009,7 @@
                     GetTempPathW(MAX_PATH,path);
             }
         }
-        rc = !extract_cabinet_file(source,path);
+        rc = !extract_cabinet_file(package, source,path);
     }
     msiobj_release(&row->hdr);
     MSI_ViewClose(view);
@@ -2974,11 +3062,12 @@
         if (file->Temporary)
             continue;
 
-        if (!package->components[file->ComponentIndex].Enabled ||
-            !package->components[file->ComponentIndex].FeatureState)
+        if (package->components[file->ComponentIndex].ActionRequest != 
+             INSTALLSTATE_LOCAL)
         {
             TRACE("File %s is not scheduled for install\n",
                    debugstr_w(file->File));
+
             continue;
         }
 
@@ -3127,8 +3216,8 @@
         }
 
         component_index = get_loaded_component(package,component);
-        if (!package->components[component_index].Enabled ||
-            !package->components[component_index].FeatureState)
+        if (package->components[component_index].ActionRequest != 
+             INSTALLSTATE_LOCAL)
         {
             TRACE("Skipping copy due to disabled component\n");
             msiobj_release(&row->hdr);
@@ -3358,8 +3447,8 @@
         component = load_dynamic_stringW(row, 6);
         component_index = get_loaded_component(package,component);
 
-        if (!package->components[component_index].Enabled ||
-            !package->components[component_index].FeatureState)
+        if (package->components[component_index].ActionRequest != 
+             INSTALLSTATE_LOCAL)
         {
             TRACE("Skipping write due to disabled component\n");
             msiobj_release(&row->hdr);
@@ -3865,8 +3954,7 @@
             continue;
         }
 
-        if (!package->components[index].Enabled ||
-            !package->components[index].FeatureState)
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
         {
             TRACE("Skipping typelib reg due to disabled component\n");
             msiobj_release(&row->hdr);
@@ -4110,8 +4198,7 @@
             continue;
         }
 
-        if (!package->components[index].Enabled ||
-            !package->components[index].FeatureState)
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
         {
             TRACE("Skipping class reg due to disabled component\n");
             msiobj_release(&row->hdr);
@@ -4471,8 +4558,7 @@
             continue;
         }
 
-        if (!package->components[index].Enabled ||
-            !package->components[index].FeatureState)
+        if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
         {
             TRACE("Skipping shortcut creation due to disabled component\n");
             msiobj_release(&row->hdr);
@@ -5027,7 +5113,7 @@
     if (index < 0)
         return ERROR_UNKNOWN_FEATURE;
 
-    package->features[index].State = iState;
+    package->features[index].ActionRequest= iState;
 
     return ERROR_SUCCESS;
 }
@@ -5057,15 +5143,11 @@
         return ERROR_UNKNOWN_FEATURE;
 
     if (piInstalled)
-        *piInstalled = package->features[index].State;
+        *piInstalled = package->features[index].Installed;
 
     if (piAction)
-    {
-        if (package->features[index].Enabled)
-            *piAction = INSTALLSTATE_LOCAL;
-        else
-            *piAction = package->features[index].State;
-    }
+        *piAction = package->features[index].Action;
+
     TRACE("returning %i %i\n",*piInstalled,*piAction);
 
     return ERROR_SUCCESS;
@@ -5116,16 +5198,10 @@
         return ERROR_UNKNOWN_COMPONENT;
 
     if (piInstalled)
-        *piInstalled = package->components[index].State;
+        *piInstalled = package->components[index].Installed;
 
     if (piAction)
-    {
-        if (package->components[index].Enabled &&
-            package->components[index].FeatureState)
-            *piAction = INSTALLSTATE_LOCAL;
-        else
-            *piAction = INSTALLSTATE_UNKNOWN;
-    }
+        *piInstalled = package->components[index].Action;
 
     return ERROR_SUCCESS;
 }


More information about the wine-patches mailing list