/// <summary> /// Creates a PayloadInfoRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this Media row belongs to and should get its column definitions from.</param> public PayloadInfoRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Unbind an MSI database file. /// </summary> /// <param name="databaseFile">The database file.</param> /// <param name="database">The opened database.</param> /// <param name="outputType">The type of output to create.</param> /// <param name="exportBasePath">The path where files should be exported.</param> /// <param name="skipSummaryInfo">Option to skip unbinding the _SummaryInformation table.</param> /// <returns>The output representing the database.</returns> private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath, bool skipSummaryInfo) { string modularizationGuid = null; Output output = new Output(SourceLineNumberCollection.FromFileName(databaseFile)); View validationView = null; // set the output type output.Type = outputType; // get the codepage database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt"); using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt"))) { string line; while (null != (line = sr.ReadLine())) { string[] data = line.Split('\t'); if (2 == data.Length) { output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); } } } // get the summary information table if it exists; it won't if unbinding a transform if (!skipSummaryInfo) { using (SummaryInformation summaryInformation = new SummaryInformation(database)) { Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]); for (int i = 1; 19 >= i; i++) { string value = summaryInformation.GetProperty(i); if (0 < value.Length) { Row row = table.CreateRow(output.SourceLineNumbers); row[0] = i; row[1] = value; } } output.Tables.Add(table); } } try { // open a view on the validation table if it exists if (database.TableExists("_Validation")) { validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?"); } // get the normal tables using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables")) { while (true) { using (Record tableRecord = tablesView.Fetch()) { if (null == tableRecord) { break; } string tableName = tableRecord.GetString(1); using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) { TableDefinition tableDefinition = new TableDefinition(tableName, false, false); Hashtable tablePrimaryKeys = new Hashtable(); using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES), columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES)) { int columnCount = columnNameRecord.GetFieldCount(); // index the primary keys using (Record primaryKeysRecord = database.PrimaryKeys(tableName)) { int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount(); for (int i = 1; i <= primaryKeysFieldCount; i++) { tablePrimaryKeys[primaryKeysRecord.GetString(i)] = null; } } for (int i = 1; i <= columnCount; i++) { string columnName = columnNameRecord.GetString(i); string idtType = columnTypeRecord.GetString(i); ColumnType columnType; int length; bool nullable; ColumnCategory columnCategory = ColumnCategory.Unknown; ColumnModularizeType columnModularizeType = ColumnModularizeType.None; bool primary = tablePrimaryKeys.Contains(columnName); bool minValueSet = false; int minValue = -1; bool maxValueSet = false; int maxValue = -1; string keyTable = null; bool keyColumnSet = false; int keyColumn = -1; string category = null; string set = null; string description = null; // get the column type, length, and whether its nullable switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture)) { case 'i': columnType = ColumnType.Number; break; case 'l': columnType = ColumnType.Localized; break; case 's': columnType = ColumnType.String; break; case 'v': columnType = ColumnType.Object; break; default: // TODO: error columnType = ColumnType.Unknown; break; } length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); nullable = Char.IsUpper(idtType[0]); // try to get validation information if (null != validationView) { using (Record validationRecord = new Record(2)) { validationRecord.SetString(1, tableName); validationRecord.SetString(2, columnName); validationView.Execute(validationRecord); } using (Record validationRecord = validationView.Fetch()) { if (null != validationRecord) { string validationNullable = validationRecord.GetString(3); minValueSet = !validationRecord.IsNull(4); minValue = (minValueSet ? validationRecord.GetInteger(4) : -1); maxValueSet = !validationRecord.IsNull(5); maxValue = (maxValueSet ? validationRecord.GetInteger(5) : -1); keyTable = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null); keyColumnSet = !validationRecord.IsNull(7); keyColumn = (keyColumnSet ? validationRecord.GetInteger(7) : -1); category = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null); set = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null); description = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null); // check the validation nullable value against the column definition if (null == validationNullable) { // TODO: warn for illegal validation nullable column } else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable)) { // TODO: warn for mismatch between column definition and validation nullable } // convert category to ColumnCategory if (null != category) { try { columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true); } catch (ArgumentException) { columnCategory = ColumnCategory.Unknown; } } } else { // TODO: warn about no validation information } } } // guess the modularization type if ("Icon" == keyTable && 1 == keyColumn) { columnModularizeType = ColumnModularizeType.Icon; } else if ("Condition" == columnName) { columnModularizeType = ColumnModularizeType.Condition; } else if (ColumnCategory.Formatted == columnCategory || ColumnCategory.FormattedSDDLText == columnCategory) { columnModularizeType = ColumnModularizeType.Property; } else if (ColumnCategory.Identifier == columnCategory) { columnModularizeType = ColumnModularizeType.Column; } tableDefinition.Columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true)); } } // use our table definitions if core properties are the same; this allows us to take advantage // of wix concepts like localizable columns which current code assumes if (this.tableDefinitions.Contains(tableName) && 0 == tableDefinition.CompareTo(this.tableDefinitions[tableName])) { tableDefinition = this.tableDefinitions[tableName]; } Table table = new Table(null, tableDefinition); while (true) { using (Record rowRecord = tableView.Fetch()) { if (null == rowRecord) { break; } int recordCount = rowRecord.GetFieldCount(); Row row = table.CreateRow(output.SourceLineNumbers); for (int i = 0; recordCount > i && row.Fields.Length > i; i++) { if (rowRecord.IsNull(i + 1)) { if (!row.Fields[i].Column.IsNullable) { // TODO: display an error for a null value in a non-nullable field OR // display a warning and put an empty string in the value to let the compiler handle it // (the second option is risky because the later code may make certain assumptions about // the contents of a row value) } } else { switch (row.Fields[i].Column.Type) { case ColumnType.Number: bool success = false; int intValue = rowRecord.GetInteger(i + 1); if (row.Fields[i].Column.IsLocalizable) { success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); } else { success = row.BestEffortSetField(i, intValue); } if (!success) { this.OnMessage(WixWarnings.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); } break; case ColumnType.Object: string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; if (null != exportBasePath) { string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); sourceFile = Path.Combine(exportBasePath, relativeSourceFile); // ensure the parent directory exists System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName)); using (FileStream fs = System.IO.File.Create(sourceFile)) { int bytesRead; byte[] buffer = new byte[512]; while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } row[i] = sourceFile; break; default: string value = rowRecord.GetString(i + 1); switch (row.Fields[i].Column.Category) { case ColumnCategory.Guid: value = value.ToUpper(CultureInfo.InvariantCulture); break; } // de-modularize if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) { Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); if (null == modularizationGuid) { Match match = modularization.Match(value); if (match.Success) { modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); } } value = modularization.Replace(value, String.Empty); } // escape "$(" for the preprocessor value = value.Replace("$(", "$$("); // escape things that look like wix variables MatchCollection matches = Common.WixVariableRegex.Matches(value); for (int j = matches.Count - 1; 0 <= j; j--) { value = value.Insert(matches[j].Index, "!"); } row[i] = value; break; } } } } } output.Tables.Add(table); } } } } } finally { if (null != validationView) { validationView.Close(); } } // set the modularization guid as the PackageCode if (null != modularizationGuid) { Table table = output.Tables["_SummaryInformation"]; foreach (Row row in table.Rows) { if (9 == (int)row[0]) // PID_REVNUMBER { row[1] = modularizationGuid; } } } if (this.isAdminImage) { GenerateWixFileTable(databaseFile, output); GenerateSectionIds(output); } return output; }
/// <summary> /// Creates an ApprovedExeForElevation row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this ApprovedExeForElevation row belongs to and should get its column definitions from.</param> public WixApprovedExeForElevationRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a File row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDefinition">TableDefinition this Media row belongs to and should get its column definitions from.</param> public FileRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDefinition) : base(sourceLineNumbers, tableDefinition) { this.assemblyType = FileAssemblyType.NotAnAssembly; this.previousSource = new string[1]; this.previousSymbols = new string[1]; this.previousRetainOffsets = new string[1]; this.previousRetainLengths = new string[1]; this.previousIgnoreOffsets = new string[1]; this.previousIgnoreLengths = new string[1]; }
/// <summary> /// Creates a ChainMsiPackage row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this row belongs to and should get its column definitions from.</param> public ChainMsiPackageRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a shallow copy of a row from another row. /// </summary> /// <param name="source">The row the data is copied from.</param> protected Row(Row source) { this.table = source.table; this.tableDefinition = source.tableDefinition; this.rowNumber = source.rowNumber; this.operation = source.operation; this.sectionId = source.sectionId; this.sourceLineNumbers = source.sourceLineNumbers; this.fields = source.fields; this.symbol = source.symbol; }
/// <summary> /// Parses an odbc driver or translator element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="componentId">Identifier of parent component.</param> /// <param name="fileId">Default identifer for driver/translator file.</param> /// <param name="table">Table we're processing for.</param> private void ParseODBCDriverOrTranslator(XmlNode node, string componentId, string fileId, TableDefinition table) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string driver = fileId; string name = null; string setup = fileId; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "File": driver = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "File", driver); break; case "Name": name = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "SetupFile": setup = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "File", setup); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (null == name) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Name")); } // drivers have a few possible children if ("ODBCDriver" == table.Name) { // process any data sources for the driver foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "ODBCDataSource": string ignoredKeyPath = null; this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath); break; case "Property": this.ParseODBCProperty(child, id, "ODBCAttribute"); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } } else { foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.core.UnexpectedElement(node, child); } else { this.core.UnsupportedExtensionElement(node, child); } } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, table.Name); row[0] = id; row[1] = componentId; row[2] = name; row[3] = driver; row[4] = setup; } }
/// <summary> /// Gets the validation rows for the table. /// </summary> /// <param name="validationTable">Defintion for the validation table.</param> /// <returns>Collection of output rows for the validation table.</returns> internal OutputRowCollection GetValidationRows(TableDefinition validationTable) { OutputRowCollection outputRows = new OutputRowCollection(); foreach (ColumnDefinition columnDef in this.columns) { if (columnDef.IsUnreal) { continue; } Row row = new Row(validationTable); row[0] = this.name; row[1] = columnDef.Name; if (columnDef.IsNullable) { row[2] = "Y"; } else { row[2] = "N"; } if (columnDef.IsMinValueSet) { row[3] = columnDef.MinValue; } if (columnDef.IsMaxValueSet) { row[4] = columnDef.MaxValue; } row[5] = columnDef.KeyTable; if (columnDef.IsKeyColumnSet) { row[6] = columnDef.KeyColumn; } if (ColumnCategory.Unknown != columnDef.Category) { row[7] = columnDef.Category.ToString(); } row[8] = columnDef.Possibilities; row[9] = columnDef.Description; outputRows.Add(new OutputRow(row)); } return outputRows; }
/// <summary> /// Parse a table from the xml. /// </summary> /// <param name="reader">XmlReader where the intermediate is persisted.</param> /// <param name="section">Section to populate with persisted data.</param> /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param> /// <returns>The parsed table.</returns> internal static Table Parse(XmlReader reader, Section section, TableDefinitionCollection tableDefinitions) { Debug.Assert("table" == reader.LocalName); bool empty = reader.IsEmptyElement; TableOperation operation = TableOperation.None; string name = null; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "name": name = reader.Value; break; case "op": switch (reader.Value) { case "add": operation = TableOperation.Add; break; case "drop": operation = TableOperation.Drop; break; default: throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name, reader.Value, "Add", "Drop")); } break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal)) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name)); } break; } } if (null == name) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", "name")); } TableDefinition tableDefinition = tableDefinitions[name]; Table table = new Table(section, tableDefinition); table.Operation = operation; if (!empty) { bool done = false; // loop through all the rows in a table while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "row": Row.Parse(reader, table); break; default: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "table")); } } return(table); }
/// <summary> /// Creates an output table with the specified definition. /// </summary> /// <param name="tableDef">Definition for all tables in this output table.</param> public OutputTable(TableDefinition tableDef) { this.tableDef = tableDef; this.outputRows = new OutputRowCollection(); }
/// <summary> /// Parses table definition from xml reader. /// </summary> /// <param name="reader">Reader to get data from.</param> /// <returns>The TableDefintion represented by the Xml.</returns> internal static TableDefinition Parse(XmlReader reader) { Debug.Assert("tableDefinition" == reader.LocalName); bool empty = reader.IsEmptyElement; bool createSymbols = false; bool hasPrimaryKeyColumn = false; string name = null; bool unreal = false; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "createSymbols": createSymbols = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "createSymbols", reader.Name, reader.Value); break; case "name": name = reader.Value; break; case "unreal": unreal = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "tableDefinition", reader.Name, reader.Value); break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/")) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "tableDefinition", reader.Name)); } break; } } if (null == name) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "tableDefinition", "name")); } TableDefinition tableDefinition = new TableDefinition(name, createSymbols, unreal); // parse the child elements if (!empty) { bool done = false; while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "columnDefinition": ColumnDefinition columnDefinition = ColumnDefinition.Parse(reader); tableDefinition.columns.Add(columnDefinition); if (columnDefinition.IsLocalizable) { tableDefinition.localizable = true; } if (columnDefinition.IsPrimaryKey) { hasPrimaryKeyColumn = true; } break; default: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "tableDefinition", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!unreal && !hasPrimaryKeyColumn) { throw new WixException(WixErrors.RealTableMissingPrimaryKeyColumn(SourceLineNumberCollection.FromUri(reader.BaseURI), name)); } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "tableDefinition")); } } return(tableDefinition); }
/// <summary> /// Processes an XmlReader and builds up the output table object. /// </summary> /// <param name="reader">Reader to get data from.</param> /// <param name="section">Section to add loaded rows into.</param> /// <returns>Output table.</returns> internal static OutputTable Parse(XmlReader reader, Section section) { Debug.Assert("outputTable" == reader.LocalName); string name = null; bool empty = reader.IsEmptyElement; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "name": name = reader.Value; break; default: throw new WixParseException(String.Format("The outputTable element contains an unexpected attribute {0}.", reader.Name)); } } if (null == name) { throw new WixParseException("The outputTable/@name attribute was not found; it is required."); } OutputTable outputTable = null; if (!empty) { bool done = false; // loop through all the fields in a row while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "tableDefinition": outputTable = new OutputTable(TableDefinition.Parse(reader)); break; case "tuple": if (null == outputTable) { throw new WixParseException("The outputTable element is missing a tableDefinition child element."); } outputTable.outputRows.Add(new OutputRow(Row.Parse(reader, section, outputTable.tableDef))); break; default: throw new WixParseException(String.Format("The outputTable element contains an unexpected child element {0}.", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixParseException("Missing end element while processing the outputTable element."); } } return(outputTable); }
/// <summary> /// Parses table definition from xml reader. /// </summary> /// <param name="reader">Reader to get data from.</param> /// <returns>The TableDefintion represented by the Xml.</returns> internal static TableDefinition Parse(XmlReader reader) { Debug.Assert("tableDefinition" == reader.LocalName); string name = null; bool unreal = false; bool empty = reader.IsEmptyElement; // parse the attributes while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "name": name = reader.Value; break; case "unreal": unreal = Common.IsYes(reader.Value, null, "tableDefinition", reader.Name, name); break; case "xmlns": break; default: throw new WixParseException(String.Format("The tableDefinition element contains an unexpected attribute '{0}'.", reader.Name)); } } if (null == name) { throw new WixParseException("The tableDefinition/@name attribute was not found; it is required."); } TableDefinition tableDefinition = new TableDefinition(name, unreal); // parse the child elements if (!empty) { bool done = false; while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "columnDefinition": tableDefinition.columns.Add(ColumnDefinition.Parse(reader)); break; default: throw new WixParseException(String.Format("The tableDefinition element contains an unexpected child element {0}.", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixParseException("Missing end element while processing the tableDefinition element."); } } return(tableDefinition); }
/// <summary> /// Instantiate a new WixExtensionTableDefinitionConflictException. /// </summary> /// <param name="extension">Extension with conflict.</param> /// <param name="tableDefinition">Table definition conflicting</param> public WixExtensionTableDefinitionConflictException(SchemaExtension extension, TableDefinition tableDefinition) : base(null, ExceptionType) { this.extension = extension; this.tableDefinition = tableDefinition; }
/// <summary> /// Links the definition of a custom table. /// </summary> /// <param name="table">The table to link.</param> /// <param name="customTableDefinitions">Receives the linked definition of the custom table.</param> private void LinkCustomTable(Table table, TableDefinitionCollection customTableDefinitions) { foreach (Row row in table.Rows) { bool bootstrapperApplicationData = (null != row[13] && 1 == (int)row[13]); TableDefinition customTable = new TableDefinition((string)row[0], false, bootstrapperApplicationData, bootstrapperApplicationData); if (null == row[4]) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "CustomTable/Column", "PrimaryKey")); } string[] columnNames = row[2].ToString().Split('\t'); string[] columnTypes = row[3].ToString().Split('\t'); string[] primaryKeys = row[4].ToString().Split('\t'); string[] minValues = row[5] == null ? null : row[5].ToString().Split('\t'); string[] maxValues = row[6] == null ? null : row[6].ToString().Split('\t'); string[] keyTables = row[7] == null ? null : row[7].ToString().Split('\t'); string[] keyColumns = row[8] == null ? null : row[8].ToString().Split('\t'); string[] categories = row[9] == null ? null : row[9].ToString().Split('\t'); string[] sets = row[10] == null ? null : row[10].ToString().Split('\t'); string[] descriptions = row[11] == null ? null : row[11].ToString().Split('\t'); string[] modularizations = row[12] == null ? null : row[12].ToString().Split('\t'); int currentPrimaryKey = 0; for (int i = 0; i < columnNames.Length; ++i) { string name = columnNames[i]; ColumnType type = ColumnType.Unknown; if (columnTypes[i].StartsWith("s", StringComparison.OrdinalIgnoreCase)) { type = ColumnType.String; } else if (columnTypes[i].StartsWith("l", StringComparison.OrdinalIgnoreCase)) { type = ColumnType.Localized; } else if (columnTypes[i].StartsWith("i", StringComparison.OrdinalIgnoreCase)) { type = ColumnType.Number; } else if (columnTypes[i].StartsWith("v", StringComparison.OrdinalIgnoreCase)) { type = ColumnType.Object; } else { throw new WixException(WixErrors.UnknownCustomTableColumnType(row.SourceLineNumbers, columnTypes[i])); } bool nullable = columnTypes[i].Substring(0, 1) == columnTypes[i].Substring(0, 1).ToUpper(CultureInfo.InvariantCulture); int length = Convert.ToInt32(columnTypes[i].Substring(1), CultureInfo.InvariantCulture); bool primaryKey = false; if (currentPrimaryKey < primaryKeys.Length && primaryKeys[currentPrimaryKey] == columnNames[i]) { primaryKey = true; currentPrimaryKey++; } bool minValSet = null != minValues && null != minValues[i] && 0 < minValues[i].Length; int minValue = 0; if (minValSet) { minValue = Convert.ToInt32(minValues[i], CultureInfo.InvariantCulture); } bool maxValSet = null != maxValues && null != maxValues[i] && 0 < maxValues[i].Length; int maxValue = 0; if (maxValSet) { maxValue = Convert.ToInt32(maxValues[i], CultureInfo.InvariantCulture); } bool keyColumnSet = null != keyColumns && null != keyColumns[i] && 0 < keyColumns[i].Length; int keyColumn = 0; if (keyColumnSet) { keyColumn = Convert.ToInt32(keyColumns[i], CultureInfo.InvariantCulture); } ColumnCategory category = ColumnCategory.Unknown; if (null != categories && null != categories[i] && 0 < categories[i].Length) { switch (categories[i]) { case "Text": category = ColumnCategory.Text; break; case "UpperCase": category = ColumnCategory.UpperCase; break; case "LowerCase": category = ColumnCategory.LowerCase; break; case "Integer": category = ColumnCategory.Integer; break; case "DoubleInteger": category = ColumnCategory.DoubleInteger; break; case "TimeDate": category = ColumnCategory.TimeDate; break; case "Identifier": category = ColumnCategory.Identifier; break; case "Property": category = ColumnCategory.Property; break; case "Filename": category = ColumnCategory.Filename; break; case "WildCardFilename": category = ColumnCategory.WildCardFilename; break; case "Path": category = ColumnCategory.Path; break; case "Paths": category = ColumnCategory.Paths; break; case "AnyPath": category = ColumnCategory.AnyPath; break; case "DefaultDir": category = ColumnCategory.DefaultDir; break; case "RegPath": category = ColumnCategory.RegPath; break; case "Formatted": category = ColumnCategory.Formatted; break; case "FormattedSddl": category = ColumnCategory.FormattedSDDLText; break; case "Template": category = ColumnCategory.Template; break; case "Condition": category = ColumnCategory.Condition; break; case "Guid": category = ColumnCategory.Guid; break; case "Version": category = ColumnCategory.Version; break; case "Language": category = ColumnCategory.Language; break; case "Binary": category = ColumnCategory.Binary; break; case "CustomSource": category = ColumnCategory.CustomSource; break; case "Cabinet": category = ColumnCategory.Cabinet; break; case "Shortcut": category = ColumnCategory.Shortcut; break; default: break; } } string keyTable = keyTables != null ? keyTables[i] : null; string setValue = sets != null ? sets[i] : null; string description = descriptions != null ? descriptions[i] : null; string modString = modularizations != null ? modularizations[i] : null; ColumnModularizeType modularization = ColumnModularizeType.None; if (modString != null) { switch (modString) { case "None": modularization = ColumnModularizeType.None; break; case "Column": modularization = ColumnModularizeType.Column; break; case "Property": modularization = ColumnModularizeType.Property; break; case "Condition": modularization = ColumnModularizeType.Condition; break; case "CompanionFile": modularization = ColumnModularizeType.CompanionFile; break; case "SemicolonDelimited": modularization = ColumnModularizeType.SemicolonDelimited; break; } } ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, nullable, modularization, ColumnType.Localized == type, minValSet, minValue, maxValSet, maxValue, keyTable, keyColumnSet, keyColumn, category, setValue, description, true, true); customTable.Columns.Add(columnDefinition); } customTableDefinitions.Add(customTable); } }
/// <summary> /// Creates a table in a section. /// </summary> /// <param name="section">Section to add table to.</param> /// <param name="tableDefinition">Definition of the table.</param> public Table(Section section, TableDefinition tableDefinition) { this.section = section; this.tableDefinition = tableDefinition; this.rows = new RowCollection(); }
/// <summary> /// Ensure this output contains a particular table. /// </summary> /// <param name="tableDefinition">Definition of the table that should exist.</param> /// <returns>The table in this output.</returns> internal Table EnsureTable(TableDefinition tableDefinition) { return this.tables.EnsureTable(this.entrySection, tableDefinition); }
/// <summary> /// Creates a PatchTargetCodeRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this PatchTargetCode row belongs to and should get its column definitions from.</param> public WixBundlePatchTargetCodeRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Adds a table definition to the collection. /// </summary> /// <param name="tableDefinition">Table definition to add to the collection.</param> /// <value>Indexes by table definition name.</value> public void Add(TableDefinition tableDefinition) { if (null == tableDefinition) { throw new ArgumentNullException("tableDefinition"); } this.collection.Add(tableDefinition.Name, tableDefinition); }
/// <summary> /// Ensure this output contains a particular table. /// </summary> /// <param name="tableDefinition">Definition of the table that should exist.</param> /// <returns>The table in this output.</returns> internal Table EnsureTable(TableDefinition tableDefinition) { return(this.tables.EnsureTable(this.entrySection, tableDefinition)); }
/// <summary> /// Parses a control group element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="table">Table referred to by control group.</param> /// <param name="childTag">Expected child elements.</param> private void ParseControlGroupElement(XmlNode node, TableDefinition table, string childTag) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); int order = 0; string property = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Property": property = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == property) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Property")); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { if (childTag != child.LocalName) { this.core.UnexpectedElement(node, child); } switch (child.LocalName) { case "ListItem": this.ParseListItemElement(child, table, property, ref order); break; case "Property": this.ParsePropertyElement(child); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } }
/// <summary> /// Creates a File row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this Media row belongs to and should get its column definitions from.</param> public FileRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a WixUpdateRegistrationRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this WixUpdateRegistrationRow row belongs to and should get its column definitions from.</param> public WixUpdateRegistrationRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary>Creates a File row that does not belong to a table.</summary> /// <param name="tableDef">TableDefinition this File row should get its column definitions from.</param> public FileRow(TableDefinition tableDef) : base(tableDef) { }
/// <summary> /// Creates a Media row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this Media row belongs to and should get its column definitions from.</param> public MediaRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a WixUpdateRegistrationRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this WixUpdateRegistrationRow row belongs to and should get its column definitions from.</param> public WixUpdateRegistrationRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a WixSimpleReferenceRow that belongs to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDefinitions">Table definitions for this row.</param> public WixSimpleReferenceRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDefinitions) : base(sourceLineNumbers, tableDefinitions) { }
/// <summary> /// Creates a WixCommandLineRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this WixCommandLineRow row belongs to and should get its column definitions from.</param> public WixCommandLineRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary>Creates a File row that does not belong to a table.</summary> /// <param name="tableDef">TableDefinition this File row should get its column definitions from.</param> public FileRow(TableDefinition tableDef) : base(tableDef) { }
/// <summary> /// Creates a PayloadInfoRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this Media row belongs to and should get its column definitions from.</param> public PayloadInfoRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a ChainMsiPackage row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this row belongs to and should get its column definitions from.</param> public ChainMsiPackageRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary> /// Creates a WixSimpleReferenceRow that belongs to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDefinitions">Table definitions for this row.</param> public WixSimpleReferenceRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDefinitions) : base(sourceLineNumbers, tableDefinitions) { }
/// <summary> /// Ensure this TableCollection contains a particular table. /// </summary> /// <param name="section">Section containing the new table.</param> /// <param name="tableDefinition">Definition of the table that should exist.</param> /// <returns>The table in this collection.</returns> public Table EnsureTable(Section section, TableDefinition tableDefinition) { Table table = this[tableDefinition.Name]; if (null == table) { table = new Table(section, tableDefinition); this.Add(table); } return table; }
/// <summary> /// Unbind an MSI database file. /// </summary> /// <param name="databaseFile">The database file.</param> /// <param name="database">The opened database.</param> /// <param name="outputType">The type of output to create.</param> /// <param name="exportBasePath">The path where files should be exported.</param> /// <returns>The output representing the database.</returns> private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath) { string modularizationGuid = null; Output output = new Output(SourceLineNumberCollection.FromFileName(databaseFile)); View validationView = null; // set the output type output.Type = outputType; // get the codepage database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt"); using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt"))) { string line; while (null != (line = sr.ReadLine())) { string[] data = line.Split('\t'); if (2 == data.Length) { output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); } } } // get the summary information table using (SummaryInformation summaryInformation = new SummaryInformation(database)) { Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]); for (int i = 1; 19 >= i; i++) { string value = summaryInformation.GetProperty(i); if (0 < value.Length) { Row row = table.CreateRow(output.SourceLineNumbers); row[0] = i; row[1] = value; } } output.Tables.Add(table); } try { // open a view on the validation table if it exists if (database.TableExists("_Validation")) { validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?"); } // get the normal tables using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables")) { Record tableRecord; while (null != (tableRecord = tablesView.Fetch())) { string tableName = tableRecord.GetString(1); using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) { Record rowRecord; Table table; TableDefinition tableDefinition; if (this.tableDefinitions.Contains(tableName)) { tableDefinition = this.tableDefinitions[tableName]; // TODO: verify table definitions // - error for different column name or data type // - warn for additional columns // - need extra info for new columns in standard tables (MSI 4.0 changes) } else // custom table { TableDefinition customTableDefinition = new TableDefinition(tableName, false, false); Hashtable customTablePrimaryKeys = new Hashtable(); Record customColumnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES); Record customColumnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES); int customColumnCount = customColumnNameRecord.GetFieldCount(); // index the primary keys using (Record primaryKeysRecord = database.PrimaryKeys(tableName)) { int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount(); for (int i = 1; i <= primaryKeysFieldCount; i++) { customTablePrimaryKeys[primaryKeysRecord.GetString(i)] = null; } } for (int i = 1; i <= customColumnCount; i++) { string columnName = customColumnNameRecord.GetString(i); string idtType = customColumnTypeRecord.GetString(i); ColumnType columnType; int length; bool nullable; ColumnCategory columnCategory = ColumnCategory.Unknown; ColumnModularizeType columnModularizeType = ColumnModularizeType.None; bool primary = customTablePrimaryKeys.Contains(columnName); bool minValueSet = false; int minValue = -1; bool maxValueSet = false; int maxValue = -1; string keyTable = null; bool keyColumnSet = false; int keyColumn = -1; string category = null; string set = null; string description = null; // get the column type, length, and whether its nullable switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture)) { case 'i': columnType = ColumnType.Number; break; case 'l': columnType = ColumnType.Localized; break; case 's': columnType = ColumnType.String; break; case 'v': columnType = ColumnType.Object; break; default: // TODO: error columnType = ColumnType.Unknown; break; } length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture); nullable = Char.IsUpper(idtType[0]); // try to get validation information if (null != validationView) { Record validationRecord = new Record(2); validationRecord.SetString(1, tableName); validationRecord.SetString(2, columnName); validationView.Execute(validationRecord); validationRecord.Close(); if (null != (validationRecord = validationView.Fetch())) { string validationNullable = validationRecord.GetString(3); minValueSet = !validationRecord.IsNull(4); minValue = (minValueSet ? validationRecord.GetInteger(4) : -1); maxValueSet = !validationRecord.IsNull(5); maxValue = (maxValueSet ? validationRecord.GetInteger(5) : -1); keyTable = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null); keyColumnSet = !validationRecord.IsNull(7); keyColumn = (keyColumnSet ? validationRecord.GetInteger(7) : -1); category = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null); set = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null); description = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null); // check the validation nullable value against the column definition if (null == validationNullable) { // TODO: warn for illegal validation nullable column } else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable)) { // TODO: warn for mismatch between column definition and validation nullable } // convert category to ColumnCategory if (null != category) { try { columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true); } catch (ArgumentException) { columnCategory = ColumnCategory.Unknown; } } validationRecord.Close(); } else { // TODO: warn about no validation information } } // guess the modularization type if ("Icon" == keyTable && 1 == keyColumn) { columnModularizeType = ColumnModularizeType.Icon; } else if ("Condition" == columnName) { columnModularizeType = ColumnModularizeType.Condition; } else if (ColumnCategory.Formatted == columnCategory) { columnModularizeType = ColumnModularizeType.Property; } else if (ColumnCategory.Identifier == columnCategory) { columnModularizeType = ColumnModularizeType.Column; } customTableDefinition.Columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true)); } tableDefinition = customTableDefinition; customColumnNameRecord.Close(); customColumnTypeRecord.Close(); } table = new Table(null, tableDefinition); while (null != (rowRecord = tableView.Fetch())) { int recordCount = rowRecord.GetFieldCount(); Row row = table.CreateRow(output.SourceLineNumbers); for (int i = 0; recordCount > i && row.Fields.Length > i; i++) { if (rowRecord.IsNull(i + 1)) { if (!row.Fields[i].Column.IsNullable) { // TODO: display an error for a null value in a non-nullable field OR // display a warning and put an empty string in the value to let the compiler handle it // (the second option is risky because the later code may make certain assumptions about // the contents of a row value) } } else { switch (row.Fields[i].Column.Type) { case ColumnType.Number: if (row.Fields[i].Column.IsLocalizable) { row[i] = Convert.ToString(rowRecord.GetInteger(i + 1), CultureInfo.InvariantCulture); } else { row[i] = rowRecord.GetInteger(i + 1); } break; case ColumnType.Object: string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; if (null != exportBasePath) { string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); sourceFile = Path.Combine(exportBasePath, relativeSourceFile); // ensure the parent directory exists System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName)); using (FileStream fs = System.IO.File.Create(sourceFile)) { int bytesRead; byte[] buffer = new byte[512]; while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } row[i] = sourceFile; break; default: string value = rowRecord.GetString(i + 1); switch (row.Fields[i].Column.Category) { case ColumnCategory.Guid: value = value.ToUpper(CultureInfo.InvariantCulture); break; } // de-modularize if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) { Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); if (null == modularizationGuid) { Match match = modularization.Match(value); if (match.Success) { modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); } } value = modularization.Replace(value, String.Empty); } // escape "$(" for the preprocessor value = value.Replace("$(", "$$("); // escape things that look like wix variables MatchCollection matches = Common.WixVariableRegex.Matches(value); for (int j = matches.Count - 1; 0 <= j; j--) { value = value.Insert(matches[j].Index, "!"); } row[i] = value; break; } } } rowRecord.Close(); } output.Tables.Add(table); } tableRecord.Close(); } } } finally { if (null != validationView) { validationView.Close(); } } // set the modularization guid as the PackageCode if (null != modularizationGuid) { Table table = output.Tables["_SummaryInformation"]; foreach (Row row in table.Rows) { if (9 == (int)row[0]) // PID_REVNUMBER { row[1] = modularizationGuid; } } } return(output); }
/// <summary> /// Creates a table in a section. /// </summary> /// <param name="section">Section to add table to.</param> /// <param name="tableDefinition">Definition of the table.</param> public Table(Section section, TableDefinition tableDefinition) { this.section = section; this.tableDefinition = tableDefinition; this.rows = new RowCollection(); }
/// <summary> /// Creates an output table with the specified definition. /// </summary> /// <param name="tableDef">Definition for all tables in this output table.</param> public OutputTable(TableDefinition tableDef) { this.tableDef = tableDef; this.outputRows = new OutputRowCollection(); }
/// <summary> /// Creates a row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDefinition">TableDefinition this row should get its column definitions from.</param> /// <remarks>This constructor is used in cases where there isn't a clear owner of the row. The linker uses this constructor for the rows it generates.</remarks> public Row(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDefinition) { if (null == tableDefinition) { throw new ArgumentNullException("tableDefinition"); } this.rowNumber = rowCount++; this.sourceLineNumbers = sourceLineNumbers; this.fields = new Field[tableDefinition.Columns.Count]; this.tableDefinition = tableDefinition; for (int i = 0; i < this.fields.Length; ++i) { this.fields[i] = Field.NewField(this.tableDefinition.Columns[i]); } }
/// <summary> /// Creates a Row from the XmlReader /// </summary> /// <param name="reader">Reader to get data from.</param> /// <param name="section">Section the row is added to.</param> /// <param name="tableDef">Table definition for this row.</param> /// <returns>New row object.</returns> internal static Row Parse(XmlReader reader, Section section, TableDefinition tableDef) { Debug.Assert("tuple" == reader.LocalName); bool empty = reader.IsEmptyElement; string sectionId = null; SourceLineNumberCollection sourceLineNumbers = null; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "sectionId": sectionId = reader.Value; break; case "sourceLineNumber": sourceLineNumbers = new SourceLineNumberCollection(reader.Value); break; default: throw new WixParseException(String.Format("The tuple element contains an unexpected attribute {0}.", reader.Name)); } } Row row = Common.CreateRowInSection(sourceLineNumbers, section, tableDef); row.sectionId = sectionId; // loop through all the fields in a row if (!empty) { bool done = false; int field = 0; // loop through all the fields in a row while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "field": if (row.Fields.Length <= field) { throw new WixParseException(String.Format("This tuple has more fields for table '{0}' than are defined. This is potentially because a standard table is being redefined as a custom table.", tableDef.Name)); } row[field] = Field.Parse(reader); ++field; break; default: throw new WixParseException(String.Format("The tuple element contains an unexpected child element {0}.", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixParseException("Missing end element while processing the tuple element."); } } return row; }
/// <summary>Creates a Control row that does not belong to a table.</summary> /// <param name="tableDef">TableDefinition this Control row should get its column definitions from.</param> public BBControlRow(TableDefinition tableDef) : base(tableDef) { }
/// <summary> /// Creates a row that does not belong to a table. /// </summary> /// <param name="tableDef">TableDefinition this row should get its column definitions from.</param> /// <remarks>This constructor is used in cases where there isn't a clear owner of the row. The linker uses this constructor for the rows it generates.</remarks> public Row(TableDefinition tableDef) : this(null, null == tableDef ? null : tableDef.Columns) { this.tableDef = tableDef; }
/// <summary> /// Parses a list item element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="table">Table to add row to.</param> /// <param name="property">Identifier of property referred to by list item.</param> /// <param name="order">Relative order of list items.</param> private void ParseListItemElement(XmlNode node, TableDefinition table, string property, ref int order) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string icon = null; string text = null; string value = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Icon": if ("ListView" == table.Name) { icon = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Binary", icon); } else { this.core.OnMessage(WixErrors.IllegalAttributeExceptOnElement(sourceLineNumbers, node.Name, attrib.Name, "ListView")); } break; case "Text": text = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Value": value = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == value) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Value")); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.core.UnexpectedElement(node, child); } else { this.core.UnsupportedExtensionElement(node, child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, table.Name); row[0] = property; row[1] = ++order; row[2] = value; row[3] = text; if (null != icon) { row[4] = icon; } } }
/// <summary> /// Creates a row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this row should get its column definitions from.</param> /// <remarks>This constructor is used in cases where there isn't a clear owner of the row. The linker uses this constructor for the rows it generates.</remarks> public Row(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : this(sourceLineNumbers, null == tableDef ? null : tableDef.Columns) { this.tableDef = tableDef; }
/// <summary> /// Parses a control element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="dialog">Identifier for parent dialog.</param> /// <param name="table">Table control belongs in.</param> /// <param name="lastTabRow">Last row in the tab order.</param> /// <param name="firstControl">Name of the first control in the tab order.</param> /// <param name="defaultControl">Name of the default control.</param> /// <param name="cancelControl">Name of the candle control.</param> /// <param name="trackDiskSpace">True if the containing dialog tracks disk space.</param> private void ParseControlElement(XmlNode node, string dialog, TableDefinition table, ref Row lastTabRow, ref string firstControl, ref string defaultControl, ref string cancelControl, bool trackDiskSpace) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; BitArray bits = new BitArray(32); int attributes = 0; string checkBoxPropertyRef = null; string checkboxValue = null; string controlType = null; bool disabled = false; string height = null; string help = null; bool isCancel = false; bool isDefault = false; bool notTabbable = false; string property = null; int publishOrder = 0; string[] specialAttributes = null; string sourceFile = null; string text = null; string tooltip = null; RadioButtonType radioButtonsType = RadioButtonType.NotSet; string width = null; string x = null; string y = null; // The rest of the method relies on the control's Type, so we have to get that first. XmlAttribute typeAttribute = node.Attributes["Type"]; if (null == typeAttribute) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Type")); } else { controlType = this.core.GetAttributeValue(sourceLineNumbers, typeAttribute); } switch (controlType) { case "Billboard": specialAttributes = null; notTabbable = true; disabled = true; this.core.EnsureTable(sourceLineNumbers, "Billboard"); break; case "Bitmap": specialAttributes = MsiInterop.BitmapControlAttributes; notTabbable = true; disabled = true; break; case "CheckBox": specialAttributes = MsiInterop.CheckboxControlAttributes; break; case "ComboBox": specialAttributes = MsiInterop.ComboboxControlAttributes; break; case "DirectoryCombo": specialAttributes = MsiInterop.VolumeControlAttributes; break; case "DirectoryList": specialAttributes = null; break; case "Edit": specialAttributes = MsiInterop.EditControlAttributes; break; case "GroupBox": specialAttributes = null; notTabbable = true; break; case "Hyperlink": specialAttributes = MsiInterop.HyperlinkControlAttributes; break; case "Icon": specialAttributes = MsiInterop.IconControlAttributes; notTabbable = true; disabled = true; break; case "Line": specialAttributes = null; notTabbable = true; disabled = true; break; case "ListBox": specialAttributes = MsiInterop.ListboxControlAttributes; break; case "ListView": specialAttributes = MsiInterop.ListviewControlAttributes; break; case "MaskedEdit": specialAttributes = MsiInterop.EditControlAttributes; break; case "PathEdit": specialAttributes = MsiInterop.EditControlAttributes; break; case "ProgressBar": specialAttributes = MsiInterop.ProgressControlAttributes; notTabbable = true; disabled = true; break; case "PushButton": specialAttributes = MsiInterop.ButtonControlAttributes; break; case "RadioButtonGroup": specialAttributes = MsiInterop.RadioControlAttributes; break; case "ScrollableText": specialAttributes = null; break; case "SelectionTree": specialAttributes = null; break; case "Text": specialAttributes = MsiInterop.TextControlAttributes; notTabbable = true; break; case "VolumeCostList": specialAttributes = MsiInterop.VolumeControlAttributes; notTabbable = true; break; case "VolumeSelectCombo": specialAttributes = MsiInterop.VolumeControlAttributes; break; default: specialAttributes = null; notTabbable = true; break; } foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Type": // already processed break; case "Cancel": isCancel = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "CheckBoxPropertyRef": checkBoxPropertyRef = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "CheckBoxValue": checkboxValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Default": isDefault = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Height": height = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "Help": help = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "IconSize": string iconSizeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (null != specialAttributes) { if (0 < iconSizeValue.Length) { Wix.Control.IconSizeType iconsSizeType = Wix.Control.ParseIconSizeType(iconSizeValue); switch (iconsSizeType) { case Wix.Control.IconSizeType.Item16: CompilerCore.NameToBit(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); break; case Wix.Control.IconSizeType.Item32: CompilerCore.NameToBit(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); break; case Wix.Control.IconSizeType.Item48: CompilerCore.NameToBit(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); CompilerCore.NameToBit(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, iconSizeValue, "16", "32", "48")); break; } } } else { this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name, attrib.Name, iconSizeValue, "Type")); } break; case "Property": property = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "TabSkip": notTabbable = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Text": text = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "ToolTip": tooltip = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Width": width = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "X": x = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "Y": y = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; default: YesNoType attribValue = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); if (!CompilerCore.NameToBit(MsiInterop.CommonControlAttributes, attrib.Name, attribValue, bits, 0)) { if (null == specialAttributes || !CompilerCore.NameToBit(specialAttributes, attrib.Name, attribValue, bits, 16)) { this.core.UnexpectedAttribute(sourceLineNumbers, attrib); } } break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } attributes = CompilerCore.ConvertBitArrayToInt32(bits); if (disabled) { attributes |= MsiInterop.MsidbControlAttributesEnabled; // bit will be inverted when stored } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (null == height) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Height")); } if (null == width) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Width")); } if (null == x) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "X")); } if (null == y) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Y")); } if (isCancel) { cancelControl = id; } if (isDefault) { defaultControl = id; } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); switch (child.LocalName) { case "Binary": this.ParseBinaryElement(child); break; case "ComboBox": this.ParseControlGroupElement(child, this.tableDefinitions["ComboBox"], "ListItem"); break; case "Condition": this.ParseConditionElement(child, node.LocalName, id, dialog); break; case "ListBox": this.ParseControlGroupElement(child, this.tableDefinitions["ListBox"], "ListItem"); break; case "ListView": this.ParseControlGroupElement(child, this.tableDefinitions["ListView"], "ListItem"); break; case "Property": this.ParsePropertyElement(child); break; case "Publish": // ensure that the dialog and control identifiers are not null if (null == dialog) { dialog = String.Empty; } if (null == id) { id = String.Empty; } this.ParsePublishElement(child, dialog, id, ref publishOrder); break; case "RadioButtonGroup": radioButtonsType = this.ParseRadioButtonGroupElement(child, property, radioButtonsType); break; case "Subscribe": this.ParseSubscribeElement(child, dialog, id); break; case "Text": foreach (XmlAttribute attrib in child.Attributes) { switch (attrib.LocalName) { case "SourceFile": case "src": if (null != sourceFile) { this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, node.Name, "src", "SourceFile")); } if ("src" == attrib.LocalName) { this.core.OnMessage(WixWarnings.DeprecatedAttribute(childSourceLineNumbers, node.Name, attrib.Name, "SourceFile")); } sourceFile = this.core.GetAttributeValue(childSourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(childSourceLineNumbers, attrib); break; } } if (0 < child.InnerText.Length) { if (null != sourceFile) { this.core.OnMessage(WixErrors.IllegalAttributeWithInnerText(childSourceLineNumbers, child.Name, "SourceFile")); } else { text = child.InnerText; } } break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } // If the radio buttons have icons, then we need to add the icon attribute. switch (radioButtonsType) { case RadioButtonType.Bitmap: attributes |= MsiInterop.MsidbControlAttributesBitmap; break; case RadioButtonType.Icon: attributes |= MsiInterop.MsidbControlAttributesIcon; break; case RadioButtonType.Text: // Text is the default so nothing needs to be added bits break; } // If we're tracking disk space, and this is a non-FormatSize Text control, and the text attribute starts with // '[' and ends with ']', add a space. It is not necessary for the whole string to be a property, just // those two characters matter. if (trackDiskSpace && "Text" == controlType && MsiInterop.MsidbControlAttributesFormatSize != (attributes & MsiInterop.MsidbControlAttributesFormatSize) && null != text && text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal)) { text = String.Concat(text, " "); } // the logic for creating control rows is a little tricky because of the way tabable controls are set Row row = null; if (!this.core.EncounteredError) { if ("CheckBox" == controlType) { if (String.IsNullOrEmpty(property) && String.IsNullOrEmpty(checkBoxPropertyRef)) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Property", "CheckBoxPropertyRef", true)); } else if (!String.IsNullOrEmpty(property) && !String.IsNullOrEmpty(checkBoxPropertyRef)) { this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name, "Property", "CheckBoxPropertyRef")); } else if (!String.IsNullOrEmpty(property)) { row = this.core.CreateRow(sourceLineNumbers, "CheckBox"); row[0] = property; row[1] = checkboxValue; } else { this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CheckBox", checkBoxPropertyRef); } } row = this.core.CreateRow(sourceLineNumbers, table.Name); row[0] = dialog; row[1] = id; row[2] = controlType; row[3] = x; row[4] = y; row[5] = width; row[6] = height; row[7] = attributes ^ (MsiInterop.MsidbControlAttributesVisible | MsiInterop.MsidbControlAttributesEnabled); if ("BBControl" == table.Name) { row[8] = text; // BBControl.Text if (null != sourceFile) { Row wixBBControlRow = this.core.CreateRow(sourceLineNumbers, "WixBBControl"); wixBBControlRow[0] = dialog; wixBBControlRow[1] = id; wixBBControlRow[2] = sourceFile; } } else { row[8] = !String.IsNullOrEmpty(property) ? property : checkBoxPropertyRef; row[9] = text; if (null != tooltip || null != help) { row[11] = String.Concat(tooltip, "|", help); // Separator is required, even if only one is non-null. } if (null != sourceFile) { Row wixControlRow = this.core.CreateRow(sourceLineNumbers, "WixControl"); wixControlRow[0] = dialog; wixControlRow[1] = id; wixControlRow[2] = sourceFile; } } } if (!notTabbable) { if ("BBControl" == table.Name) { this.core.OnMessage(WixErrors.TabbableControlNotAllowedInBillboard(sourceLineNumbers, node.Name, controlType)); } if (null == firstControl) { firstControl = id; } if (null != lastTabRow) { lastTabRow[10] = id; } lastTabRow = row; } // bitmap and icon controls contain a foreign key into the binary table in the text column; // add a reference if the identifier of the binary entry is known during compilation if (("Bitmap" == controlType || "Icon" == controlType) && CompilerCore.IsIdentifier(text)) { this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Binary", text); } }
/// <summary> /// Create a row in a section. /// </summary> /// <param name="sourceLineNumbers">Line number information about the row.</param> /// <param name="section">Section in which a row is to be added.</param> /// <param name="tableDefinition">Table definition for the row being added.</param> /// <returns>The row added to the section.</returns> internal static Row CreateRowInSection(SourceLineNumberCollection sourceLineNumbers, Section section, TableDefinition tableDefinition) { Table table = section.Tables[tableDefinition.Name]; if (null == table) { table = new Table(section, tableDefinition); section.Tables.Add(table); } return table.CreateRow(sourceLineNumbers); }
/// <summary> /// Links an array of intermediates into an output. /// </summary> /// <param name="intermediates">Array of intermediates to link together.</param> /// <returns>Output object from the linking.</returns> public Output Link(Intermediate[] intermediates) { Output output = null; try { SymbolCollection allSymbols; Section entrySection; bool containsModuleSubstitution = false; bool containsModuleConfiguration = false; StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); ConnectToFeatureCollection componentGroupsToFeatures = new ConnectToFeatureCollection(); ConnectToModuleCollection componentGroupsToModules = new ConnectToModuleCollection(); ComplexReferenceCollection componentsToComponentGroupsComplexReferences = new ComplexReferenceCollection(); ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection(); ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection(); this.activeOutput = null; this.foundError = false; SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); ActionTable requiredActions = new ActionTable(); RowCollection suppressActionRows = new RowCollection(); TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); RowCollection customRows = new RowCollection(); foreach (SchemaExtension extension in this.extensions.Values) { extension.Messages = this.extensionMessages; } // first find the entry section and create the symbols hash for all // the sections in all the intermediates Common.FindEntrySectionAndLoadSymbols(intermediates, this.allowIdenticalRows, this, out entrySection, out allSymbols); // should have found an entry section by now if (null == entrySection) { this.OnMessage(WixErrors.MissingEntrySection()); return null; } // add the standard action symbols to the entry section's symbol table this.LoadStandardActionSymbols(allSymbols, entrySection, this.standardActions); // now that we know where we're starting from, create the output object output = new Output(entrySection); // Note: this entry section will get added to the output section collection later if (null != this.localizer && -1 != this.localizer.Codepage) { output.Codepage = this.localizer.Codepage; } this.activeOutput = output; // resolve the symbol references to find the set of sections we // care about then resolve complex references in those sections Common.ResolveReferences(output.Type, output.Sections, output.EntrySection, allSymbols, referencedSymbols, unresolvedReferences, this); this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures, featuresToFeatures); for (int i = 0; i < unresolvedReferences.Count; ++i) { Common.ReferenceSection referenceSection = (Common.ReferenceSection)unresolvedReferences[i]; if (this.allowUnresolvedReferences) { this.OnMessage(WixWarnings.UnresolvedReferenceWarning(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } else { this.OnMessage(WixErrors.UnresolvedReference(SourceLineNumberCollection.FromFileName(referenceSection.section.Intermediate.SourcePath), referenceSection.section.Type.ToString(), referenceSection.section.Id, referenceSection.reference.SymbolicName)); } } if (this.foundError) { return null; } this.ResolveComponentGroups(output, referencedSymbols, componentsToComponentGroupsComplexReferences, componentGroupsToFeatures, componentGroupsToModules, componentsToFeatures); this.FindOrphanedSymbols(referencedSymbols); // resolve the feature backlink for each section then update the feature to feature connects this.ResolveFeatureBacklinks(output, componentsToFeatures, allSymbols, referencedSymbols, unresolvedReferences); this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols, referencedSymbols, unresolvedReferences); // create a Hashtable of all the suppressed sequence types Hashtable suppressedSequenceTypes = new Hashtable(); // create a Hashtable of all the suppressed standard actions Hashtable suppressedStandardActions = new Hashtable(); if (this.suppressAdminSequence) { suppressedSequenceTypes[SequenceType.adminExecute] = null; suppressedSequenceTypes[SequenceType.adminUI] = null; } if (this.suppressAdvertiseSequence) { suppressedSequenceTypes[SequenceType.advertiseExecute] = null; } if (this.suppressUISequence) { suppressedSequenceTypes[SequenceType.adminUI] = null; suppressedSequenceTypes[SequenceType.installUI] = null; } // start generating OutputTables and OutputRows for all the sections in the output RowCollection ensureTableRows = new RowCollection(); foreach (Section section in this.activeOutput.Sections) { // add this sections list of identifiers to ignore modularization this.activeOutput.IgnoreModularizations.Add(section.IgnoreModularizations); foreach (Table table in section.Tables) { bool copyRows = !table.Definition.IsUnreal; // by default, copy rows if the table is not unreal // handle special tables switch (table.Name) { case "Actions": foreach (Row row in table.Rows) { SequenceType sequenceType; string seqType = (string)row[0]; string id = (string)row[1]; int sequence = null == row[3] ? 0 : Convert.ToInt32(row[3]); bool suppress = 1 == Convert.ToInt32(row[6]); switch (seqType) { case "AdminUISequence": sequenceType = SequenceType.adminUI; break; case "AdminExecuteSequence": sequenceType = SequenceType.adminExecute; break; case "AdvertiseExecuteSequence": sequenceType = SequenceType.advertiseExecute; break; case "InstallExecuteSequence": sequenceType = SequenceType.installExecute; break; case "InstallUISequence": sequenceType = SequenceType.installUI; break; default: throw new WixInvalidSequenceTypeException(null, seqType); } if (suppressedSequenceTypes.Contains(sequenceType)) { this.OnMessage(WixWarnings.SuppressAction(id, Action.SequenceTypeToString(sequenceType))); continue; } // create a SuppressAction row to allow suppressing the action from a merge module if (suppress) { Row suppressActionRow = new Row(row.SourceLineNumbers, this.tableDefinitions["SuppressAction"]); if ("AdvertiseExecuteSequence" == (string)row[0]) { suppressActionRow[0] = "AdvtExecuteSequence"; } else { suppressActionRow[0] = row[0]; } suppressActionRow[1] = row[1]; suppressActionRows.Add(suppressActionRow); } Action action = this.standardActions[sequenceType, id]; string beforeAction = (string)row[4]; string afterAction = (string)row[5]; // if this is not a standard action or there is a before or after action specified if (null == action || null != beforeAction || null != afterAction) { action = new Action(sequenceType, id, (string)row[2], sequence, beforeAction, afterAction); requiredActions.Add(action, true); // add the action and overwrite even if it already exists since this is a customization // if the parent action is a standard action add it to the required list string parentActionName = null != beforeAction ? beforeAction : afterAction; Action parentAction = this.standardActions[sequenceType, parentActionName]; if (null != parentAction) { requiredActions.Add(parentAction); } } else if (!suppress) // must have a standard action that is being overriden (when not suppressed) { action.Condition = (string)row[2]; if (0 != sequence) // if the user specified a sequence number, override the default { action.SequenceNumber = sequence; } requiredActions.Add(action, true); // ensure this action is in the required list } // action was suppressed by user if (suppress && null != action) { suppressedStandardActions[String.Concat(action.SequenceType.ToString(), id)] = action; } } break; case "AppSearch": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Signature"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); break; case "Binary": case "Icon": case "MsiDigitalCertificate": foreach (Row row in table.Rows) { ImportStreamType importStreamType = ImportStreamType.Unknown; switch (table.Name) { case "Binary": importStreamType = ImportStreamType.Binary; break; case "Icon": importStreamType = ImportStreamType.Icon; break; case "MsiDigitalCertificate": importStreamType = ImportStreamType.DigitalCertificate; break; } ImportStream importStream = new ImportStream(importStreamType, row[0].ToString(), row[1].ToString()); if (this.activeOutput.ImportStreams.Contains(importStream.Name)) { this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, String.Format("{0} element with Id='{1}' is defined multiple times.", table.Name, row.Symbol.Name))); } this.activeOutput.ImportStreams.Add(importStream); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); copyRows = false; break; case "BindImage": requiredActions.Add(this.standardActions[SequenceType.installExecute, "BindImage"]); break; case "CCPSearch": requiredActions.Add(this.standardActions[SequenceType.installExecute, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RMCCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "AppSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "CCPSearch"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "RMCCPSearch"]); break; case "Class": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterClassInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterClassInfo"]); break; case "Complus": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterComPlus"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterComPlus"]); break; case "CreateFolder": requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFolders"]); break; case "CustomAction": if (OutputType.Module == this.activeOutput.Type) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); } break; case "CustomTables": foreach (Row row in table.Rows) { TableDefinition customTable = new TableDefinition((string)row[0], false); if (null == row[4]) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "CustomTable/Column", "PrimaryKey")); } string[] columnNames = row[2].ToString().Split(tabCharacter); string[] columnTypes = row[3].ToString().Split(tabCharacter); string[] primaryKeys = row[4].ToString().Split(tabCharacter); string[] minValues = row[5] == null ? null : row[5].ToString().Split(tabCharacter); string[] maxValues = row[6] == null ? null : row[6].ToString().Split(tabCharacter); string[] keyTables = row[7] == null ? null : row[7].ToString().Split(tabCharacter); string[] keyColumns = row[8] == null ? null : row[8].ToString().Split(tabCharacter); string[] categories = row[9] == null ? null : row[9].ToString().Split(tabCharacter); string[] sets = row[10] == null ? null : row[10].ToString().Split(tabCharacter); string[] descriptions = row[11] == null ? null : row[11].ToString().Split(tabCharacter); string[] modularizations = row[12] == null ? null : row[12].ToString().Split(tabCharacter); int currentPrimaryKey = 0; for (int i = 0; i < columnNames.Length; ++i) { string name = columnNames[i]; ColumnType type = ColumnType.Unknown; switch (columnTypes[i].Substring(0, 1).ToLower(CultureInfo.InvariantCulture)) { case "s": type = ColumnType.String; break; case "l": type = ColumnType.Localized; break; case "i": type = ColumnType.Number; break; case "g": type = ColumnType.Object; break; default: throw new ApplicationException(String.Format("Unknown custom table column type: {0}", columnTypes[i])); } bool nullable = columnTypes[i].Substring(0, 1) == columnTypes[i].Substring(0, 1).ToUpper(CultureInfo.InvariantCulture); int length = Convert.ToInt32(columnTypes[i].Substring(1)); bool primaryKey = false; if (currentPrimaryKey < primaryKeys.Length && primaryKeys[currentPrimaryKey] == columnNames[i]) { primaryKey = true; currentPrimaryKey++; } bool minValSet = null != minValues && null != minValues[i] && 0 < minValues[i].Length; int minValue = 0; if (minValSet) { minValue = Convert.ToInt32(minValues[i]); } bool maxValSet = null != maxValues && null != maxValues[i] && 0 < maxValues[i].Length; int maxValue = 0; if (maxValSet) { maxValue = Convert.ToInt32(maxValues[i]); } bool keyColumnSet = null != keyColumns && null != keyColumns[i] && 0 < keyColumns[i].Length; int keyColumn = 0; if (keyColumnSet) { keyColumn = Convert.ToInt32(keyColumns[i]); } ColumnCategory category = ColumnCategory.Unknown; if (null != categories && null != categories[i] && 0 < categories[i].Length) { switch (categories[i]) { case "Text": category = ColumnCategory.Text; break; case "UpperCase": category = ColumnCategory.UpperCase; break; case "LowerCase": category = ColumnCategory.LowerCase; break; case "Integer": category = ColumnCategory.Integer; break; case "DoubleInteger": category = ColumnCategory.DoubleInteger; break; case "TimeDate": category = ColumnCategory.TimeDate; break; case "Identifier": category = ColumnCategory.Identifier; break; case "Property": category = ColumnCategory.Property; break; case "Filename": category = ColumnCategory.Filename; break; case "WildCardFilename": category = ColumnCategory.WildCardFilename; break; case "Path": category = ColumnCategory.Path; break; case "Paths": category = ColumnCategory.Paths; break; case "AnyPath": category = ColumnCategory.AnyPath; break; case "DefaultDir": category = ColumnCategory.DefaultDir; break; case "RegPath": category = ColumnCategory.RegPath; break; case "Formatted": category = ColumnCategory.Formatted; break; case "Template": category = ColumnCategory.Template; break; case "Condition": category = ColumnCategory.Condition; break; case "Guid": category = ColumnCategory.Guid; break; case "Version": category = ColumnCategory.Version; break; case "Language": category = ColumnCategory.Language; break; case "Binary": category = ColumnCategory.Binary; break; case "CustomSource": category = ColumnCategory.CustomSource; break; case "Cabinet": category = ColumnCategory.Cabinet; break; case "Shortcut": category = ColumnCategory.Shortcut; break; default: break; } } string keyTable = keyTables != null ? keyTables[i] : null; string setValue = sets != null ? sets[i] : null; string description = descriptions != null ? descriptions[i] : null; string modString = modularizations != null ? modularizations[i] : null; ColumnModularizeType modularization = ColumnModularizeType.None; if (modString != null) { switch (modString) { case "None": modularization = ColumnModularizeType.None; break; case "Column": modularization = ColumnModularizeType.Column; break; case "Property": modularization = ColumnModularizeType.Property; break; case "Condition": modularization = ColumnModularizeType.Condition; break; case "CompanionFile": modularization = ColumnModularizeType.CompanionFile; break; case "SemicolonDelimited": modularization = ColumnModularizeType.SemicolonDelimited; break; } } ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, false, nullable, modularization, false, ColumnType.Localized == type, minValSet, minValue, maxValSet, maxValue, keyTable, keyColumnSet, keyColumn, category, setValue, description, true, true); customTable.Columns.Add(columnDefinition); } customTableDefinitions.Add(customTable); } copyRows = false; // we've created table definitions from these rows, no need to process them any longer break; case "RowData": foreach (Row row in table.Rows) { customRows.Add(row); } copyRows = false; break; case "Dialog": Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ListBox"]); break; case "Directory": foreach (Row row in table.Rows) { if (OutputType.Module == this.activeOutput.Type && Common.IsStandardDirectory(row[0].ToString())) { // if the directory table contains references to standard windows folders // mergemod.dll will add customactions to set the MSM directory to // the same directory as the standard windows folder and will add references to // custom action to all the standard sequence tables. A problem will occur // if the MSI does not have these tables as mergemod.dll does not add these // tables to the MSI if absent. This code adds the tables in case mergemod.dll // needs them. Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["CustomAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); break; // no need to look here any more, we already found all that we needed to } } break; case "DuplicateFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "DuplicateFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveDuplicateFiles"]); break; case "EnsureTables": foreach (Row row in table.Rows) { ensureTableRows.Add(row); } break; case "Environment": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteEnvironmentStrings"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveEnvironmentStrings"]); break; case "Extension": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterExtensionInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterExtensionInfo"]); break; case "File": foreach (FileRow row in table.Rows) { // DiskId is not valid when creating a module, so set it to // 0 for all files to ensure proper sorting in the binder if (OutputType.Module == this.activeOutput.Type) { row.DiskId = 0; } // if we have an assembly, insert the MsiAssembly row and assembly actions if (FileAssemblyType.NotAnAssembly != row.AssemblyType) { string feature; if (OutputType.Module == output.Type) { feature = Guid.Empty.ToString("B"); } else { ConnectToFeature connect = componentsToFeatures[row.Component]; if (null == connect) { throw new WixMissingFeatureException(row.SourceLineNumbers, new FeatureBacklink(row.Component, FeatureBacklinkType.Assembly, row.File)); } feature = connect.PrimaryFeature; } OutputTable assemblyOutputTable = Common.EnsureOutputTable(output, this.tableDefinitions["MsiAssembly"]); Row assemblyRow = new Row(assemblyOutputTable.TableDefinition); assemblyRow[0] = row.Component; assemblyRow[1] = feature; assemblyRow[2] = row.AssemblyManifest; assemblyRow[3] = row.AssemblyApplication; assemblyRow[4] = Convert.ToInt32(row.AssemblyType); assemblyOutputTable.OutputRows.Add(new OutputRow(assemblyRow, this.sectionIdOnTuples ? section.Id : null)); requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); } if (null == row.Source) // source to the file must be provided { this.OnMessage(WixErrors.FileSourceRequired(row.SourceLineNumbers, row.File)); } this.activeOutput.FileMediaInformationCollection.Add(new FileMediaInformation(row)); } requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallFiles"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "Font": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterFonts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterFonts"]); break; case "IniFile": case "RemoveIniFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteIniValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveIniValues"]); break; case "IsolatedComponent": requiredActions.Add(this.standardActions[SequenceType.installExecute, "IsolateComponents"]); break; case "LaunchCondition": requiredActions.Add(this.standardActions[SequenceType.installExecute, "LaunchConditions"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "LaunchConditions"]); break; case "Media": foreach (MediaRow row in table.Rows) { this.activeOutput.MediaRows.Add(row); } copyRows = false; break; case "Merge": // just copy the rows to the output copyRows = true; break; case "MIME": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterMIMEInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterMIMEInfo"]); break; case "ModuleSignature": if (OutputType.Module == this.activeOutput.Type) { foreach (Row row in table.Rows) { if (null != this.activeOutput.ModularizationGuid) { throw new ArgumentOutOfRangeException("Unexpected number of rows found in table", "ModuleSignature"); } this.activeOutput.ModularizationGuid = row[3].ToString(); } } break; case "ModuleSubstitution": containsModuleSubstitution = true; break; case "ModuleConfiguration": containsModuleConfiguration = true; break; case "MoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "MoveFiles"]); break; case "MsiAssembly": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiPublishAssemblies"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MsiUnpublishAssemblies"]); break; case "ODBCDataSource": case "ODBCTranslator": case "ODBCDriver": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SetODBCFolders"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallODBC"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveODBC"]); break; case "ProgId": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterProgIdInfo"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterProgIdInfo"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Extension"]); // Extension table is required with a ProgId table break; case "Property": foreach (PropertyRow row in table.Rows) { // if there is no value in the property, then it must be virtual if (null == row.Value || 0 == row.Value.Length) { row.IsUnreal = true; } if (row.Admin) { adminProperties[row.Id] = null; } if (row.Secure) { secureProperties[row.Id] = null; } if (row.Hidden) { hiddenProperties[row.Id] = null; } } break; case "PublishComponent": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "PublishComponents"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnpublishComponents"]); break; case "Registry": requiredActions.Add(this.standardActions[SequenceType.installExecute, "WriteRegistryValues"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveRegistryValues"]); break; case "RemoveFile": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveFiles"]); break; case "SelfReg": requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfRegModules"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "SelfUnregModules"]); break; case "ServiceControl": requiredActions.Add(this.standardActions[SequenceType.installExecute, "StartServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "StopServices"]); break; case "ServiceInstall": requiredActions.Add(this.standardActions[SequenceType.installExecute, "InstallServices"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "DeleteServices"]); break; case "Shortcut": requiredActions.Add(this.standardActions[SequenceType.advertiseExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "CreateShortcuts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "RemoveShortcuts"]); break; case "TypeLib": requiredActions.Add(this.standardActions[SequenceType.installExecute, "RegisterTypeLibraries"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "UnregisterTypeLibraries"]); break; case "Upgrade": { requiredActions.Add(this.standardActions[SequenceType.installExecute, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installExecute, "MigrateFeatureStates"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "FindRelatedProducts"]); requiredActions.Add(this.standardActions[SequenceType.installUI, "MigrateFeatureStates"]); foreach (UpgradeRow row in table.Rows) { // this should never happen because candle will make sure that all UpgradeVersion(s) have an ActionProperty...but still don't let it slide if (null == row.ActionProperty) { this.OnMessage(WixErrors.ExpectedAttribute(row.SourceLineNumbers, "UpgradeVersion", "ActionProperty")); } secureProperties[row.ActionProperty] = null; } break; } case "_SummaryInformation": // if we are processing a product, reach into the summary // information and pull out the bits that say if the layout // image is supposed to have long file names and is compressed if (OutputType.Product == output.Type) { foreach (Row row in table.Rows) { // we're looking for the "Word Count" property which happens to // be number 15 (and I thought the answer to the universe was 42, heh). if ("15" == row[0].ToString()) { output.LongFileNames = (0 == (Convert.ToInt32(row[1]) & 1)); output.Compressed = (2 == (Convert.ToInt32(row[1]) & 2)); break; // we're done looking for what we came looking for } } } break; } if (copyRows) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions[table.Name]); this.CopyTableRowsToOutputTable(table, outputTable, section.Id); } } } if (0 < ensureTableRows.Count) { foreach (Row row in ensureTableRows) { string tableId = (string)row[0]; TableDefinition tableDef = null; try { tableDef = this.tableDefinitions[tableId]; } catch (WixMissingTableDefinitionException) { tableDef = customTableDefinitions[tableId]; } Common.EnsureOutputTable(this.activeOutput, tableDef); } } // copy all the suppress action rows to the output to suppress actions from merge modules if (0 < suppressActionRows.Count) { OutputTable suppressActionOutputTable = new OutputTable(this.tableDefinitions["SuppressAction"]); this.activeOutput.OutputTables.Add(suppressActionOutputTable); foreach (Row suppressActionRow in suppressActionRows) { suppressActionOutputTable.OutputRows.Add(new OutputRow(suppressActionRow)); } } foreach (Action suppressedAction in suppressedStandardActions.Values) { if (requiredActions.Contains(suppressedAction)) { // We thought they really ought to have a standard action // that they wanted to suppress, so warn them and remove it this.OnMessage(WixWarnings.SuppressAction(suppressedAction.Id, Action.SequenceTypeToString(suppressedAction.SequenceType))); requiredActions.Remove(suppressedAction); } } // check for missing table and add them or display an error as appropriate switch (this.activeOutput.Type) { case OutputType.Module: Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Component"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Directory"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["FeatureComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleComponents"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleSignature"]); break; case OutputType.PatchCreation: OutputTable imageFamiliesTable = this.activeOutput.OutputTables["ImageFamilies"]; OutputTable targetImagesTable = this.activeOutput.OutputTables["TargetImages"]; OutputTable upgradedImagesTable = this.activeOutput.OutputTables["UpgradedImages"]; if (null == imageFamiliesTable || 1 > imageFamiliesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies")); } if (null == targetImagesTable || 1 > targetImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages")); } if (null == upgradedImagesTable || 1 > upgradedImagesTable.OutputRows.Count) { this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages")); } Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Properties"]); break; case OutputType.Product: // AdminExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFiles"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallAdminPackage"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminExecute, "InstallFinalize"]); // AdminUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.adminUI, "ExecuteAction"]); // AdvtExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.advertiseExecute, "InstallFinalize"]); // InstallExecuteSequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallValidate"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "ProcessComponents"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "UnpublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterUser"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "RegisterProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishFeatures"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "PublishProduct"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installExecute, "InstallFinalize"]); // InstallUISequence Table this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ValidateProductID"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostInitialize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "FileCost"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "CostFinalize"]); this.AddIfNotSuppressed(requiredActions, suppressedStandardActions, this.standardActions[SequenceType.installUI, "ExecuteAction"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["File"]); Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Media"]); break; } // check for illegal tables foreach (OutputTable table in this.activeOutput.OutputTables) { switch (this.activeOutput.Type) { case OutputType.Module: if ("BBControl" == table.Name || "Billboard" == table.Name || "CCPSearch" == table.Name || "Feature" == table.Name || "LaunchCondition" == table.Name || "Media" == table.Name || "Merge" == table.Name || "Patch" == table.Name || "Upgrade" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } else if ("Error" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.DangerousTableInMergeModule(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.PatchCreation: if ("_SummaryInformation" != table.Name && "ExternalFiles" != table.Name && "FamilyFileRanges" != table.Name && "ImageFamilies" != table.Name && "PatchMetadata" != table.Name && "PatchSequence" != table.Name && "Properties" != table.Name && "TargetFiles_OptionalData" != table.Name && "TargetImages" != table.Name && "UpgradedFiles_OptionalData" != table.Name && "UpgradedFilesToIgnore" != table.Name && "UpgradedImages" != table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixErrors.UnexpectedTableInPatchCreationPackage(outputRow.Row.SourceLineNumbers, table.Name)); } } break; case OutputType.Product: if ("ModuleAdminExecuteSequence" == table.Name || "ModuleAdminUISequence" == table.Name || "ModuleAdvtExecuteSequence" == table.Name || "ModuleAdvtUISequence" == table.Name || "ModuleComponents" == table.Name || "ModuleConfiguration" == table.Name || "ModuleDependency" == table.Name || "ModuleExclusion" == table.Name || "ModuleIgnoreTable" == table.Name || "ModuleInstallExecuteSequence" == table.Name || "ModuleInstallUISequence" == table.Name || "ModuleSignature" == table.Name || "ModuleSubstitution" == table.Name) { foreach (OutputRow outputRow in table.OutputRows) { this.OnMessage(WixWarnings.UnexpectedTableInProduct(outputRow.Row.SourceLineNumbers, table.Name)); } } break; } } // add the custom row data foreach (Row row in customRows) { TableDefinition customTable = (TableDefinition)customTableDefinitions[row[0].ToString()]; string[] data = row[2].ToString().Split(tabCharacter); Row customRow = new Row(customTable); for (int i = 0; i < data.Length; ++i) { string[] item = data[i].Split(colonCharacter, 2); customRow.SetData(item[0], item[1]); } bool dataErrors = false; for (int i = 0; i < customTable.Columns.Count; ++i) { if (!customTable.Columns[i].IsNullable && customRow.IsColumnEmpty(i)) { this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTable.Columns[i].Name, customTable.Name)); dataErrors = true; } } if (!dataErrors) { OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, customTable); outputTable.OutputRows.Add(new OutputRow(customRow)); } } // update the special properties if (0 < adminProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "AdminProperties"; newRow[1] = GetPropertyListString(adminProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < secureProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "SecureCustomProperties"; newRow[1] = GetPropertyListString(secureProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (0 < hiddenProperties.Count) { Row newRow = new Row(this.tableDefinitions["Property"]); newRow[0] = "MsiHiddenProperties"; newRow[1] = GetPropertyListString(hiddenProperties); OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["Property"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleSubstitution) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleSubstitution"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } if (containsModuleConfiguration) { Row newRow = new Row(this.tableDefinitions["ModuleIgnoreTable"]); newRow[0] = "ModuleConfiguration"; OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["ModuleIgnoreTable"]); outputTable.OutputRows.Add(new OutputRow(newRow)); } // process the actions foreach (Action action in requiredActions) { // skip actions in suppressed sequences if (suppressedSequenceTypes.Contains(action.SequenceType)) { continue; } if (OutputType.Product == this.activeOutput.Type) { this.ResolveActionSequence(action, requiredActions); } TableDefinition sequenceTableDef = null; bool module = OutputType.Module == this.activeOutput.Type; switch (action.SequenceType) { case SequenceType.adminExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminExecuteSequence"]; } break; case SequenceType.adminUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdminUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdminUISequence"]; } else { sequenceTableDef = this.tableDefinitions["AdminUISequence"]; } break; case SequenceType.advertiseExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["AdvtExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleAdvtExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["AdvtExecuteSequence"]; } break; case SequenceType.installExecute: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallExecuteSequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallExecuteSequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallExecuteSequence"]; } break; case SequenceType.installUI: if (module) { Common.EnsureOutputTable(this.activeOutput, this.tableDefinitions["InstallUISequence"]); sequenceTableDef = this.tableDefinitions["ModuleInstallUISequence"]; } else { sequenceTableDef = this.tableDefinitions["InstallUISequence"]; } break; } Row row = new Row(sequenceTableDef); if (module) { row[0] = action.Id; if (0 != action.SequenceNumber) { row[1] = action.SequenceNumber; } else { bool after = null == action.Before; row[2] = after ? action.After : action.Before; row[3] = after ? 1 : 0; } row[4] = action.Condition; } else // add the row to the sequence table { row[0] = action.Id; row[1] = action.Condition; row[2] = action.SequenceNumber; } OutputTable outputTable = Common.EnsureOutputTable(this.activeOutput, sequenceTableDef); outputTable.OutputRows.Add(new OutputRow(row)); } // set the suppressed action sequences if (this.suppressAdminSequence) { this.activeOutput.SuppressAdminSequence = true; } if (this.suppressAdvertiseSequence) { this.activeOutput.SuppressAdvertiseSequence = true; } if (this.suppressUISequence) { this.activeOutput.SuppressUISequence = true; } } finally { this.activeOutput = null; } return (this.foundError ? null : output); }
/// <summary> /// Ensures the output contains a particular table definition and returns the output table. /// </summary> /// <param name="output">Output to add table definition.</param> /// <param name="tableDef">Table definition to add.</param> /// <returns>Output table in the output.</returns> internal static OutputTable EnsureOutputTable(Output output, TableDefinition tableDef) { OutputTable outputTable = output.OutputTables[tableDef.Name]; if (null == outputTable) { outputTable = new OutputTable(tableDef); output.OutputTables.Add(outputTable); } return outputTable; }
/// <summary> /// Creates a WixBundleRow row that does not belong to a table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="tableDef">TableDefinition this WixBundleRow row belongs to and should get its column definitions from.</param> public WixBundleRow(SourceLineNumberCollection sourceLineNumbers, TableDefinition tableDef) : base(sourceLineNumbers, tableDef) { }
/// <summary>Creates a Control row that does not belong to a table.</summary> /// <param name="tableDef">TableDefinition this Control row should get its column definitions from.</param> public BBControlRow(TableDefinition tableDef) : base(tableDef) { }