- Rework how we handle Feature and Component States. I have confirmed

from testing that, although documented nowhere, having ADDLOCAL on
  the install line overrides INSTALLLEVEL.
- Track all files extracted from cabinents as tempfiles so they can be
  removed at the end of the install to not leave uninstalled but
  uncabbed files laying around.
This commit is contained in:
Aric Stewart 2004-12-27 19:06:22 +00:00 committed by Alexandre Julliard
parent ae1aa32c77
commit fbdd70968d
1 changed files with 140 additions and 64 deletions

View File

@ -64,8 +64,10 @@ typedef struct tagMSIFEATURE
WCHAR Directory[96]; WCHAR Directory[96];
INT Attributes; INT Attributes;
INSTALLSTATE State; INSTALLSTATE Installed;
BOOL Enabled; INSTALLSTATE ActionRequest;
INSTALLSTATE Action;
INT ComponentCount; INT ComponentCount;
INT Components[1024]; /* yes hardcoded limit.... I am bad */ INT Components[1024]; /* yes hardcoded limit.... I am bad */
INT Cost; INT Cost;
@ -80,8 +82,10 @@ typedef struct tagMSICOMPONENT
WCHAR Condition[0x100]; WCHAR Condition[0x100];
WCHAR KeyPath[96]; WCHAR KeyPath[96];
INSTALLSTATE State; INSTALLSTATE Installed;
BOOL FeatureState; INSTALLSTATE ActionRequest;
INSTALLSTATE Action;
BOOL Enabled; BOOL Enabled;
INT Cost; INT Cost;
} MSICOMPONENT; } MSICOMPONENT;
@ -411,7 +415,10 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
for (i = 0; i < package->loaded_files; i++) for (i = 0; i < package->loaded_files; i++)
{ {
if (package->files[i].Temporary) if (package->files[i].Temporary)
{
TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
DeleteFileW(package->files[i].TargetPath); DeleteFileW(package->files[i].TargetPath);
}
} }
} }
@ -1832,9 +1839,11 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row)
sz = 96; sz = 96;
MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
package->components[index].State = INSTALLSTATE_ABSENT; package->components[index].Installed = INSTALLSTATE_ABSENT;
package->components[index].Action = INSTALLSTATE_UNKNOWN;
package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
package->components[index].Enabled = TRUE; package->components[index].Enabled = TRUE;
package->components[index].FeatureState= FALSE;
return index; return index;
} }
@ -1894,7 +1903,10 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
package->features[index].Attributes= MSI_RecordGetInteger(row,8); package->features[index].Attributes= MSI_RecordGetInteger(row,8);
package->features[index].State = INSTALLSTATE_ABSENT;
package->features[index].Installed = INSTALLSTATE_ABSENT;
package->features[index].Action = INSTALLSTATE_UNKNOWN;
package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
/* load feature components */ /* load feature components */
@ -2372,39 +2384,84 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
else else
install_level = 1; install_level = 1;
override = load_dynamic_property(package,szAddLocal,NULL); /* ok hereis the rub
* ADDLOCAL and its friend OVERRIDE INSTALLLEVLE
/* * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is
* Components FeatureState defaults to FALSE. The idea is we want to * itnored for all the features. seems strange, epsecially since it is not
* enable the component is ANY feature that uses it is enabled to install * documented anywhere, but it is how it works.
*/ */
for(i = 0; i < package->loaded_features; i++)
override = load_dynamic_property(package,szAddLocal,NULL);
if (override)
{ {
BOOL feature_state= ((package->features[i].Level > 0) && for(i = 0; i < package->loaded_features; i++)
{
if (strcmpiW(override,all)==0 ||
strstrW(override,package->features[i].Feature))
{
package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
package->features[i].Action = INSTALLSTATE_LOCAL;
}
}
HeapFree(GetProcessHeap(),0,override);
}
else
{
for(i = 0; i < package->loaded_features; i++)
{
BOOL feature_state= ((package->features[i].Level > 0) &&
(package->features[i].Level <= install_level)); (package->features[i].Level <= install_level));
if (override && (strcmpiW(override,all)==0 || if (feature_state)
strstrW(override,package->features[i].Feature))) {
{ package->features[i].ActionRequest= INSTALLSTATE_LOCAL;
TRACE("Override of install level found\n"); package->features[i].Action = INSTALLSTATE_LOCAL;
feature_state = TRUE; }
} }
package->features[i].Enabled = feature_state; }
TRACE("Feature %s has a state of %i\n", /*
debugstr_w(package->features[i].Feature), feature_state); * now we want to enable or disable components base on feature
for( j = 0; j < package->features[i].ComponentCount; j++) */
for(i = 0; i < package->loaded_features; i++)
{
MSIFEATURE* feature = &package->features[i];
TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
debugstr_w(feature->Feature), feature->Installed, feature->Action,
feature->ActionRequest);
for( j = 0; j < feature->ComponentCount; j++)
{ {
package->components[package->features[i].Components[j]].FeatureState MSICOMPONENT* component = &package->components[
|= feature_state; feature->Components[j]];
if (!component->Enabled)
{
component->Action = INSTALLSTATE_ABSENT;
component->ActionRequest = INSTALLSTATE_ABSENT;
}
else
{
if (feature->Action == INSTALLSTATE_LOCAL)
component->Action = INSTALLSTATE_LOCAL;
if (feature->ActionRequest == INSTALLSTATE_LOCAL)
component->ActionRequest = INSTALLSTATE_LOCAL;
}
} }
} }
if (override)
HeapFree(GetProcessHeap(),0,override); for(i = 0; i < package->loaded_components; i++)
/* {
* So basically we ONLY want to install a component if its Enabled AND MSICOMPONENT* component= &package->components[i];
* FeatureState are both TRUE
*/ TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
debugstr_w(component->Component), component->Installed,
component->Action, component->ActionRequest);
}
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -2686,6 +2743,11 @@ end:
/* Support functions for FDI functions */ /* Support functions for FDI functions */
typedef struct
{
MSIPACKAGE* package;
LPCSTR cab_path;
} CabData;
static void * cabinet_alloc(ULONG cb) static void * cabinet_alloc(ULONG cb)
{ {
@ -2758,14 +2820,35 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{ {
case fdintCOPY_FILE: case fdintCOPY_FILE:
{ {
ULONG len = strlen((char*)pfdin->pv) + strlen(pfdin->psz1); CabData *data = (CabData*) pfdin->pv;
ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
char *file = cabinet_alloc((len+1)*sizeof(char)); char *file = cabinet_alloc((len+1)*sizeof(char));
strcpy(file, (char*)pfdin->pv); LPWSTR trackname;
LPWSTR trackpath;
LPWSTR tracknametmp;
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
strcpy(file, data->cab_path);
strcat(file, pfdin->psz1); strcat(file, pfdin->psz1);
TRACE("file: %s\n", debugstr_a(file)); TRACE("file: %s\n", debugstr_a(file));
/* track this file so it can be deleted if not installed */
trackpath=strdupAtoW(file);
tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
strlenW(tmpprefix)+1) * sizeof(WCHAR));
strcpyW(trackname,tmpprefix);
strcatW(trackname,tracknametmp);
track_tempfile(data->package, trackname, trackpath);
HeapFree(GetProcessHeap(),0,trackpath);
HeapFree(GetProcessHeap(),0,trackname);
HeapFree(GetProcessHeap(),0,tracknametmp);
return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
} }
case fdintCLOSE_FILE_INFO: case fdintCLOSE_FILE_INFO:
@ -2792,13 +2875,15 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
* *
* Extract files from a cab file. * Extract files from a cab file.
*/ */
static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path) static BOOL extract_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
const WCHAR* path)
{ {
HFDI hfdi; HFDI hfdi;
ERF erf; ERF erf;
BOOL ret; BOOL ret;
char *cabinet; char *cabinet;
char *cab_path; char *cab_path;
CabData data;
TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
@ -2829,7 +2914,10 @@ static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
return FALSE; return FALSE;
} }
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, cab_path); data.package = package;
data.cab_path = cab_path;
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
if (!ret) if (!ret)
ERR("FDICopy failed\n"); ERR("FDICopy failed\n");
@ -2921,7 +3009,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence,
GetTempPathW(MAX_PATH,path); GetTempPathW(MAX_PATH,path);
} }
} }
rc = !extract_cabinet_file(source,path); rc = !extract_cabinet_file(package, source,path);
} }
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
MSI_ViewClose(view); MSI_ViewClose(view);
@ -2974,11 +3062,12 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package)
if (file->Temporary) if (file->Temporary)
continue; continue;
if (!package->components[file->ComponentIndex].Enabled || if (package->components[file->ComponentIndex].ActionRequest !=
!package->components[file->ComponentIndex].FeatureState) INSTALLSTATE_LOCAL)
{ {
TRACE("File %s is not scheduled for install\n", TRACE("File %s is not scheduled for install\n",
debugstr_w(file->File)); debugstr_w(file->File));
continue; continue;
} }
@ -3127,8 +3216,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
} }
component_index = get_loaded_component(package,component); component_index = get_loaded_component(package,component);
if (!package->components[component_index].Enabled || if (package->components[component_index].ActionRequest !=
!package->components[component_index].FeatureState) INSTALLSTATE_LOCAL)
{ {
TRACE("Skipping copy due to disabled component\n"); TRACE("Skipping copy due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
@ -3358,8 +3447,8 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
component = load_dynamic_stringW(row, 6); component = load_dynamic_stringW(row, 6);
component_index = get_loaded_component(package,component); component_index = get_loaded_component(package,component);
if (!package->components[component_index].Enabled || if (package->components[component_index].ActionRequest !=
!package->components[component_index].FeatureState) INSTALLSTATE_LOCAL)
{ {
TRACE("Skipping write due to disabled component\n"); TRACE("Skipping write due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
@ -3865,8 +3954,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping typelib reg due to disabled component\n"); TRACE("Skipping typelib reg due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
@ -4110,8 +4198,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping class reg due to disabled component\n"); TRACE("Skipping class reg due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
@ -4471,8 +4558,7 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
continue; continue;
} }
if (!package->components[index].Enabled || if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)
!package->components[index].FeatureState)
{ {
TRACE("Skipping shortcut creation due to disabled component\n"); TRACE("Skipping shortcut creation due to disabled component\n");
msiobj_release(&row->hdr); msiobj_release(&row->hdr);
@ -5027,7 +5113,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
if (index < 0) if (index < 0)
return ERROR_UNKNOWN_FEATURE; return ERROR_UNKNOWN_FEATURE;
package->features[index].State = iState; package->features[index].ActionRequest= iState;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -5057,15 +5143,11 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
return ERROR_UNKNOWN_FEATURE; return ERROR_UNKNOWN_FEATURE;
if (piInstalled) if (piInstalled)
*piInstalled = package->features[index].State; *piInstalled = package->features[index].Installed;
if (piAction) if (piAction)
{ *piAction = package->features[index].Action;
if (package->features[index].Enabled)
*piAction = INSTALLSTATE_LOCAL;
else
*piAction = package->features[index].State;
}
TRACE("returning %i %i\n",*piInstalled,*piAction); TRACE("returning %i %i\n",*piInstalled,*piAction);
return ERROR_SUCCESS; return ERROR_SUCCESS;
@ -5116,16 +5198,10 @@ piAction);
return ERROR_UNKNOWN_COMPONENT; return ERROR_UNKNOWN_COMPONENT;
if (piInstalled) if (piInstalled)
*piInstalled = package->components[index].State; *piInstalled = package->components[index].Installed;
if (piAction) if (piAction)
{ *piInstalled = package->components[index].Action;
if (package->components[index].Enabled &&
package->components[index].FeatureState)
*piAction = INSTALLSTATE_LOCAL;
else
*piAction = INSTALLSTATE_UNKNOWN;
}
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }