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@codeweavers.com>
Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Piotr Caban 2020-07-01 10:44:00 +02:00 committed by Alexandre Julliard
parent 99e7c801e4
commit 877540b522
4 changed files with 110 additions and 11 deletions

View File

@ -1374,6 +1374,49 @@ static UINT load_all_patches(MSIPACKAGE *package)
return rc; 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 UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
{ {
static const WCHAR query[] = { static const WCHAR query[] = {
@ -1518,6 +1561,7 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
msi_load_all_features( package ); msi_load_all_features( package );
load_all_files( package ); load_all_files( package );
load_all_patches( package ); load_all_patches( package );
mark_patched_components( package );
load_all_media( package ); load_all_media( package );
return ERROR_SUCCESS; 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 )) else if (!msi_get_property_int( package->db, szInstalled, 0 ))
{ {
@ -1834,6 +1872,61 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
} }
} }
} }
}
else
{
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
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 */ /* disable child features of unselected parent or follow parent */
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{ {
@ -1841,7 +1934,6 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
disable_children( feature, level ); disable_children( feature, level );
follow_parent( feature ); follow_parent( feature );
} }
}
/* now we want to set component state based based on feature state */ /* now we want to set component state based based on feature state */
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )

View File

@ -544,6 +544,8 @@ typedef struct tagMSICOMPONENT
unsigned int hasAdvertisedFeature:1; unsigned int hasAdvertisedFeature:1;
unsigned int hasLocalFeature:1; unsigned int hasLocalFeature:1;
unsigned int hasSourceFeature:1; unsigned int hasSourceFeature:1;
unsigned int added:1;
unsigned int updated:1;
} MSICOMPONENT; } MSICOMPONENT;
typedef struct tagComponentList typedef struct tagComponentList

View File

@ -274,9 +274,14 @@ static UINT apply_substorage_transform( MSIPACKAGE *package, MSIDATABASE *patch_
{ {
ret = check_transform_applicable( package, stg ); ret = check_transform_applicable( package, stg );
if (ret == ERROR_SUCCESS) if (ret == ERROR_SUCCESS)
{
msi_table_apply_transform( package->db, stg, MSITRANSFORM_ERROR_VIEWTRANSFORM );
msi_table_apply_transform( package->db, stg, 0 ); msi_table_apply_transform( package->db, stg, 0 );
}
else else
{
TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name)); TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
}
IStorage_Release( stg ); IStorage_Release( stg );
} }
else else

View File

@ -844,7 +844,7 @@ static void test_simple_patch( void )
size = get_pf_file_size( "msitest\\patch.txt" ); size = get_pf_file_size( "msitest\\patch.txt" );
ok( size == 1002, "expected 1002, got %u\n", size ); ok( size == 1002, "expected 1002, got %u\n", size );
size = get_pf_file_size( "msitest\\file.txt" ); 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 */ /* show that MsiOpenPackage applies registered patches */
r = MsiOpenPackageA( path, &hpackage ); r = MsiOpenPackageA( path, &hpackage );