diff --git a/dlls/msi/action.c b/dlls/msi/action.c index bc7fecbd739..d02860e4d71 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 dbe833e6134..a1b7f033c37 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 1233ec306bf..67da5778415 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 a846defef45..87f64d6c835 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 );