Piotr Caban : msi: Install feature when new component is added.

Alexandre Julliard julliard at winehq.org
Thu Jul 2 15:04:32 CDT 2020


Module: wine
Branch: master
Commit: 877540b522c46134aa1b843519fa5694adb187ce
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=877540b522c46134aa1b843519fa5694adb187ce

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Wed Jul  1 10:44:00 2020 +0200

msi: Install feature when new component is added.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49350
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msi/action.c      | 112 ++++++++++++++++++++++++++++++++++++++++++++-----
 dlls/msi/msipriv.h     |   2 +
 dlls/msi/patch.c       |   5 +++
 dlls/msi/tests/patch.c |   2 +-
 4 files changed, 110 insertions(+), 11 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index bc7fecbd73..d02860e4d7 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -1374,6 +1374,49 @@ static UINT load_all_patches(MSIPACKAGE *package)
     return rc;
 }
 
+static UINT iterate_patched_component( MSIRECORD *row, LPVOID param )
+{
+    MSIPACKAGE *package = param;
+    const WCHAR *name;
+    MSICOMPONENT *c;
+
+    name = MSI_RecordGetString( row, 1 );
+    TRACE( "found patched component: %s\n", wine_dbgstr_w(name) );
+    c = msi_get_loaded_component( package, name );
+    if (!c)
+        return ERROR_SUCCESS;
+
+    c->updated = 1;
+    if (!wcscmp( MSI_RecordGetString( row, 2 ), L"INSERT" ))
+        c->added = 1;
+    return ERROR_SUCCESS;
+}
+
+static void mark_patched_components( MSIPACKAGE *package )
+{
+    static const WCHAR select[] = L"SELECT `Row`, `Column` FROM `_TransformView` WHERE `Table`='Component'";
+    MSIQUERY *q;
+    UINT r;
+
+    r = MSI_OpenQuery( package->db, &q, select );
+    if (r != ERROR_SUCCESS)
+        return;
+
+    MSI_IterateRecords( q, NULL, iterate_patched_component, package );
+    msiobj_release( &q->hdr );
+
+    while (1)
+    {
+        r = MSI_OpenQuery( package->db, &q, L"ALTER TABLE `_TransformView` FREE" );
+        if (r != ERROR_SUCCESS)
+            return;
+        r = MSI_ViewExecute( q, NULL );
+        msiobj_release( &q->hdr );
+        if (r != ERROR_SUCCESS)
+            return;
+    }
+}
+
 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
 {
     static const WCHAR query[] = {
@@ -1518,6 +1561,7 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
     msi_load_all_features( package );
     load_all_files( package );
     load_all_patches( package );
+    mark_patched_components( package );
     load_all_media( package );
 
     return ERROR_SUCCESS;
@@ -1802,12 +1846,6 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
                 }
             }
         }
-        LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-        {
-            if (feature->Feature_Parent) continue;
-            disable_children( feature, level );
-            follow_parent( feature );
-        }
     }
     else if (!msi_get_property_int( package->db, szInstalled, 0 ))
     {
@@ -1834,15 +1872,69 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
                 }
             }
         }
-        /* disable child features of unselected parent or follow parent */
+    }
+    else
+    {
         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
         {
-            if (feature->Feature_Parent) continue;
-            disable_children( feature, level );
-            follow_parent( feature );
+            ComponentList *cl;
+            MSIFEATURE *cur;
+
+            if (!is_feature_selected( feature, level )) continue;
+            if (feature->ActionRequest != INSTALLSTATE_UNKNOWN) continue;
+
+            LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
+            {
+                if (!cl->component->updated && !cl->component->added)
+                    continue;
+
+                cur = feature;
+                while (cur)
+                {
+                    if (cur->ActionRequest != INSTALLSTATE_UNKNOWN)
+                        break;
+
+                    if (cur->Installed != INSTALLSTATE_ABSENT)
+                    {
+                        cur->Action = cur->Installed;
+                        cur->ActionRequest = cur->Installed;
+                    }
+                    else if (!cl->component->added)
+                    {
+                        break;
+                    }
+                    else if (cur->Attributes & msidbFeatureAttributesFavorSource)
+                    {
+                        cur->Action = INSTALLSTATE_SOURCE;
+                        cur->ActionRequest = INSTALLSTATE_SOURCE;
+                    }
+                    else if (cur->Attributes & msidbFeatureAttributesFavorAdvertise)
+                    {
+                        cur->Action = INSTALLSTATE_ADVERTISED;
+                        cur->ActionRequest = INSTALLSTATE_ADVERTISED;
+                    }
+                    else
+                    {
+                        cur->Action = INSTALLSTATE_LOCAL;
+                        cur->ActionRequest = INSTALLSTATE_LOCAL;
+                    }
+
+                    if (!cur->Feature_Parent)
+                        break;
+                    cur = msi_get_loaded_feature(package, cur->Feature_Parent);
+                }
+            }
         }
     }
 
+    /* disable child features of unselected parent or follow parent */
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
+    {
+        if (feature->Feature_Parent) continue;
+        disable_children( feature, level );
+        follow_parent( feature );
+    }
+
     /* now we want to set component state based based on feature state */
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index dbe833e613..a1b7f033c3 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -544,6 +544,8 @@ typedef struct tagMSICOMPONENT
     unsigned int hasAdvertisedFeature:1;
     unsigned int hasLocalFeature:1;
     unsigned int hasSourceFeature:1;
+    unsigned int added:1;
+    unsigned int updated:1;
 } MSICOMPONENT;
 
 typedef struct tagComponentList
diff --git a/dlls/msi/patch.c b/dlls/msi/patch.c
index 1233ec306b..67da577841 100644
--- a/dlls/msi/patch.c
+++ b/dlls/msi/patch.c
@@ -274,9 +274,14 @@ static UINT apply_substorage_transform( MSIPACKAGE *package, MSIDATABASE *patch_
     {
         ret = check_transform_applicable( package, stg );
         if (ret == ERROR_SUCCESS)
+        {
+            msi_table_apply_transform( package->db, stg, MSITRANSFORM_ERROR_VIEWTRANSFORM );
             msi_table_apply_transform( package->db, stg, 0 );
+        }
         else
+        {
             TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
+        }
         IStorage_Release( stg );
     }
     else
diff --git a/dlls/msi/tests/patch.c b/dlls/msi/tests/patch.c
index a846defef4..87f64d6c83 100644
--- a/dlls/msi/tests/patch.c
+++ b/dlls/msi/tests/patch.c
@@ -844,7 +844,7 @@ static void test_simple_patch( void )
     size = get_pf_file_size( "msitest\\patch.txt" );
     ok( size == 1002, "expected 1002, got %u\n", size );
     size = get_pf_file_size( "msitest\\file.txt" );
-    todo_wine ok( size == 1000, "expected 1000, got %u\n", size );
+    ok( size == 1000, "expected 1000, got %u\n", size );
 
     /* show that MsiOpenPackage applies registered patches */
     r = MsiOpenPackageA( path, &hpackage );




More information about the wine-cvs mailing list