action.c
来自「一个类似windows」· C语言 代码 · 共 2,053 行 · 第 1/5 页
C
2,053 行
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 hereis 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)
{
feature->ActionRequest = INSTALLSTATE_SOURCE;
feature->Action = INSTALLSTATE_SOURCE;
}
else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
{
feature->ActionRequest = INSTALLSTATE_ADVERTISED;
feature->Action = INSTALLSTATE_ADVERTISED;
}
else
{
feature->ActionRequest = INSTALLSTATE_LOCAL;
feature->Action = INSTALLSTATE_LOCAL;
}
}
}
}
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, Request %i)\n",
debugstr_w(feature->Feature), feature->Installed, feature->Action,
feature->ActionRequest);
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
{
component = cl->component;
if (!component->Enabled)
{
component->Action = INSTALLSTATE_UNKNOWN;
component->ActionRequest = INSTALLSTATE_UNKNOWN;
}
else
{
if (feature->Action == INSTALLSTATE_LOCAL)
{
component->Action = INSTALLSTATE_LOCAL;
component->ActionRequest = INSTALLSTATE_LOCAL;
}
else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
{
if ((component->Action == INSTALLSTATE_UNKNOWN) ||
(component->Action == INSTALLSTATE_ABSENT) ||
(component->Action == INSTALLSTATE_ADVERTISED))
{
component->Action = INSTALLSTATE_SOURCE;
component->ActionRequest = INSTALLSTATE_SOURCE;
}
}
else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
{
if ((component->Action == INSTALLSTATE_UNKNOWN) ||
(component->Action == INSTALLSTATE_ABSENT))
{
component->Action = INSTALLSTATE_ADVERTISED;
component->ActionRequest = INSTALLSTATE_ADVERTISED;
}
}
else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
{
if (component->Action == INSTALLSTATE_UNKNOWN)
{
component->Action = INSTALLSTATE_ABSENT;
component->ActionRequest = INSTALLSTATE_ABSENT;
}
}
}
}
}
LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
{
TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
debugstr_w(component->Component), component->Installed,
component->Action, component->ActionRequest);
}
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;
}
/*
* 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;
MSIFILE *file;
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);
}
TRACE("File calculations\n");
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
MSICOMPONENT* comp = file->Component;
LPWSTR p;
if (!comp)
continue;
/* 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));
if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
{
file->state = msifs_missing;
comp->Cost += file->FileSize;
continue;
}
if (file->Version)
{
DWORD handle;
DWORD versize;
UINT sz;
LPVOID version;
static WCHAR name[] = {'\\',0};
static const WCHAR name_fmt[] =
{'%','u','.','%','u','.','%','u','.','%','u',0};
WCHAR filever[0x100];
VS_FIXEDFILEINFO *lpVer;
TRACE("Version comparison..\n");
versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
version = msi_alloc(versize);
GetFileVersionInfoW(file->TargetPath, 0, versize, version);
VerQueryValueW(version, (LPWSTR)name, (LPVOID*)&lpVer, &sz);
sprintfW(filever,name_fmt,
HIWORD(lpVer->dwFileVersionMS),
LOWORD(lpVer->dwFileVersionMS),
HIWORD(lpVer->dwFileVersionLS),
LOWORD(lpVer->dwFileVersionLS));
TRACE("new %s old %s\n", debugstr_w(file->Version),
debugstr_w(filever));
if (strcmpiW(filever,file->Version)<0)
{
file->state = msifs_overwrite;
/* FIXME: cost should be diff in size */
comp->Cost += file->FileSize;
}
else
file->state = msifs_present;
msi_free(version);
}
else
file->state = msifs_present;
}
TRACE("Evaluating Condition Table\n");
rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
if (rc == ERROR_SUCCESS)
{
rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
package);
msiobj_release(&view->hdr);
}
TRACE("Enabling or Disabling Components\n");
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
{
if (comp->Condition)
{
if (MSI_EvaluateConditionW(package,
comp->Condition) == MSICONDITION_FALSE)
{
TRACE("Disabling component %s\n", debugstr_w(comp->Component));
comp->Enabled = FALSE;
}
}
}
MSI_SetPropertyW(package,szCosting,szOne);
/* set default run level if not set */
level = msi_dup_property( package, szlevel );
if (!level)
MSI_SetPropertyW(package,szlevel, szOne);
msi_free(level);
ACTION_UpdateInstallStates(package);
return SetFeatureStates(package);
}
/* OK this value is "interpreted" and then formatted based on the
first few characters */
static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
DWORD *size)
{
LPSTR data = NULL;
if (value[0]=='#' && value[1]!='#' && value[1]!='%')
{
if (value[1]=='x')
{
LPWSTR ptr;
CHAR byte[5];
LPWSTR deformated = NULL;
int count;
deformat_string(package, &value[2], &deformated);
/* binary value type */
ptr = deformated;
*type = REG_BINARY;
if (strlenW(ptr)%2)
*size = (strlenW(ptr)/2)+1;
else
*size = strlenW(ptr)/2;
data = msi_alloc(*size);
byte[0] = '0';
byte[1] = 'x';
byte[4] = 0;
count = 0;
/* if uneven pad with a zero in front */
if (strlenW(ptr)%2)
{
byte[2]= '0';
byte[3]= *ptr;
ptr++;
data[count] = (BYTE)strtol(byte,NULL,0);
count ++;
TRACE("Uneven byte count\n");
}
while (*ptr)
{
byte[2]= *ptr;
ptr++;
byte[3]= *ptr;
ptr++;
data[count] = (BYTE)strtol(byte,NULL,0);
count ++;
}
msi_free(deformated);
TRACE("Data %li bytes(%i)\n",*size,count);
}
else
{
LPWSTR deformated;
LPWSTR p;
DWORD d = 0;
deformat_string(package, &value[1], &deformated);
*type=REG_DWORD;
*size = sizeof(DWORD);
data = msi_alloc(*size);
p = deformated;
if (*p == '-')
p++;
while (*p)
{
if ( (*p < '0') || (*p > '9') )
break;
d *= 10;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?