📄 action.c
字号:
{
res = INSTALLSTATE_INCOMPLETE;
}
}
}
feature->Installed = res;
}
}
static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
INSTALLSTATE state)
{
static const WCHAR all[]={'A','L','L',0};
LPWSTR override;
MSIFEATURE *feature;
override = msi_dup_property( package, property );
if (!override)
return FALSE;
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
if (strcmpiW(override,all)==0)
msi_feature_set_state( feature, state );
else
{
LPWSTR ptr = override;
LPWSTR ptr2 = strchrW(override,',');
while (ptr)
{
if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
|| (!ptr2 && strcmpW(ptr,feature->Feature)==0))
{
msi_feature_set_state( feature, state );
break;
}
if (ptr2)
{
ptr=ptr2+1;
ptr2 = strchrW(ptr,',');
}
else
break;
}
}
}
msi_free(override);
return TRUE;
}
UINT MSI_SetFeatureStates(MSIPACKAGE *package)
{
int install_level;
static const WCHAR szlevel[] =
{'I','N','S','T','A','L','L','L','E','V','E','L',0};
static const WCHAR szAddLocal[] =
{'A','D','D','L','O','C','A','L',0};
static const WCHAR szRemove[] =
{'R','E','M','O','V','E',0};
static const WCHAR szReinstall[] =
{'R','E','I','N','S','T','A','L','L',0};
BOOL override = FALSE;
MSICOMPONENT* component;
MSIFEATURE *feature;
/* I do not know if this is where it should happen.. but */
TRACE("Checking Install Level\n");
install_level = msi_get_property_int( package, szlevel, 1 );
/* ok here is the _real_ rub
* all these activation/deactivation things happen in order and things
* later on the list override things earlier on the list.
* 1) INSTALLLEVEL processing
* 2) ADDLOCAL
* 3) REMOVE
* 4) ADDSOURCE
* 5) ADDDEFAULT
* 6) REINSTALL
* 7) COMPADDLOCAL
* 8) COMPADDSOURCE
* 9) FILEADDLOCAL
* 10) FILEADDSOURCE
* 11) FILEADDDEFAULT
* I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
* ignored for all the features. seems strange, especially since it is not
* documented anywhere, but it is how it works.
*
* I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
* REMOVE are the big ones, since we don't handle administrative installs
* yet anyway.
*/
override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
if (!override)
{
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
BOOL feature_state = ((feature->Level > 0) &&
(feature->Level <= install_level));
if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
{
if (feature->Attributes & msidbFeatureAttributesFavorSource)
msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
else
msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
}
}
/* 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 )
msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
}
}
else
{
/* set the Preselected Property */
static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
static const WCHAR szOne[] = { '1', 0 };
MSI_SetPropertyW(package,szPreselected,szOne);
}
/*
* now we want to enable or disable components base on feature
*/
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
ComponentList *cl;
TRACE("Examining Feature %s (Installed %i, Action %i)\n",
debugstr_w(feature->Feature), feature->Installed, feature->Action);
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
{
component = cl->component;
if (!component->Enabled)
continue;
if (component->Attributes & msidbComponentAttributesOptional)
msi_component_set_state( component, INSTALLSTATE_DEFAULT );
else
{
if (component->Attributes & msidbComponentAttributesSourceOnly)
msi_component_set_state( component, INSTALLSTATE_SOURCE );
else
msi_component_set_state( component, INSTALLSTATE_LOCAL );
}
if (component->ForceLocalState)
msi_component_set_state( component, INSTALLSTATE_LOCAL );
if (feature->Attributes == msidbFeatureAttributesFavorLocal)
{
if (!(component->Attributes & msidbComponentAttributesSourceOnly))
msi_component_set_state( component, INSTALLSTATE_LOCAL );
}
else if (feature->Attributes == msidbFeatureAttributesFavorSource)
{
if ((component->Action == INSTALLSTATE_UNKNOWN) ||
(component->Action == INSTALLSTATE_ABSENT) ||
(component->Action == INSTALLSTATE_ADVERTISED) ||
(component->Action == INSTALLSTATE_DEFAULT))
msi_component_set_state( component, INSTALLSTATE_SOURCE );
}
else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
{
if ((component->Action == INSTALLSTATE_UNKNOWN) ||
(component->Action == INSTALLSTATE_ABSENT))
msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
}
else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
{
if (component->Action == INSTALLSTATE_UNKNOWN)
msi_component_set_state( component, INSTALLSTATE_ABSENT );
}
else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
}
}
LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
{
if (component->Action == INSTALLSTATE_DEFAULT)
{
TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
msi_component_set_state( component, INSTALLSTATE_LOCAL );
}
TRACE("Result: Component %s (Installed %i, Action %i)\n",
debugstr_w(component->Component), component->Installed, component->Action);
}
return ERROR_SUCCESS;
}
static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = (MSIPACKAGE*)param;
LPCWSTR name;
LPWSTR path;
name = MSI_RecordGetString(row,1);
/* This helper function now does ALL the work */
TRACE("Dir %s ...\n",debugstr_w(name));
load_folder(package,name);
path = resolve_folder(package,name,FALSE,TRUE,NULL);
TRACE("resolves to %s\n",debugstr_w(path));
msi_free(path);
return ERROR_SUCCESS;
}
static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = (MSIPACKAGE*)param;
LPCWSTR name;
MSIFEATURE *feature;
name = MSI_RecordGetString( row, 1 );
feature = get_loaded_feature( package, name );
if (!feature)
ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
else
{
LPCWSTR Condition;
Condition = MSI_RecordGetString(row,3);
if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
{
int level = MSI_RecordGetInteger(row,2);
TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
feature->Level = level;
}
}
return ERROR_SUCCESS;
}
LPWSTR msi_get_disk_file_version( LPCWSTR filename )
{
static const WCHAR name_fmt[] =
{'%','u','.','%','u','.','%','u','.','%','u',0};
static WCHAR name[] = {'\\',0};
VS_FIXEDFILEINFO *lpVer;
WCHAR filever[0x100];
LPVOID version;
DWORD versize;
DWORD handle;
UINT sz;
TRACE("%s\n", debugstr_w(filename));
versize = GetFileVersionInfoSizeW( filename, &handle );
if (!versize)
return NULL;
version = msi_alloc( versize );
GetFileVersionInfoW( filename, 0, versize, version );
VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
msi_free( version );
sprintfW( filever, name_fmt,
HIWORD(lpVer->dwFileVersionMS),
LOWORD(lpVer->dwFileVersionMS),
HIWORD(lpVer->dwFileVersionLS),
LOWORD(lpVer->dwFileVersionLS));
return strdupW( filever );
}
static UINT msi_check_file_install_states( MSIPACKAGE *package )
{
LPWSTR file_version;
MSIFILE *file;
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
MSICOMPONENT* comp = file->Component;
LPWSTR p;
if (!comp)
continue;
if (file->IsCompressed)
comp->ForceLocalState = TRUE;
/* calculate target */
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
msi_free(file->TargetPath);
TRACE("file %s is named %s\n",
debugstr_w(file->File), debugstr_w(file->FileName));
file->TargetPath = build_directory_name(2, p, file->FileName);
msi_free(p);
TRACE("file %s resolves to %s\n",
debugstr_w(file->File), debugstr_w(file->TargetPath));
/* don't check files of components that aren't installed */
if (comp->Installed == INSTALLSTATE_UNKNOWN ||
comp->Installed == INSTALLSTATE_ABSENT)
{
file->state = msifs_missing; /* assume files are missing */
continue;
}
if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
{
file->state = msifs_missing;
comp->Cost += file->FileSize;
comp->Installed = INSTALLSTATE_INCOMPLETE;
continue;
}
if (file->Version &&
(file_version = msi_get_disk_file_version( file->TargetPath )))
{
TRACE("new %s old %s\n", debugstr_w(file->Version),
debugstr_w(file_version));
/* FIXME: seems like a bad way to compare version numbers */
if (lstrcmpiW(file_version, file->Version)<0)
{
file->state = msifs_overwrite;
comp->Cost += file->FileSize;
comp->Installed = INSTALLSTATE_INCOMPLETE;
}
else
file->state = msifs_present;
msi_free( file_version );
}
else
file->state = msifs_present;
}
return ERROR_SUCCESS;
}
/*
* A lot is done in this function aside from just the costing.
* The costing needs to be implemented at some point but for now I am going
* to focus on the directory building
*
*/
static UINT ACTION_CostFinalize(MSIPACKAGE *package)
{
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','D','i','r','e','c','t','o','r','y','`',0};
static const WCHAR ConditionQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','C','o','n','d','i','t','i','o','n','`',0};
static const WCHAR szCosting[] =
{'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
static const WCHAR szlevel[] =
{'I','N','S','T','A','L','L','L','E','V','E','L',0};
static const WCHAR szOne[] = { '1', 0 };
MSICOMPONENT *comp;
UINT rc;
MSIQUERY * view;
LPWSTR level;
if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
return ERROR_SUCCESS;
TRACE("Building Directory properties\n");
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc == ERROR_SUCCESS)
{
rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
package);
msiobj_release(&view->hdr);
}
/* read components states from the registry */
ACTION_GetComponentInstallStates(package);
TRACE("File calculations\n");
msi_check_file_install_states( package );
TR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -