public void Execute() { var directories = this.Section.Symbols.OfType <DirectorySymbol>().ToList(); var directoryIds = new SortedSet <string>(directories.Select(d => d.Id.Id)); foreach (var directory in directories) { var parentDirectoryId = directory.ParentDirectoryRef; if (String.IsNullOrEmpty(parentDirectoryId)) { if (directory.Id.Id != "TARGETDIR") { directory.ParentDirectoryRef = "TARGETDIR"; } } else { this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, directory.SourceLineNumbers); } } if (!directoryIds.Contains("TARGETDIR") && WindowsInstallerStandard.TryGetStandardDirectory("TARGETDIR", out var targetDir)) { directoryIds.Add(targetDir.Id.Id); this.Section.AddSymbol(targetDir); } }
/// <summary> /// Adds the PatchFiles action to the sequence table if it does not already exist. /// </summary> /// <param name="table">The sequence table to check or modify.</param> /// <param name="mainTransform">The primary authoring transform.</param> /// <param name="pairedTransform">The secondary patch transform.</param> /// <param name="mainFileRow">The file row that contains information about the patched file.</param> private void AddPatchFilesActionToSequenceTable(SequenceTable table, Output mainTransform, Output pairedTransform, Row mainFileRow) { // Find/add PatchFiles action (also determine sequence for it). // Search mainTransform first, then pairedTransform (pairedTransform overrides). bool hasPatchFilesAction = false; int seqInstallFiles = 0; int seqDuplicateFiles = 0; string tableName = table.ToString(); TestSequenceTableForPatchFilesAction( mainTransform.Tables[tableName], ref hasPatchFilesAction, ref seqInstallFiles, ref seqDuplicateFiles); TestSequenceTableForPatchFilesAction( pairedTransform.Tables[tableName], ref hasPatchFilesAction, ref seqInstallFiles, ref seqDuplicateFiles); if (!hasPatchFilesAction) { Table iesTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]); if (0 == iesTable.Rows.Count) { iesTable.Operation = TableOperation.Add; } Row patchAction = iesTable.CreateRow(null); WixActionRow wixPatchAction = WindowsInstallerStandard.GetStandardActions()[table, "PatchFiles"]; int sequence = wixPatchAction.Sequence; // Test for default sequence value's appropriateness if (seqInstallFiles >= sequence || (0 != seqDuplicateFiles && seqDuplicateFiles <= sequence)) { if (0 != seqDuplicateFiles) { if (seqDuplicateFiles < seqInstallFiles) { throw new WixException(WixErrors.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, iesTable.Name, "InstallFiles", "DuplicateFiles", wixPatchAction.Action)); } else { sequence = (seqDuplicateFiles + seqInstallFiles) / 2; if (seqInstallFiles == sequence || seqDuplicateFiles == sequence) { throw new WixException(WixErrors.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, iesTable.Name, "InstallFiles", "DuplicateFiles", wixPatchAction.Action)); } } } else { sequence = seqInstallFiles + 1; } } patchAction[0] = wixPatchAction.Action; patchAction[1] = wixPatchAction.Condition; patchAction[2] = sequence; patchAction.Operation = RowOperation.Add; } }
public SequenceActionsCommand(IntermediateSection section) { this.Section = section; this.RelativeActionsForActions = new Dictionary <string, RelativeActions>(); this.StandardActionsById = WindowsInstallerStandard.StandardActions().ToDictionary(a => a.Id.Id); }
/// <summary> /// Instantiates a standard ActionRow. /// </summary> /// <param name="sequenceTable">The sequence table of the standard action.</param> /// <param name="action">The name of the standard action.</param> /// <param name="condition">The condition of the standard action.</param> /// <param name="sequence">The suggested sequence number of the standard action.</param> private WixActionRow(SequenceTable sequenceTable, string action, string condition, int sequence) : base(null, WindowsInstallerStandard.GetTableDefinitions()["WixAction"]) { this.SequenceTable = sequenceTable; this.Action = action; this.Condition = condition; this.Sequence = sequence; this.Overridable = true; // all standard actions are overridable by default }
private IEnumerable <WixActionSymbol> GetActions(SequenceTable sequence, string[] actionNames) { foreach (var action in WindowsInstallerStandard.StandardActions()) { if (action.SequenceTable == sequence && actionNames.Contains(action.Action)) { yield return(action); } } }
/// <summary> /// Determines if the directory Id starts with a standard directory id. /// </summary> /// <param name="directoryId">The directory id.</param> /// <param name="standardDirectoryId">The standard directory id.</param> /// <returns>true if the directory starts with a standard directory id.</returns> private static bool StartsWithStandardDirectoryId(string directoryId, out string standardDirectoryId) { standardDirectoryId = null; foreach (string id in WindowsInstallerStandard.GetStandardDirectories()) { if (directoryId.StartsWith(id, StringComparison.Ordinal)) { standardDirectoryId = id; return(true); } } return(false); }
/// <summary> /// Get the source path of a directory. /// </summary> /// <param name="directories">All cached directories.</param> /// <param name="componentIdGenSeeds">Hash table of Component GUID generation seeds indexed by directory id.</param> /// <param name="directory">Directory identifier.</param> /// <param name="canonicalize">Canonicalize the path for standard directories.</param> /// <returns>Source path of a directory.</returns> internal static string GetDirectoryPath(Hashtable directories, Hashtable componentIdGenSeeds, string directory, bool canonicalize) { if (!directories.Contains(directory)) { throw new WixException(WixErrors.ExpectedDirectory(directory)); } ResolvedDirectory resolvedDirectory = (ResolvedDirectory)directories[directory]; if (null == resolvedDirectory.Path) { if (null != componentIdGenSeeds && componentIdGenSeeds.Contains(directory)) { resolvedDirectory.Path = (string)componentIdGenSeeds[directory]; } else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory)) { // when canonicalization is on, standard directories are treated equally resolvedDirectory.Path = directory; } else { string name = resolvedDirectory.Name; if (canonicalize && null != name) { name = name.ToLower(CultureInfo.InvariantCulture); } if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) { resolvedDirectory.Path = name; } else { string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize); if (null != resolvedDirectory.Name) { resolvedDirectory.Path = Path.Combine(parentPath, name); } else { resolvedDirectory.Path = parentPath; } } } } return(resolvedDirectory.Path); }
private Dictionary <string, WixActionSymbol> GetRequiredStandardActions() { var overridableActionSymbols = new Dictionary <string, WixActionSymbol>(); var requiredActionIds = this.GetRequiredActionIds(); foreach (var actionId in requiredActionIds) { WindowsInstallerStandard.TryGetStandardAction(actionId, out var standardAction); overridableActionSymbols.Add(standardAction.Id.Id, standardAction); } return(overridableActionSymbols); }
/// <summary> /// Get the source path of a directory. /// </summary> /// <param name="directories">All cached directories.</param> /// <param name="componentIdGenSeeds">Hash table of Component GUID generation seeds indexed by directory id.</param> /// <param name="directory">Directory identifier.</param> /// <param name="canonicalize">Canonicalize the path for standard directories.</param> /// <returns>Source path of a directory.</returns> public static string GetDirectoryPath(Dictionary <string, ResolvedDirectory> directories, Dictionary <string, string> componentIdGenSeeds, string directory, bool canonicalize) { if (!directories.TryGetValue(directory, out var resolvedDirectory)) { throw new WixException(ErrorMessages.ExpectedDirectory(directory)); } if (null == resolvedDirectory.Path) { if (null != componentIdGenSeeds && componentIdGenSeeds.ContainsKey(directory)) { resolvedDirectory.Path = (string)componentIdGenSeeds[directory]; } else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory)) { // when canonicalization is on, standard directories are treated equally resolvedDirectory.Path = directory; } else { string name = resolvedDirectory.Name; if (canonicalize) { name = name?.ToLowerInvariant(); } if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) { resolvedDirectory.Path = name; } else { string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize); if (null != resolvedDirectory.Name) { resolvedDirectory.Path = Path.Combine(parentPath, name); } else { resolvedDirectory.Path = parentPath; } } } } return(resolvedDirectory.Path); }
private string GetStandardDirectoryParent(string directoryId) { switch (directoryId) { case "TARGETDIR": return(null); case "CommonFiles6432Folder": case "ProgramFiles6432Folder": case "System6432Folder": return(WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, this.Platform)); default: return("TARGETDIR"); } }
/// <summary> /// Get the action symbol that is the parent of the given action symbol. /// </summary> /// <param name="actionSymbol">The given action symbol.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <returns>Null if there is no parent. Used for loop termination.</returns> private WixActionSymbol GetParentActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols) { if (null == actionSymbol.Before && null == actionSymbol.After) { return(null); } var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + (actionSymbol.After ?? actionSymbol.Before); if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol); } return(parentActionSymbol); }
private void SchedulePropertyExeAction(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier name, string source, string cmdline, CustomActionSymbol caTemplate, string condition, string beforeAction, string afterAction) { const SequenceTable sequence = SequenceTable.InstallExecuteSequence; caTemplate.SourceType = CustomActionSourceType.Property; caTemplate.Source = source; caTemplate.TargetType = CustomActionTargetType.Exe; caTemplate.Target = cmdline; section.AddSymbol(caTemplate); section.AddSymbol(new WixActionSymbol(sourceLineNumbers, new Identifier(name.Access, sequence, name.Id)) { SequenceTable = SequenceTable.InstallExecuteSequence, Action = name.Id, Condition = condition, // no explicit sequence Before = beforeAction, After = afterAction, Overridable = false, }); if (null != beforeAction) { if (WindowsInstallerStandard.IsStandardAction(beforeAction)) { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), beforeAction); } else { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, beforeAction); } } if (null != afterAction) { if (WindowsInstallerStandard.IsStandardAction(afterAction)) { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), afterAction); } else { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, afterAction); } } }
private void SchedulePropertyExeAction(SourceLineNumber sourceLineNumbers, Identifier name, string source, string cmdline, int extraBits, string condition, string beforeAction, string afterAction) { const string sequence = "InstallExecuteSequence"; Row actionRow = this.Core.CreateRow(sourceLineNumbers, "CustomAction", name); actionRow[1] = VSCompiler.MsidbCustomActionTypeProperty | VSCompiler.MsidbCustomActionTypeExe | extraBits; actionRow[2] = source; actionRow[3] = cmdline; Row sequenceRow = this.Core.CreateRow(sourceLineNumbers, "WixAction"); sequenceRow[0] = sequence; sequenceRow[1] = name.Id; sequenceRow[2] = condition; // no explicit sequence sequenceRow[4] = beforeAction; sequenceRow[5] = afterAction; sequenceRow[6] = 0; // not overridable if (null != beforeAction) { if (WindowsInstallerStandard.IsStandardAction(beforeAction)) { this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, beforeAction); } else { this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); } } if (null != afterAction) { if (WindowsInstallerStandard.IsStandardAction(afterAction)) { this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, afterAction); } else { this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); } } }
private void SchedulePropertyExeAction(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier name, string source, string cmdline, int extraBits, string condition, string beforeAction, string afterAction) { const string sequence = "InstallExecuteSequence"; var actionRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "CustomAction", name); actionRow.Set(1, VSCompiler.MsidbCustomActionTypeProperty | VSCompiler.MsidbCustomActionTypeExe | extraBits); actionRow.Set(2, source); actionRow.Set(3, cmdline); var sequenceRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixAction", new Identifier(name.Access, sequence, name.Id)); sequenceRow.Set(0, sequence); sequenceRow.Set(1, name.Id); sequenceRow.Set(2, condition); // no explicit sequence sequenceRow.Set(4, beforeAction); sequenceRow.Set(5, afterAction); sequenceRow.Set(6, 0); // not overridable if (null != beforeAction) { if (WindowsInstallerStandard.IsStandardAction(beforeAction)) { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixAction", sequence, beforeAction); } else { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", beforeAction); } } if (null != afterAction) { if (WindowsInstallerStandard.IsStandardAction(afterAction)) { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixAction", sequence, afterAction); } else { this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", afterAction); } } }
public string GetCanonicalDirectoryPath(Dictionary <string, IResolvedDirectory> directories, Dictionary <string, string> componentIdGenSeeds, string directory, Platform platform) { if (!directories.TryGetValue(directory, out var resolvedDirectory)) { throw new WixException(ErrorMessages.ExpectedDirectory(directory)); } if (null == resolvedDirectory.Path) { if (null != componentIdGenSeeds && componentIdGenSeeds.ContainsKey(directory)) { resolvedDirectory.Path = componentIdGenSeeds[directory]; } else if (WindowsInstallerStandard.IsStandardDirectory(directory)) { resolvedDirectory.Path = WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directory, platform); } else { var name = resolvedDirectory.Name?.ToLowerInvariant(); if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) { resolvedDirectory.Path = name; } else { var parentPath = this.GetCanonicalDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, platform); if (null != resolvedDirectory.Name) { resolvedDirectory.Path = Path.Combine(parentPath, name); } else { resolvedDirectory.Path = parentPath; } } } } return(resolvedDirectory.Path); }
/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionSymbol">The action symbol to be sequenced.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> private void SequenceActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols) { var after = false; if (actionSymbol.After != null) { after = true; } else if (actionSymbol.Before == null) { throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set."); } var parentActionName = (after ? actionSymbol.After : actionSymbol.Before); var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionSymbol = parentActionSymbol.Clone(); requiredActionSymbols.Add(parentActionSymbol.Id.Id, parentActionSymbol); } else { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Found an action with a non-existent {0} action: {1}.", (after ? "After" : "Before"), parentActionName)); } } else if (actionSymbol == parentActionSymbol || this.ContainsChildActionSymbol(actionSymbol, parentActionSymbol)) // cycle detected { throw new WixException(ErrorMessages.ActionCircularDependency(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, parentActionSymbol.Action)); } // Add this action to the appropriate list of dependent action symbols. var relativeActions = this.GetRelativeActions(parentActionSymbol); var relatedSymbols = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedSymbols.Add(actionSymbol); }
private void EnsureStandardDirectoryAdded(ISet <string> directoryIds, string directoryId, SourceLineNumber sourceLineNumbers) { if (!directoryIds.Contains(directoryId) && WindowsInstallerStandard.TryGetStandardDirectory(directoryId, out var standardDirectory)) { var parentDirectoryId = this.GetStandardDirectoryParent(directoryId); var directory = new DirectorySymbol(sourceLineNumbers, standardDirectory.Id) { Name = standardDirectory.Name, ParentDirectoryRef = parentDirectoryId, }; directoryIds.Add(directory.Id.Id); this.Section.AddSymbol(directory); if (!String.IsNullOrEmpty(parentDirectoryId)) { this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, sourceLineNumbers); } } }
/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionSymbol">The action symbol to be sequenced.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <param name="firstReference">A dictionary used for detecting cyclic references among action symbols.</param> private void SequenceActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols, Dictionary <WixActionSymbol, WixActionSymbol> firstReference) { var after = false; if (actionSymbol.After != null) { after = true; } else if (actionSymbol.Before == null) { throw new WixException($"Found action '{actionSymbol.Id.Id}' at {actionSymbol.SourceLineNumbers}' with no Sequence, Before, or After column set. The compiler should have prevented this."); } var parentActionName = (after ? actionSymbol.After : actionSymbol.Before); var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionSymbol = parentActionSymbol.Clone(); requiredActionSymbols.Add(parentActionSymbol.Id.Id, parentActionSymbol); } else { throw new WixException($"Found action {actionSymbol.Id.Id} with a non-existent {(after ? "After" : "Before")} action '{parentActionName}'. The linker should have prevented this."); } } this.CheckForCircularActionReference(actionSymbol, requiredActionSymbols, firstReference); // Add this action to the appropriate list of dependent action symbols. var relativeActions = this.GetRelativeActions(parentActionSymbol); var relatedSymbols = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedSymbols.Add(actionSymbol); }
public WixActionSymbol ScheduleActionSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, AccessModifier access, SequenceTable sequence, string actionName, string condition, string beforeAction, string afterAction, bool overridable = false) { var actionId = new Identifier(access, sequence, actionName); var actionSymbol = section.AddSymbol(new WixActionSymbol(sourceLineNumbers, actionId) { SequenceTable = sequence, Action = actionName, Condition = condition, Before = beforeAction, After = afterAction, Overridable = overridable, }); if (null != beforeAction) { if (WindowsInstallerStandard.IsStandardAction(beforeAction)) { this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), beforeAction); } else { this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, beforeAction); } } if (null != afterAction) { if (WindowsInstallerStandard.IsStandardAction(afterAction)) { this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), afterAction); } else { this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, afterAction); } } return(actionSymbol); }
public int Execute() { var intermediates = this.CompilePhase(); var tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); if (this.OutputType == OutputType.Library) { this.LibraryPhase(intermediates, tableDefinitions); } else { var output = this.LinkPhase(intermediates, tableDefinitions); if (!Messaging.Instance.EncounteredError) { this.BindPhase(output, tableDefinitions); } } return(Messaging.Instance.LastErrorNumber); }
/// <summary> /// Instantiate a new Librarian class. /// </summary> public Librarian() { this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); }
/// <summary> /// Adds the PatchFiles action to the sequence table if it does not already exist. /// </summary> /// <param name="table">The sequence table to check or modify.</param> /// <param name="mainTransform">The primary authoring transform.</param> /// <param name="pairedTransform">The secondary patch transform.</param> /// <param name="mainFileRow">The file row that contains information about the patched file.</param> private void AddPatchFilesActionToSequenceTable(SequenceTable table, WindowsInstallerData mainTransform, WindowsInstallerData pairedTransform, Row mainFileRow) { var tableName = table.ToString(); // Find/add PatchFiles action (also determine sequence for it). // Search mainTransform first, then pairedTransform (pairedTransform overrides). var hasPatchFilesAction = false; var installFilesSequence = 0; var duplicateFilesSequence = 0; TestSequenceTableForPatchFilesAction( mainTransform.Tables[tableName], ref hasPatchFilesAction, ref installFilesSequence, ref duplicateFilesSequence); TestSequenceTableForPatchFilesAction( pairedTransform.Tables[tableName], ref hasPatchFilesAction, ref installFilesSequence, ref duplicateFilesSequence); if (!hasPatchFilesAction) { WindowsInstallerStandard.TryGetStandardAction(tableName, "PatchFiles", out var patchFilesActionSymbol); var sequence = patchFilesActionSymbol.Sequence; // Test for default sequence value's appropriateness if (installFilesSequence >= sequence || (0 != duplicateFilesSequence && duplicateFilesSequence <= sequence)) { if (0 != duplicateFilesSequence) { if (duplicateFilesSequence < installFilesSequence) { throw new WixException(ErrorMessages.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action)); } else { sequence = (duplicateFilesSequence + installFilesSequence) / 2; if (installFilesSequence == sequence || duplicateFilesSequence == sequence) { throw new WixException(ErrorMessages.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionSymbol.Action)); } } } else { sequence = installFilesSequence + 1; } } var sequenceTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]); if (0 == sequenceTable.Rows.Count) { sequenceTable.Operation = TableOperation.Add; } var patchAction = sequenceTable.CreateRow(null); patchAction[0] = patchFilesActionSymbol.Action; patchAction[1] = patchFilesActionSymbol.Condition; patchAction[2] = sequence; patchAction.Operation = RowOperation.Add; } }
public Inscriber() { this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); }
public void Execute() { var requiredActionSymbols = new Dictionary <string, WixActionSymbol>(); // Get the standard actions required based on symbols in the section. var overridableActionSymbols = this.GetRequiredStandardActions(); // Index all the action symbols and look for collisions. foreach (var actionSymbol in this.Section.Symbols.OfType <WixActionSymbol>()) { if (actionSymbol.Overridable) // overridable action { if (overridableActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) { this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); if (null != collidingActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionSymbol.SourceLineNumbers)); } } else { overridableActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } else // unsequenced or sequenced action. { // Unsequenced action (allowed for certain standard actions). if (null == actionSymbol.Before && null == actionSymbol.After && !actionSymbol.Sequence.HasValue) { if (WindowsInstallerStandard.TryGetStandardAction(actionSymbol.Id.Id, out var standardAction)) { // Populate the sequence from the standard action actionSymbol.Sequence = standardAction.Sequence; } else // not a supported unscheduled action. { throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set."); } } if (requiredActionSymbols.TryGetValue(actionSymbol.Id.Id, out var collidingActionSymbol)) { this.Messaging.Write(ErrorMessages.ActionCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); if (null != collidingActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.ActionCollision2(collidingActionSymbol.SourceLineNumbers)); } } else { requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } } // Add the overridable action symbols that are not overridden to the required action symbols. foreach (var actionSymbol in overridableActionSymbols.Values) { if (!requiredActionSymbols.ContainsKey(actionSymbol.Id.Id)) { requiredActionSymbols.Add(actionSymbol.Id.Id, actionSymbol); } } // Suppress the required actions that are overridable. foreach (var suppressActionSymbol in this.Section.Symbols.OfType <WixSuppressActionSymbol>()) { var key = suppressActionSymbol.Id.Id; // If there is an overridable symbol to suppress; suppress it. There is no warning if there // is no action to suppress because the action may be suppressed from a merge module in // the binder. if (requiredActionSymbols.TryGetValue(key, out var requiredActionSymbol)) { if (requiredActionSymbol.Overridable) { this.Messaging.Write(WarningMessages.SuppressAction(suppressActionSymbol.SourceLineNumbers, suppressActionSymbol.Action, suppressActionSymbol.SequenceTable.ToString())); if (null != requiredActionSymbol.SourceLineNumbers) { this.Messaging.Write(WarningMessages.SuppressAction2(requiredActionSymbol.SourceLineNumbers)); } requiredActionSymbols.Remove(key); } else // suppressing a non-overridable action symbol { this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction(suppressActionSymbol.SourceLineNumbers, suppressActionSymbol.SequenceTable.ToString(), suppressActionSymbol.Action)); if (null != requiredActionSymbol.SourceLineNumbers) { this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction2(requiredActionSymbol.SourceLineNumbers)); } } } } // Build up dependency trees of the relatively scheduled actions. // Use ToList() to create a copy of the required action symbols so that new symbols can // be added while enumerating. foreach (var actionSymbol in requiredActionSymbols.Values.ToList()) { if (!actionSymbol.Sequence.HasValue) { // check for standard actions that don't have a sequence number in a merge module if (SectionType.Module == this.Section.Type && WindowsInstallerStandard.IsStandardAction(actionSymbol.Action)) { this.Messaging.Write(ErrorMessages.StandardActionRelativelyScheduledInModule(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); } this.SequenceActionSymbol(actionSymbol, requiredActionSymbols); } else if (SectionType.Module == this.Section.Type && 0 < actionSymbol.Sequence && !WindowsInstallerStandard.IsStandardAction(actionSymbol.Action)) // check for custom actions and dialogs that have a sequence number { this.Messaging.Write(ErrorMessages.CustomActionSequencedInModule(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action)); } } // Look for standard actions with sequence restrictions that aren't necessarily scheduled based // on the presence of a particular table. if (requiredActionSymbols.ContainsKey("InstallExecuteSequence/DuplicateFiles") && !requiredActionSymbols.ContainsKey("InstallExecuteSequence/InstallFiles")) { WindowsInstallerStandard.TryGetStandardAction("InstallExecuteSequence/InstallFiles", out var standardAction); requiredActionSymbols.Add(standardAction.Id.Id, standardAction); } // Schedule actions. List <WixActionSymbol> scheduledActionSymbols; if (SectionType.Module == this.Section.Type) { scheduledActionSymbols = requiredActionSymbols.Values.ToList(); } else { scheduledActionSymbols = this.ScheduleActions(requiredActionSymbols); } // Remove all existing WixActionSymbols from the section then add the // scheduled actions back to the section. Note: we add the indices in // reverse order to make it easy to remove them from the list later. var removeIndices = new List <int>(); for (var i = this.Section.Symbols.Count - 1; i >= 0; --i) { var symbol = this.Section.Symbols[i]; if (symbol.Definition.Type == SymbolDefinitionType.WixAction) { removeIndices.Add(i); } } foreach (var removeIndex in removeIndices) { this.Section.Symbols.RemoveAt(removeIndex); } foreach (var action in scheduledActionSymbols) { this.Section.AddSymbol(action); } }
/// <summary> /// Constructor for binder core. /// </summary> internal BinderCore() { this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); }
private string ModularizedRowFieldValue(Row row, Field field) { var fieldData = field.AsString(); if (!(WindowsInstallerStandard.IsStandardAction(fieldData) || WindowsInstallerStandard.IsStandardProperty(fieldData))) { var modularizeType = field.Column.ModularizeType; // special logic for the ControlEvent table's Argument column // this column requires different modularization methods depending upon the value of the Event column if (ColumnModularizeType.ControlEventArgument == field.Column.ModularizeType) { switch (row[2].ToString()) { case "CheckExistingTargetPath": // redirectable property name case "CheckTargetPath": case "DoAction": // custom action name case "NewDialog": // dialog name case "SelectionBrowse": case "SetTargetPath": case "SpawnDialog": case "SpawnWaitDialog": if (Common.IsIdentifier(fieldData)) { modularizeType = ColumnModularizeType.Column; } else { modularizeType = ColumnModularizeType.Property; } break; default: // formatted modularizeType = ColumnModularizeType.Property; break; } } else if (ColumnModularizeType.ControlText == field.Column.ModularizeType) { // icons are stored in the Binary table, so they get column-type modularization if (("Bitmap" == row[2].ToString() || "Icon" == row[2].ToString()) && Common.IsIdentifier(fieldData)) { modularizeType = ColumnModularizeType.Column; } else { modularizeType = ColumnModularizeType.Property; } } switch (modularizeType) { case ColumnModularizeType.Column: // ensure the value is an identifier (otherwise it shouldn't be modularized this way) if (!Common.IsIdentifier(fieldData)) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixDataStrings.EXP_CannotModularizeIllegalID, fieldData)); } // if we're not supposed to suppress modularization of this identifier if (!this.SuppressModularizationIdentifiers.Contains(fieldData)) { fieldData = String.Concat(fieldData, ".", this.ModularizationGuid); } break; case ColumnModularizeType.Property: case ColumnModularizeType.Condition: Regex regex; if (ColumnModularizeType.Property == modularizeType) { regex = new Regex(@"\[(?<identifier>[#$!]?[a-zA-Z_][a-zA-Z0-9_\.]*)]", RegexOptions.Singleline | RegexOptions.ExplicitCapture); } else { Debug.Assert(ColumnModularizeType.Condition == modularizeType); // This heinous looking regular expression is actually quite an elegant way // to shred the entire condition into the identifiers that need to be // modularized. Let's break it down piece by piece: // // 1. Look for the operators: NOT, EQV, XOR, OR, AND, IMP (plus a space). Note that the // regular expression is case insensitive so we don't have to worry about // all the permutations of these strings. // 2. Look for quoted strings. Quoted strings are just text and are ignored // outright. // 3. Look for environment variables. These look like identifiers we might // otherwise be interested in but start with a percent sign. Like quoted // strings these enviroment variable references are ignored outright. // 4. Match all identifiers that are things that need to be modularized. Note // the special characters (!, $, ?, &) that denote Component and Feature states. regex = new Regex(@"NOT\s|EQV\s|XOR\s|OR\s|AND\s|IMP\s|"".*?""|%[a-zA-Z_][a-zA-Z0-9_\.]*|(?<identifier>[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); // less performant version of the above with captures showing where everything lives // regex = new Regex(@"(?<operator>NOT|EQV|XOR|OR|AND|IMP)|(?<string>"".*?"")|(?<environment>%[a-zA-Z_][a-zA-Z0-9_\.]*)|(?<identifier>[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)",RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture); } var matches = regex.Matches(fieldData); var sb = new StringBuilder(fieldData); // Notice how this code walks backward through the list // because it modifies the string as we through it. for (var i = matches.Count - 1; 0 <= i; i--) { var group = matches[i].Groups["identifier"]; if (group.Success) { var identifier = group.Value; if (!WindowsInstallerStandard.IsStandardProperty(identifier) && !this.SuppressModularizationIdentifiers.Contains(identifier)) { sb.Insert(group.Index + group.Length, '.'); sb.Insert(group.Index + group.Length + 1, this.ModularizationGuid); } } } fieldData = sb.ToString(); break; case ColumnModularizeType.CompanionFile: // if we're not supposed to ignore this identifier and the value does not start with // a digit, we must have a companion file so modularize it if (!this.SuppressModularizationIdentifiers.Contains(fieldData) && 0 < fieldData.Length && !Char.IsDigit(fieldData, 0)) { fieldData = String.Concat(fieldData, ".", this.ModularizationGuid); } break; case ColumnModularizeType.Icon: if (!this.SuppressModularizationIdentifiers.Contains(fieldData)) { var start = fieldData.LastIndexOf(".", StringComparison.Ordinal); if (-1 == start) { fieldData = String.Concat(fieldData, ".", this.ModularizationGuid); } else { fieldData = String.Concat(fieldData.Substring(0, start), ".", this.ModularizationGuid, fieldData.Substring(start)); } } break; case ColumnModularizeType.SemicolonDelimited: var keys = fieldData.Split(';'); for (var i = 0; i < keys.Length; ++i) { if (!String.IsNullOrEmpty(keys[i])) { keys[i] = String.Concat(keys[i], ".", this.ModularizationGuid); } } fieldData = String.Join(";", keys); break; } } return(fieldData); }