msi: Disable child features of parent features that are unselected because of the install level.
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index a1729d3..037d509 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -1163,6 +1163,19 @@
return ERROR_SUCCESS;
}
+static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
+{
+ FeatureList *fl;
+
+ fl = msi_alloc( sizeof(*fl) );
+ if ( !fl )
+ return ERROR_NOT_ENOUGH_MEMORY;
+ fl->feature = child;
+ list_add_tail( &parent->Children, &fl->entry );
+
+ return ERROR_SUCCESS;
+}
+
static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
{
_ilfs* ilfs= (_ilfs*)param;
@@ -1185,6 +1198,19 @@
return ERROR_SUCCESS;
}
+static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
+{
+ MSIFEATURE *feature;
+
+ LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
+ {
+ if ( !lstrcmpW( feature->Feature, name ) )
+ return feature;
+ }
+
+ return NULL;
+}
+
static UINT load_feature(MSIRECORD * row, LPVOID param)
{
MSIPACKAGE* package = (MSIPACKAGE*)param;
@@ -1206,6 +1232,7 @@
if (!feature)
return ERROR_NOT_ENOUGH_MEMORY;
+ list_init( &feature->Children );
list_init( &feature->Components );
feature->Feature = msi_dup_record_field( row, 1 );
@@ -1244,6 +1271,26 @@
return ERROR_SUCCESS;
}
+static UINT find_feature_children(MSIRECORD * row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ MSIFEATURE *parent, *child;
+
+ child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
+ if (!child)
+ return ERROR_FUNCTION_FAILED;
+
+ if (!child->Feature_Parent)
+ return ERROR_SUCCESS;
+
+ parent = find_feature_by_name( package, child->Feature_Parent );
+ if (!parent)
+ return ERROR_FUNCTION_FAILED;
+
+ add_feature_child( parent, child );
+ return ERROR_SUCCESS;
+}
+
static UINT load_all_features( MSIPACKAGE *package )
{
static const WCHAR query[] = {
@@ -1261,7 +1308,12 @@
return r;
r = MSI_IterateRecords( view, NULL, load_feature, package );
+ if (r != ERROR_SUCCESS)
+ return r;
+
+ r = MSI_IterateRecords( view, NULL, find_feature_children, package );
msiobj_release( &view->hdr );
+
return r;
}
@@ -1542,7 +1594,7 @@
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
ComponentList *cl;
- INSTALLSTATE res = -10;
+ INSTALLSTATE res = INSTALLSTATE_ABSENT;
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
{
@@ -1554,7 +1606,7 @@
break;
}
- if (res == -10)
+ if (res == INSTALLSTATE_ABSENT)
res = comp->Installed;
else
{
@@ -1693,6 +1745,21 @@
}
}
}
+
+ /* disable child features of unselected parent features */
+ LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
+ {
+ FeatureList *fl;
+
+ if (feature->Level > 0 && feature->Level <= install_level)
+ continue;
+
+ LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
+ {
+ fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
+ fl->feature->Action = INSTALLSTATE_UNKNOWN;
+ }
+ }
}
else
{
diff --git a/dlls/msi/action.h b/dlls/msi/action.h
index 785c4e3..ae7de82 100644
--- a/dlls/msi/action.h
+++ b/dlls/msi/action.h
@@ -39,6 +39,7 @@
INSTALLSTATE ActionRequest;
INSTALLSTATE Action;
+ struct list Children;
struct list Components;
INT Cost;
@@ -74,6 +75,12 @@
MSICOMPONENT *component;
} ComponentList;
+typedef struct tagFeatureList
+{
+ struct list entry;
+ MSIFEATURE *feature;
+} FeatureList;
+
typedef struct tagMSIFOLDER
{
struct list entry;
diff --git a/dlls/msi/helpers.c b/dlls/msi/helpers.c
index 8c957a2..50fc992 100644
--- a/dlls/msi/helpers.c
+++ b/dlls/msi/helpers.c
@@ -404,6 +404,13 @@
{
struct list *item, *cursor;
+ LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
+ {
+ FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
+ list_remove( &fl->entry );
+ msi_free( fl );
+ }
+
LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
{
ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c
index 4e9d40a..cd55f89 100644
--- a/dlls/msi/tests/package.c
+++ b/dlls/msi/tests/package.c
@@ -2366,6 +2366,14 @@
r = add_feature_entry( hdb, "'orion', '', '', '', 2, 1, '', 0" );
ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r );
+ /* disabled because of install level */
+ r = add_feature_entry( hdb, "'waters', '', '', '', 15, 101, '', 9" );
+ ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r );
+
+ /* child feature of disabled feature */
+ r = add_feature_entry( hdb, "'bayer', 'waters', '', '', 14, 1, '', 9" );
+ ok( r == ERROR_SUCCESS, "cannot add feature: %d\n", r );
+
/* msidbFeatureAttributesFavorLocal:msidbComponentAttributesLocalOnly */
r = add_component_entry( hdb, "'leo', '', 'TARGETDIR', 0, '', 'leo_file'" );
ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
@@ -2508,6 +2516,20 @@
state = 0xdeadbee;
action = 0xdeadbee;
+ r = MsiGetFeatureState(hpkg, "waters", &state, &action);
+ ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
+ ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state);
+ ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action);
+
+ state = 0xdeadbee;
+ action = 0xdeadbee;
+ r = MsiGetFeatureState(hpkg, "bayer", &state, &action);
+ ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
+ ok( state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state);
+ ok( action == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", action);
+
+ state = 0xdeadbee;
+ action = 0xdeadbee;
r = MsiGetComponentState(hpkg, "leo", &state, &action);
ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
ok( state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);