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