+
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script, BOOL force)
+{
+ UINT rc = ERROR_SUCCESS;
+ BOOL handled;
+
+ TRACE("Performing action (%s)\n", debugstr_w(action));
+
+ handled = ACTION_HandleStandardAction(package, action, &rc, force);
+
+ if (!handled)
+ handled = ACTION_HandleCustomAction(package, action, &rc, script, force);
+
+ if (!handled)
+ {
+ WARN("unhandled msi action %s\n", debugstr_w(action));
+ rc = ERROR_FUNCTION_NOT_CALLED;
+ }
+
+ return rc;
+}
+
+UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
+{
+ UINT rc = ERROR_SUCCESS;
+ BOOL handled = FALSE;
+
+ TRACE("Performing action (%s)\n", debugstr_w(action));
+
+ handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
+
+ if (!handled)
+ handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
+
+ if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
+ handled = TRUE;
+
+ if (!handled)
+ {
+ WARN("unhandled msi action %s\n", debugstr_w(action));
+ rc = ERROR_FUNCTION_NOT_CALLED;
+ }
+
+ return rc;
+}
+
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIRECORD *row;
+
+ 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 (needs_ui_sequence(package))
+ 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)
+ {
+ msiobj_release(&row->hdr);
+ return ERROR_SUCCESS;
+ }
+
+ action = MSI_RecordGetString(row, 1);
+ if (!action)
+ {
+ ERR("failed to fetch action\n");
+ msiobj_release(&row->hdr);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ if (needs_ui_sequence(package))
+ rc = ACTION_PerformUIAction(package, action, -1);
+ else
+ rc = ACTION_PerformAction(package, action, -1, FALSE);
+
+ msiobj_release(&row->hdr);
+ }
+
+ return rc;
+}
+
+/****************************************************
+ * TOP level entry points
+ *****************************************************/
+
+UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
+ LPCWSTR szCommandLine )
+{
+ UINT rc;
+ BOOL ui_exists;
+
+ 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->InWhatSequence = SEQUENCE_INSTALL;
+
+ if (szPackagePath)
+ {
+ LPWSTR p, dir;
+ LPCWSTR file;
+
+ dir = strdupW(szPackagePath);
+ p = strrchrW(dir, '\\');
+ if (p)
+ {
+ *(++p) = 0;
+ file = szPackagePath + (p - dir);
+ }
+ else
+ {
+ msi_free(dir);
+ dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
+ GetCurrentDirectoryW(MAX_PATH, dir);
+ lstrcatW(dir, szBackSlash);
+ file = szPackagePath;
+ }
+
+ msi_free( package->PackagePath );
+ package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
+ if (!package->PackagePath)
+ {
+ msi_free(dir);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ lstrcpyW(package->PackagePath, dir);
+ lstrcatW(package->PackagePath, file);
+ msi_free(dir);
+
+ msi_set_sourcedir_props(package, FALSE);
+ }
+
+ msi_parse_command_line( package, szCommandLine, FALSE );
+
+ msi_apply_transforms( package );
+ msi_apply_patches( package );
+
+ if (!szCommandLine && msi_get_property_int( package, szInstalled, 0 ))
+ {
+ TRACE("setting reinstall property\n");
+ MSI_SetPropertyW( package, szReinstall, szAll );
+ }
+
+ /* properties may have been added by a transform */
+ msi_clone_properties( package );
+ msi_set_context( package );
+
+ if (needs_ui_sequence( package))
+ {
+ package->script->InWhatSequence |= SEQUENCE_UI;
+ rc = ACTION_ProcessUISequence(package);
+ ui_exists = ui_sequence_exists(package);
+ if (rc == ERROR_SUCCESS || !ui_exists)
+ {
+ package->script->InWhatSequence |= SEQUENCE_EXEC;
+ rc = ACTION_ProcessExecSequence(package, ui_exists);
+ }
+ }
+ else
+ rc = ACTION_ProcessExecSequence(package, FALSE);
+
+ package->script->CurrentlyScripting = FALSE;
+
+ /* process the ending type action */
+ if (rc == ERROR_SUCCESS)
+ ACTION_PerformActionSequence(package, -1);
+ else if (rc == ERROR_INSTALL_USEREXIT)
+ ACTION_PerformActionSequence(package, -2);
+ else if (rc == ERROR_INSTALL_SUSPEND)
+ ACTION_PerformActionSequence(package, -4);
+ else /* failed */
+ ACTION_PerformActionSequence(package, -3);
+
+ /* finish up running custom actions */
+ ACTION_FinishCustomActions(package);
+
+ if (rc == ERROR_SUCCESS && package->need_reboot)
+ return ERROR_SUCCESS_REBOOT_REQUIRED;
+
+ return rc;
+}