📄 action.c
字号:
if ( strstrW( patch_product, prod_code ) )
ret = ERROR_SUCCESS;
else
ret = ERROR_FUNCTION_FAILED;
msi_free( patch_product );
msi_free( prod_code );
return ret;
}
static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
MSIDATABASE *patch_db, LPCWSTR name )
{
UINT ret = ERROR_FUNCTION_FAILED;
IStorage *stg = NULL;
HRESULT r;
TRACE("%p %s\n", package, debugstr_w(name) );
if (*name++ != ':')
{
ERR("expected a colon in %s\n", debugstr_w(name));
return ERROR_FUNCTION_FAILED;
}
r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
if (SUCCEEDED(r))
{
ret = msi_check_transform_applicable( package, stg );
if (ret == ERROR_SUCCESS)
msi_table_apply_transform( package->db, stg );
else
TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
IStorage_Release( stg );
}
else
ERR("failed to open substorage %s\n", debugstr_w(name));
return ERROR_SUCCESS;
}
static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
{
static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
LPWSTR guid_list, *guids, product_id;
UINT i, ret = ERROR_FUNCTION_FAILED;
product_id = msi_dup_property( package, szProdID );
if (!product_id)
{
/* FIXME: the property ProductID should be written into the DB somewhere */
ERR("no product ID to check\n");
return ERROR_SUCCESS;
}
guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
guids = msi_split_string( guid_list, ';' );
for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
{
if (!lstrcmpW( guids[i], product_id ))
ret = ERROR_SUCCESS;
}
msi_free( guids );
msi_free( guid_list );
msi_free( product_id );
return ret;
}
static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
{
MSISUMMARYINFO *si;
LPWSTR str, *substorage;
UINT i, r = ERROR_SUCCESS;
si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
if (!si)
return ERROR_FUNCTION_FAILED;
msi_check_patch_applicable( package, si );
/* enumerate the substorage */
str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
substorage = msi_split_string( str, ';' );
for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
msi_free( substorage );
msi_free( str );
/* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
msiobj_release( &si->hdr );
return r;
}
static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
{
MSIDATABASE *patch_db = NULL;
UINT r;
TRACE("%p %s\n", package, debugstr_w( file ) );
/* FIXME:
* We probably want to make sure we only open a patch collection here.
* Patch collections (.msp) and databases (.msi) have different GUIDs
* but currently MSI_OpenDatabaseW will accept both.
*/
r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
if ( r != ERROR_SUCCESS )
{
ERR("failed to open patch collection %s\n", debugstr_w( file ) );
return r;
}
msi_parse_patch_summary( package, patch_db );
/*
* There might be a CAB file in the patch package,
* so append it to the list of storage to search for streams.
*/
append_storage_to_db( package->db, patch_db->storage );
msiobj_release( &patch_db->hdr );
return ERROR_SUCCESS;
}
/* get the PATCH property, and apply all the patches it specifies */
static UINT msi_apply_patches( MSIPACKAGE *package )
{
static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
LPWSTR patch_list, *patches;
UINT i, r = ERROR_SUCCESS;
patch_list = msi_dup_property( package, szPatch );
TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
patches = msi_split_string( patch_list, ';' );
for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
r = msi_apply_patch_package( package, patches[i] );
msi_free( patches );
msi_free( patch_list );
return r;
}
static UINT msi_apply_transforms( MSIPACKAGE *package )
{
static const WCHAR szTransforms[] = {
'T','R','A','N','S','F','O','R','M','S',0 };
LPWSTR xform_list, *xforms;
UINT i, r = ERROR_SUCCESS;
xform_list = msi_dup_property( package, szTransforms );
xforms = msi_split_string( xform_list, ';' );
for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
{
if (xforms[i][0] == ':')
r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
else
r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
}
msi_free( xforms );
msi_free( xform_list );
return r;
}
/****************************************************
* TOP level entry points
*****************************************************/
UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
LPCWSTR szCommandLine )
{
UINT rc;
BOOL ui = FALSE;
static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
MSI_SetPropertyW(package, szAction, szInstall);
package->script = msi_alloc_zero(sizeof(MSISCRIPT));
package->script->InWhatSequence = SEQUENCE_INSTALL;
if (szPackagePath)
{
LPWSTR p, check, path;
path = strdupW(szPackagePath);
p = strrchrW(path,'\\');
if (p)
{
p++;
*p=0;
}
else
{
msi_free(path);
path = msi_alloc(MAX_PATH*sizeof(WCHAR));
GetCurrentDirectoryW(MAX_PATH,path);
strcatW(path,cszbs);
}
check = msi_dup_property( package, cszSourceDir );
if (!check)
MSI_SetPropertyW(package, cszSourceDir, path);
msi_free(check);
check = msi_dup_property( package, cszSOURCEDIR );
if (!check)
MSI_SetPropertyW(package, cszSOURCEDIR, path);
msi_free( package->PackagePath );
package->PackagePath = path;
msi_free(check);
}
msi_parse_command_line( package, szCommandLine );
msi_apply_transforms( package );
msi_apply_patches( package );
if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
{
package->script->InWhatSequence |= SEQUENCE_UI;
rc = ACTION_ProcessUISequence(package);
ui = TRUE;
if (rc == ERROR_SUCCESS)
{
package->script->InWhatSequence |= SEQUENCE_EXEC;
rc = ACTION_ProcessExecSequence(package,TRUE);
}
}
else
rc = ACTION_ProcessExecSequence(package,FALSE);
if (rc == -1)
{
/* install was halted but should be considered a success */
rc = ERROR_SUCCESS;
}
package->script->CurrentlyScripting= FALSE;
/* process the ending type action */
if (rc == ERROR_SUCCESS)
ACTION_PerformActionSequence(package,-1,ui);
else if (rc == ERROR_INSTALL_USEREXIT)
ACTION_PerformActionSequence(package,-2,ui);
else if (rc == ERROR_INSTALL_SUSPEND)
ACTION_PerformActionSequence(package,-4,ui);
else /* failed */
ACTION_PerformActionSequence(package,-3,ui);
/* finish up running custom actions */
ACTION_FinishCustomActions(package);
return rc;
}
static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
{
UINT rc = ERROR_SUCCESS;
MSIRECORD * row = 0;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
'`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
static const WCHAR UISeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
'`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
' ', '=',' ','%','i',0};
if (UI)
row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
else
row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
if (row)
{
LPCWSTR action, cond;
TRACE("Running the actions\n");
/* check conditions */
cond = MSI_RecordGetString(row,2);
/* this is a hack to skip errors in the condition code */
if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
goto end;
action = MSI_RecordGetString(row,1);
if (!action)
{
ERR("failed to fetch action\n");
rc = ERROR_FUNCTION_FAILED;
goto end;
}
if (UI)
rc = ACTION_PerformUIAction(package,action);
else
rc = ACTION_PerformAction(package,action,FALSE);
end:
msiobj_release(&row->hdr);
}
else
rc = ERROR_SUCCESS;
return rc;
}
typedef struct {
MSIPACKAGE* package;
BOOL UI;
} iterate_action_param;
static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
{
iterate_action_param *iap= (iterate_action_param*)param;
UINT rc;
LPCWSTR cond, action;
action = MSI_RecordGetString(row,1);
if (!action)
{
ERR("Error is retrieving action name\n");
return ERROR_FUNCTION_FAILED;
}
/* check conditions */
cond = MSI_RecordGetString(row,2);
/* this is a hack to skip errors in the condition code */
if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
{
TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
return ERROR_SUCCESS;
}
if (iap->UI)
rc = ACTION_PerformUIAction(iap->package,action);
else
rc = ACTION_PerformAction(iap->package,action,FALSE);
msi_dialog_check_messages( NULL );
if (iap->package->CurrentInstallState != ERROR_SUCCESS )
rc = iap->package->CurrentInstallState;
if (rc == ERROR_FUNCTION_NOT_CALLED)
rc = ERROR_SUCCESS;
if (rc != ERROR_SUCCESS)
ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
return rc;
}
UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
{
MSIQUERY * view;
UINT r;
static const WCHAR query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','%','s','`',
' ','W','H','E','R','E',' ',
'`','S','e','q','u','e','n','c','e','`',' ',
'>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
'`','S','e','q','u','e','n','c','e','`',0};
iterate_action_param iap;
/*
* FIXME: probably should be checking UILevel in the
* ACTION_PerformUIAction/ACTION_PerformAction
* rather than saving the UI level here. Those
* two functions can be merged too.
*/
iap.package = package;
iap.UI = TRUE;
TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
r = MSI_OpenQuery( package->db, &view, query, szTable );
if (r == ERROR_SUCCESS)
{
r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
msiobj_release(&view->hdr);
}
return r;
}
static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
{
MSIQUERY * view;
UINT rc;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -