📄 action.c
字号:
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;
MSIFEATURE* feature;
static const WCHAR Query1[] =
{'S','E','L','E','C','T',' ',
'`','C','o','m','p','o','n','e','n','t','_','`',
' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
'C','o','m','p','o','n','e','n','t','s','`',' ',
'W','H','E','R','E',' ',
'`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
MSIQUERY * view;
UINT rc;
_ilfs ilfs;
/* fill in the data */
feature = msi_alloc_zero( sizeof (MSIFEATURE) );
if (!feature)
return ERROR_NOT_ENOUGH_MEMORY;
list_init( &feature->Children );
list_init( &feature->Components );
feature->Feature = msi_dup_record_field( row, 1 );
TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
feature->Feature_Parent = msi_dup_record_field( row, 2 );
feature->Title = msi_dup_record_field( row, 3 );
feature->Description = msi_dup_record_field( row, 4 );
if (!MSI_RecordIsNull(row,5))
feature->Display = MSI_RecordGetInteger(row,5);
feature->Level= MSI_RecordGetInteger(row,6);
feature->Directory = msi_dup_record_field( row, 7 );
feature->Attributes = MSI_RecordGetInteger(row,8);
feature->Installed = INSTALLSTATE_UNKNOWN;
msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
list_add_tail( &package->features, &feature->entry );
/* load feature components */
rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
ilfs.package = package;
ilfs.feature = feature;
MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
msiobj_release(&view->hdr);
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[] = {
'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
'`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
MSIQUERY *view;
UINT r;
if (!list_empty(&package->features))
return ERROR_SUCCESS;
r = MSI_DatabaseOpenViewW( package->db, query, &view );
if (r != ERROR_SUCCESS)
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;
}
static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
{
if (!p)
return p;
p = strchrW(p, ch);
if (!p)
return p;
*p = 0;
return p+1;
}
static UINT load_file(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE* package = (MSIPACKAGE*)param;
LPCWSTR component;
MSIFILE *file;
/* fill in the data */
file = msi_alloc_zero( sizeof (MSIFILE) );
if (!file)
return ERROR_NOT_ENOUGH_MEMORY;
file->File = msi_dup_record_field( row, 1 );
component = MSI_RecordGetString( row, 2 );
file->Component = get_loaded_component( package, component );
if (!file->Component)
ERR("Unfound Component %s\n",debugstr_w(component));
file->FileName = msi_dup_record_field( row, 3 );
reduce_to_longfilename( file->FileName );
file->ShortName = msi_dup_record_field( row, 3 );
file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
file->FileSize = MSI_RecordGetInteger( row, 4 );
file->Version = msi_dup_record_field( row, 5 );
file->Language = msi_dup_record_field( row, 6 );
file->Attributes = MSI_RecordGetInteger( row, 7 );
file->Sequence = MSI_RecordGetInteger( row, 8 );
file->state = msifs_invalid;
/* if the compressed bits are not set in the file attributes,
* then read the information from the package word count property
*/
if (file->Attributes & msidbFileAttributesCompressed)
{
file->IsCompressed = TRUE;
}
else if (file->Attributes & msidbFileAttributesNoncompressed)
{
file->IsCompressed = FALSE;
}
else
{
file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
}
TRACE("File Loaded (%s)\n",debugstr_w(file->File));
list_add_tail( &package->files, &file->entry );
return ERROR_SUCCESS;
}
static UINT load_all_files(MSIPACKAGE *package)
{
MSIQUERY * view;
UINT rc;
static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
'`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
'`','S','e','q','u','e','n','c','e','`', 0};
if (!list_empty(&package->files))
return ERROR_SUCCESS;
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
rc = MSI_IterateRecords(view, NULL, load_file, package);
msiobj_release(&view->hdr);
return ERROR_SUCCESS;
}
/*
* I am not doing any of the costing functionality yet.
* Mostly looking at doing the Component and Feature loading
*
* The native MSI does A LOT of modification to tables here. Mostly adding
* a lot of temporary columns to the Feature and Component tables.
*
* note: Native msi also tracks the short filename. But I am only going to
* track the long ones. Also looking at this directory table
* it appears that the directory table does not get the parents
* resolved base on property only based on their entries in the
* directory table.
*/
static UINT ACTION_CostInitialize(MSIPACKAGE *package)
{
static const WCHAR szCosting[] =
{'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
static const WCHAR szZero[] = { '0', 0 };
if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
return ERROR_SUCCESS;
MSI_SetPropertyW(package, szCosting, szZero);
MSI_SetPropertyW(package, cszRootDrive, c_colon);
load_all_components( package );
load_all_features( package );
load_all_files( package );
return ERROR_SUCCESS;
}
static UINT execute_script(MSIPACKAGE *package, UINT script )
{
int i;
UINT rc = ERROR_SUCCESS;
TRACE("Executing Script %i\n",script);
if (!package->script)
{
ERR("no script!\n");
return ERROR_FUNCTION_FAILED;
}
for (i = 0; i < package->script->ActionCount[script]; i++)
{
LPWSTR action;
action = package->script->Actions[script][i];
ui_actionstart(package, action);
TRACE("Executing Action (%s)\n",debugstr_w(action));
rc = ACTION_PerformAction(package, action, TRUE);
if (rc != ERROR_SUCCESS)
break;
}
msi_free_action_script(package, script);
return rc;
}
static UINT ACTION_FileCost(MSIPACKAGE *package)
{
return ERROR_SUCCESS;
}
static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
{
static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','D','i','r','e','c', 't','o','r','y','`',' ',
'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
' ','=',' ','\'','%','s','\'',
0};
static const WCHAR szDot[] = { '.',0 };
static WCHAR szEmpty[] = { 0 };
LPWSTR p, tgt_short, tgt_long, src_short, src_long;
LPCWSTR parent;
MSIRECORD *row;
MSIFOLDER *folder;
TRACE("Looking for dir %s\n",debugstr_w(dir));
folder = get_loaded_folder( package, dir );
if (folder)
return folder;
TRACE("Working to load %s\n",debugstr_w(dir));
folder = msi_alloc_zero( sizeof (MSIFOLDER) );
if (!folder)
return NULL;
folder->Directory = strdupW(dir);
row = MSI_QueryGetRecord(package->db, Query, dir);
if (!row)
return NULL;
p = msi_dup_record_field(row, 3);
/* split src and target dir */
tgt_short = p;
src_short = folder_split_path( p, ':' );
/* split the long and short paths */
tgt_long = folder_split_path( tgt_short, '|' );
src_long = folder_split_path( src_short, '|' );
/* check for no-op dirs */
if (!lstrcmpW(szDot, tgt_short))
tgt_short = szEmpty;
if (!lstrcmpW(szDot, src_short))
src_short = szEmpty;
if (!tgt_long)
tgt_long = tgt_short;
if (!src_short) {
src_short = tgt_short;
src_long = tgt_long;
}
if (!src_long)
src_long = src_short;
/* FIXME: use the target short path too */
folder->TargetDefault = strdupW(tgt_long);
folder->SourceShortPath = strdupW(src_short);
folder->SourceLongPath = strdupW(src_long);
msi_free(p);
TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
parent = MSI_RecordGetString(row, 2);
if (parent)
{
folder->Parent = load_folder( package, parent );
if ( folder->Parent )
TRACE("loaded parent %p %s\n", folder->Parent,
debugstr_w(folder->Parent->Directory));
else
ERR("failed to load parent folder %s\n", debugstr_w(parent));
}
folder->Property = msi_dup_property( package, dir );
msiobj_release(&row->hdr);
list_add_tail( &package->folders, &folder->entry );
TRACE("%s returning %p\n",debugstr_w(dir),folder);
return folder;
}
static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
{
MSICOMPONENT *comp;
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
{
INSTALLSTATE res;
if (!comp->ComponentId)
continue;
res = MsiGetComponentPathW( package->ProductCode,
comp->ComponentId, NULL, NULL);
if (res < 0)
res = INSTALLSTATE_ABSENT;
comp->Installed = res;
}
}
/* scan for and update current install states */
static void ACTION_UpdateFeatureInstallStates(MSIPACKAGE *package)
{
MSICOMPONENT *comp;
MSIFEATURE *feature;
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
{
ComponentList *cl;
INSTALLSTATE res = INSTALLSTATE_ABSENT;
LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
{
comp= cl->component;
if (!comp->ComponentId)
{
res = INSTALLSTATE_ABSENT;
break;
}
if (res == INSTALLSTATE_ABSENT)
res = comp->Installed;
else
{
if (res == comp->Installed)
continue;
if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
res != INSTALLSTATE_SOURCE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -