/// <summary> /// Assigns the file rows to media rows based on Media or MediaTemplate authoring. Updates uncompressed files collection. /// </summary> /// <param name="fileRows">FileRowCollection</param> public void AssignFiles(FileRowCollection fileRows) { bool autoAssign = false; MediaRow mergeModuleMediaRow = null; Table mediaTable = this.output.Tables["Media"]; Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"]; // If both tables are authored, it is an error. if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1)) { throw new WixException(WixErrors.MediaTableCollision(null)); } autoAssign = mediaTemplateTable != null && OutputType.Module != this.output.Type ? true : false; // When building merge module, all the files go to "#MergeModule.CABinet" if (OutputType.Module == this.output.Type) { Table mergeModuleMediaTable = new Table(null, this.core.TableDefinitions["Media"]); mergeModuleMediaRow = (MediaRow)mergeModuleMediaTable.CreateRow(null); mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet"; this.cabinets.Add(mergeModuleMediaRow, new FileRowCollection()); } if (autoAssign) { this.AutoAssignFiles(mediaTable, fileRows); } else { this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, fileRows); } }
/// <summary> /// Adds a media row to the collection. /// </summary> /// <param name="row">Row to add to the colleciton.</param> /// <remarks>Indexes the row by disk id.</remarks> public void Add(MediaRow row) { if (null == row) { throw new ArgumentNullException("row"); } this.collection.Add(row.DiskId, row); }
/// <summary> /// Adds a row to the media table with cab name template filled in. /// </summary> /// <param name="mediaTable"></param> /// <param name="cabIndex"></param> /// <returns></returns> private MediaRow AddMediaRow(Table mediaTable, int cabIndex) { MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null); currentMediaRow.DiskId = cabIndex; mediaRows.Add(currentMediaRow); currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex); cabinets.Add(currentMediaRow, new FileRowCollection()); return(currentMediaRow); }
/// <summary> /// Resolve the layout path of a media. /// </summary> /// <param name="mediaRow">The media's row.</param> /// <param name="layoutDirectory">The layout directory for the setup image.</param> /// <returns>The layout path for the media.</returns> public virtual string ResolveMedia(MediaRow mediaRow, string layoutDirectory) { string mediaLayoutDirectory = mediaRow.Layout; if (null == mediaLayoutDirectory) { mediaLayoutDirectory = layoutDirectory; } else if (!Path.IsPathRooted(mediaLayoutDirectory)) { mediaLayoutDirectory = Path.Combine(layoutDirectory, mediaLayoutDirectory); } return(mediaLayoutDirectory); }
/// <summary> /// Adds a row to the media table with cab name template filled in. /// </summary> /// <param name="mediaTable"></param> /// <param name="cabIndex"></param> /// <returns></returns> private MediaRow AddMediaRow(Table mediaTable, int cabIndex, string compressionLevel) { MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null); currentMediaRow.DiskId = cabIndex; currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex); this.mediaRows.Add(currentMediaRow); this.cabinets.Add(currentMediaRow, new FileRowCollection()); Table wixMediaTable = this.output.EnsureTable(this.core.TableDefinitions["WixMedia"]); Row row = wixMediaTable.CreateRow(null); row[0] = cabIndex; row[1] = compressionLevel; return(currentMediaRow); }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers) { Row row; switch (this.Name) { // TODO: create strongly types rows here case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "Merge": row = new MergeRow(sourceLineNumbers, this); break; case "Property": row = new PropertyRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } this.rows.Add(row); return(row); }
/// <summary> /// Resolve the layout path of a media. /// </summary> /// <param name="mediaRow">The media's row.</param> /// <param name="layoutDirectory">The layout directory for the setup image.</param> /// <returns>The layout path for the media.</returns> public virtual string ResolveMedia(MediaRow mediaRow, string layoutDirectory) { if (mediaRow == null) { throw new ArgumentNullException("mediaRow"); } string mediaLayoutDirectory = mediaRow.Layout; if (null == mediaLayoutDirectory) { mediaLayoutDirectory = layoutDirectory; } else if (!Path.IsPathRooted(mediaLayoutDirectory)) { mediaLayoutDirectory = Path.Combine(layoutDirectory, mediaLayoutDirectory); } return(mediaLayoutDirectory); }
public Output BuildPairedTransform(string patchId, string clientPatchId, Output mainTransform, MediaRow mediaRow, int validationFlags, out string productCode) { productCode = null; Output pairedTransform = new Output(null); pairedTransform.Type = OutputType.Transform; pairedTransform.Codepage = mainTransform.Codepage; // lookup productVersion property to correct summaryInformation string newProductVersion = null; Table mainPropertyTable = mainTransform.Tables["Property"]; if (null != mainPropertyTable) { foreach (Row row in mainPropertyTable.Rows) { if ("ProductVersion" == (string)row[0]) { newProductVersion = (string)row[1]; } } } // TODO: build class for manipulating SummaryInformation table Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"]; // add required properties Hashtable mainSummaryRows = new Hashtable(); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow; } if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) { Row mainSummaryRow = mainSummaryTable.CreateRow(null); mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; mainSummaryRow[1] = validationFlags.ToString(CultureInfo.InvariantCulture); } // copy summary information from core transform Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { string value = (string)mainSummaryRow[1]; switch ((SummaryInformation.Transform)mainSummaryRow[0]) { case SummaryInformation.Transform.ProductCodes: string[] propertyData = value.Split(';'); string oldProductVersion = propertyData[0].Substring(38); string upgradeCode = propertyData[2]; productCode = propertyData[0].Substring(0, 38); if (newProductVersion == null) { newProductVersion = oldProductVersion; } // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); break; case SummaryInformation.Transform.ValidationFlags: // use validation flags authored into the patch XML mainSummaryRow[1] = value = validationFlags.ToString(CultureInfo.InvariantCulture); break; } Row pairedSummaryRow = pairedSummaryTable.CreateRow(null); pairedSummaryRow[0] = mainSummaryRow[0]; pairedSummaryRow[1] = value; } if (productCode == null) { throw new InvalidOperationException(WixStrings.EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo); } // copy File table Table mainFileTable = mainTransform.Tables["File"]; if (null != mainFileTable && 0 < mainFileTable.Rows.Count) { // We require file source information. Table mainWixFileTable = mainTransform.Tables["WixFile"]; if (null == mainWixFileTable) { throw new WixException(WixErrors.AdminImageRequired(productCode)); } FileRowCollection mainFileRows = new FileRowCollection(); mainFileRows.AddRange(mainFileTable.Rows); Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); foreach (WixFileRow mainWixFileRow in mainWixFileTable.Rows) { FileRow mainFileRow = mainFileRows[mainWixFileRow.File]; // set File.Sequence to non null to satisfy transform bind mainFileRow.Sequence = 1; // delete's don't need rows in the paired transform if (mainFileRow.Operation == RowOperation.Delete) { continue; } FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null); pairedFileRow.Operation = RowOperation.Modify; for (int i = 0; i < mainFileRow.Fields.Length; i++) { pairedFileRow[i] = mainFileRow[i]; } // override authored media for patch bind // TODO: consider using File/@DiskId for patch media mainFileRow.DiskId = mediaRow.DiskId; mainWixFileRow.DiskId = mediaRow.DiskId; // suppress any change to File.Sequence to avoid bloat mainFileRow.Fields[7].Modified = false; // force File row to appear in the transform switch (mainFileRow.Operation) { case RowOperation.Modify: case RowOperation.Add: // set msidbFileAttributesPatchAdded pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; pairedFileRow.Fields[6].Modified = true; pairedFileRow.Operation = mainFileRow.Operation; break; default: pairedFileRow.Fields[6].Modified = false; break; } } } // add Media row to pairedTransform Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]); Row pairedMediaRow = pairedMediaTable.CreateRow(null); pairedMediaRow.Operation = RowOperation.Add; for (int i = 0; i < mediaRow.Fields.Length; i++) { pairedMediaRow[i] = mediaRow[i]; } // add PatchPackage for this Media Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]); pairedPackageTable.Operation = TableOperation.Add; Row pairedPackageRow = pairedPackageTable.CreateRow(null); pairedPackageRow.Operation = RowOperation.Add; pairedPackageRow[0] = patchId; pairedPackageRow[1] = mediaRow.DiskId; // add property to both identify client patches and whether those patches are removable or not int allowRemoval = 0; Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"]; if (null != msiPatchMetadataTable) { foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows) { // get the value of the standard AllowRemoval property, if present string company = (string)msiPatchMetadataRow[0]; if ((null == company || 0 == company.Length) && "AllowRemoval" == (string)msiPatchMetadataRow[1]) { allowRemoval = Int32.Parse((string)msiPatchMetadataRow[2], CultureInfo.InvariantCulture); } } } // add the property to the patch transform's Property table Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]); pairedPropertyTable.Operation = TableOperation.Add; Row pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = string.Concat(clientPatchId, ".AllowRemoval"); pairedPropertyRow[1] = allowRemoval.ToString(CultureInfo.InvariantCulture); // add this patch code GUID to the patch transform to identify // which patches are installed, including in multi-patch // installations. pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = string.Concat(clientPatchId, ".PatchCode"); pairedPropertyRow[1] = patchId; // add PATCHNEWPACKAGECODE to apply to admin layouts pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWPACKAGECODE"; pairedPropertyRow[1] = patchId; // add PATCHNEWSUMMARYCOMMENTS and PATCHNEWSUMMARYSUBJECT to apply to admin layouts Table _summaryInformationTable = this.patch.Tables["_SummaryInformation"]; if (null != _summaryInformationTable) { foreach (Row row in _summaryInformationTable.Rows) { if (3 == (int)row[0]) // PID_SUBJECT { pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWSUMMARYSUBJECT"; pairedPropertyRow[1] = row[1]; } else if (6 == (int)row[0]) // PID_COMMENTS { pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = "PATCHNEWSUMMARYCOMMENTS"; pairedPropertyRow[1] = row[1]; } } } return pairedTransform; }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers) { Row row; switch (this.Name) { // TODO: create strongly types rows here case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "Merge": row = new MergeRow(sourceLineNumbers, this); break; case "Property": row = new PropertyRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } this.rows.Add(row); return row; }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="add">Specifies whether to only create the row or add it to the table automatically.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers, bool add) { Row row; switch (this.Name) { case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "ChainMsiPackage": row = new ChainMsiPackageRow(sourceLineNumbers, this); break; case "Component": row = new ComponentRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "PayloadInfo": row = new PayloadInfoRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; case "Variable": row = new VariableRow(sourceLineNumbers, this); break; case "WixAction": row = new WixActionRow(sourceLineNumbers, this); break; case "WixApprovedExeForElevation": row = new WixApprovedExeForElevationRow(sourceLineNumbers, this); break; case "WixBundle": row = new WixBundleRow(sourceLineNumbers, this); break; case "WixBundlePatchTargetCode": row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this); break; case "WixBundleUpdate": row = new WixBundleUpdateRow(sourceLineNumbers, this); break; case "WixCatalog": row = new WixCatalogRow(sourceLineNumbers, this); break; case "WixCommandLine": row = new WixCommandLineRow(sourceLineNumbers, this); break; case "WixComplexReference": row = new WixComplexReferenceRow(sourceLineNumbers, this); break; case "WixFile": row = new WixFileRow(sourceLineNumbers, this); break; case "WixMedia": row = new WixMediaRow(sourceLineNumbers, this); break; case "WixMediaTemplate": row = new WixMediaTemplateRow(sourceLineNumbers, this); break; case "WixMerge": row = new WixMergeRow(sourceLineNumbers, this); break; case "WixProperty": row = new WixPropertyRow(sourceLineNumbers, this); break; case "WixSimpleReference": row = new WixSimpleReferenceRow(sourceLineNumbers, this); break; case "WixUpdateRegistration": row = new WixUpdateRegistrationRow(sourceLineNumbers, this); break; case "WixVariable": row = new WixVariableRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } if (add) { this.rows.Add(row); } return(row); }
/// <summary> /// Adds the row from a Media table to the end of the collection. /// </summary> /// <param name="mediaRow">The row from the Media table to add.</param> public void Add(MediaRow mediaRow) { this.collection.Add(mediaRow.DiskId, mediaRow); }
/// <summary> /// Assign files to cabinets based on Media authoring. /// </summary> /// <param name="mediaTable"></param> /// <param name="mergeModuleMediaRow"></param> /// <param name="fileRows"></param> private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, FileRowCollection fileRows) { if (OutputType.Module != this.output.Type) { if (null != mediaTable) { Dictionary <string, MediaRow> cabinetMediaRows = new Dictionary <string, MediaRow>(StringComparer.InvariantCultureIgnoreCase); foreach (MediaRow mediaRow in mediaTable.Rows) { // If the Media row has a cabinet, make sure it is unique across all Media rows. if (!String.IsNullOrEmpty(mediaRow.Cabinet)) { MediaRow existingRow; if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) { this.core.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); this.core.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); } else { cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); } } this.mediaRows.Add(mediaRow); } } foreach (MediaRow mediaRow in this.mediaRows) { if (null != mediaRow.Cabinet) { this.cabinets.Add(mediaRow, new FileRowCollection()); } } } foreach (FileRow fileRow in fileRows) { if (OutputType.Module == output.Type) { ((FileRowCollection)this.cabinets[mergeModuleMediaRow]).Add(fileRow); } else { MediaRow mediaRow = this.mediaRows[fileRow.DiskId]; if (null == mediaRow) { this.core.OnMessage(WixErrors.MissingMedia(fileRow.SourceLineNumbers, fileRow.DiskId)); continue; } // When building a product, if the current file is not to be compressed or if // the package set not to be compressed, don't cab it. if (OutputType.Product == output.Type && (YesNoType.No == fileRow.Compressed || (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed))) { uncompressedFileRows.Add(fileRow); } else // file in a Module or marked compressed { FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[mediaRow]; if (null != cabinetFileRow) { cabinetFileRow.Add(fileRow); } else { this.core.OnMessage(WixErrors.ExpectedMediaCabinet(fileRow.SourceLineNumbers, fileRow.File, fileRow.DiskId)); } } } } }
/// <summary> /// Include transforms in a patch. /// </summary> /// <param name="transforms">List of transforms to attach.</param> public void AttachTransforms(ArrayList transforms) { int emptyTransform = 0; if (transforms == null || transforms.Count == 0) { throw new WixException(WixErrors.PatchWithoutTransforms()); } // Get the patch id from the WixPatchId table. string patchId = null; Table wixPatchIdTable = this.patch.Tables["WixPatchId"]; if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count) { Row patchIdRow = wixPatchIdTable.Rows[0]; if (null != patchIdRow) { patchId = patchIdRow[0].ToString(); } } // enumerate patch.Media to map diskId to Media row Hashtable mediaRows = new Hashtable(); Table patchMediaTable = patch.Tables["Media"]; if (patchMediaTable != null) { foreach (MediaRow row in patchMediaTable.Rows) { int media = row.DiskId; mediaRows[media] = row; } } // enumerate patch.WixPatchBaseline to map baseline to diskId Hashtable baselineMedia = new Hashtable(); Table patchBaselineTable = patch.Tables["WixPatchBaseline"]; if (patchBaselineTable != null) { foreach (Row row in patchBaselineTable.Rows) { string baseline = (string)row[0]; int media = (int)row[1]; if (baselineMedia.Contains(baseline)) { throw new InvalidOperationException(String.Format("PatchBaseline '{0}' authored into multiple Media.", baseline)); } baselineMedia[baseline] = media; } } // enumerate transforms ArrayList productCodes = new ArrayList(); ArrayList transformNames = new ArrayList(); int transformCount = 0; foreach (PatchTransform mainTransform in transforms) { string baseline = null; int media = -1; if (baselineMedia.Contains(mainTransform.Baseline)) { int newMedia = (int)baselineMedia[mainTransform.Baseline]; if (media != -1 && media != newMedia) { throw new InvalidOperationException(String.Format("Transform authored into multiple Media '{0}' and '{1}'.", media, newMedia)); } baseline = mainTransform.Baseline; media = newMedia; } if (media == -1) { // transform's baseline not attached to any Media continue; } Table patchRefTable = patch.Tables["WixPatchRef"]; if (patchRefTable != null && patchRefTable.Rows.Count > 0) { if (!this.ReduceTransform(mainTransform.Transform, patchRefTable)) { // transform has none of the content authored into this patch emptyTransform++; continue; } } // ensure consistent File.Sequence within each Media MediaRow mediaRow = (MediaRow)mediaRows[media]; // TODO: should this be authored rather than inferring it from DiskId? mediaRow.LastSequence = mediaRow.DiskId; // ignore media table from transform. mainTransform.Transform.Tables.Remove("Media"); mainTransform.Transform.Tables.Remove("WixMedia"); mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); string productCode = null; Output pairedTransform = this.BuildPairedTransform(patchId, mainTransform.Transform, mediaRow, ref productCode); productCodes.Add(productCode); // attach these transforms to the patch object // TODO: is this an acceptable way to auto-generate transform stream names? string transformName = baseline + "." + (++transformCount).ToString(); patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform)); patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform)); transformNames.Add(":" + transformName); transformNames.Add(":#" + transformName); } if (emptyTransform == transforms.Count) { throw new WixException(WixErrors.PatchWithoutValidTransforms()); } // populate MSP summary information Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]); // remove any existing data for these fields for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--) { Row row = patchSummaryInfo.Rows[i]; switch ((SummaryInformation.Patch)row[0]) { case SummaryInformation.Patch.ProductCodes: case SummaryInformation.Patch.TransformNames: case SummaryInformation.Patch.PatchCode: case SummaryInformation.Patch.InstallerRequirement: patchSummaryInfo.Rows.RemoveAt(i); break; } } // Semicolon delimited list of the product codes that can accept the patch. Row templateRow = patchSummaryInfo.CreateRow(null); templateRow[0] = (int)SummaryInformation.Patch.ProductCodes; templateRow[1] = String.Join(";", (string[])productCodes.ToArray(typeof(string))); // Semicolon delimited list of transform substorage names in the order they are applied. Row savedbyRow = patchSummaryInfo.CreateRow(null); savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames; savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string))); // GUID patch code for the patch. Row revisionRow = patchSummaryInfo.CreateRow(null); revisionRow[0] = (int)SummaryInformation.Patch.PatchCode; revisionRow[1] = patchId; // Indicates the minimum Windows Installer version that is required to install the patch. Row wordsRow = patchSummaryInfo.CreateRow(null); wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement; wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString(); Row security = patchSummaryInfo.CreateRow(null); security[0] = 19; //PID_SECURITY security[1] = "4"; Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"]; if (null != msiPatchMetadataTable) { Hashtable metadataTable = new Hashtable(); foreach (Row row in msiPatchMetadataTable.Rows) { metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString()); } if (metadataTable.Contains("DisplayName")) { string comment = String.Concat("This patch contains the logic and data required to install ", metadataTable["DisplayName"]); Row title = patchSummaryInfo.CreateRow(null); title[0] = 2; //PID_TITLE title[1] = metadataTable["DisplayName"]; Row comments = patchSummaryInfo.CreateRow(null); comments[0] = 6; //PID_COMMENTS comments[1] = comment; } if (metadataTable.Contains("CodePage")) { Row codePage = patchSummaryInfo.CreateRow(null); codePage[0] = 1; //PID_CODEPAGE codePage[1] = metadataTable["CodePage"]; } if (metadataTable.Contains("Description")) { Row subject = patchSummaryInfo.CreateRow(null); subject[0] = 3; //PID_SUBJECT subject[1] = metadataTable["Description"]; } if (metadataTable.Contains("ManufacturerName")) { Row author = patchSummaryInfo.CreateRow(null); author[0] = 4; //PID_AUTHOR author[1] = metadataTable["ManufacturerName"]; } } }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="add">Specifies whether to only create the row or add it to the table automatically.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers, bool add) { Row row; switch (this.Name) { case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "ChainMsiPackage": row = new ChainMsiPackageRow(sourceLineNumbers, this); break; case "Component": row = new ComponentRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "PayloadInfo": row = new PayloadInfoRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; case "Variable": row = new VariableRow(sourceLineNumbers, this); break; case "WixAction": row = new WixActionRow(sourceLineNumbers, this); break; case "WixApprovedExeForElevation": row = new WixApprovedExeForElevationRow(sourceLineNumbers, this); break; case "WixBundle": row = new WixBundleRow(sourceLineNumbers, this); break; case "WixBundlePatchTargetCode": row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this); break; case "WixBundleUpdate": row = new WixBundleUpdateRow(sourceLineNumbers, this); break; case "WixCatalog": row = new WixCatalogRow(sourceLineNumbers, this); break; case "WixCommandLine": row = new WixCommandLineRow(sourceLineNumbers, this); break; case "WixComplexReference": row = new WixComplexReferenceRow(sourceLineNumbers, this); break; case "WixFile": row = new WixFileRow(sourceLineNumbers, this); break; case "WixMedia": row = new WixMediaRow(sourceLineNumbers, this); break; case "WixMediaTemplate": row = new WixMediaTemplateRow(sourceLineNumbers, this); break; case "WixMerge": row = new WixMergeRow(sourceLineNumbers, this); break; case "WixProperty": row = new WixPropertyRow(sourceLineNumbers, this); break; case "WixSimpleReference": row = new WixSimpleReferenceRow(sourceLineNumbers, this); break; case "WixUpdateRegistration": row = new WixUpdateRegistrationRow(sourceLineNumbers, this); break; case "WixVariable": row = new WixVariableRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } if (add) { this.rows.Add(row); } return row; }
/// <summary> /// Assign files to cabinets based on MediaTemplate authoring. /// </summary> /// <param name="fileRows">FileRowCollection</param> private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows) { const int MaxCabIndex = 999; ulong currentPreCabSize = 0; ulong maxPreCabSizeInBytes; int maxPreCabSizeInMB = 0; int currentCabIndex = 0; MediaRow currentMediaRow = null; Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"]; // Auto assign files to cabinets based on maximum uncompressed media size mediaTable.Rows.Clear(); WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) { this.cabinetNameTemplate = mediaTemplateRow.CabinetTemplate; } string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS"); try { // Override authored mums value if environment variable is authored. if (!String.IsNullOrEmpty(mumsString)) { maxPreCabSizeInMB = Int32.Parse(mumsString); } else { maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize; } maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024; } catch (FormatException) { throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString)); } catch (OverflowException) { throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB)); } foreach (FileRow fileRow in fileRows) { // When building a product, if the current file is not to be compressed or if // the package set not to be compressed, don't cab it. if (OutputType.Product == output.Type && (YesNoType.No == fileRow.Compressed || (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed))) { uncompressedFileRows.Add(fileRow); continue; } FileInfo fileInfo = null; // Get the file size try { fileInfo = new FileInfo(fileRow.Source); } catch (ArgumentException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } catch (PathTooLongException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } catch (NotSupportedException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } if (fileInfo.Exists) { if (fileInfo.Length > Int32.MaxValue) { throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source)); } fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture); } if (currentCabIndex == MaxCabIndex) { // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore. FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); continue; } // Update current cab size. currentPreCabSize += (ulong)fileRow.FileSize; if (currentPreCabSize > maxPreCabSizeInBytes) { // Overflow due to current file currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel); FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize currentPreCabSize = (ulong)fileRow.FileSize; } else { // File fits in the current cab. if (currentMediaRow == null) { // Create new cab and MediaRow currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel); } // Associate current file with current cab. FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); } } // If there are uncompressed files and no MediaRow, create a default one. if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0) { MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null); defaultMediaRow.DiskId = 1; mediaRows.Add(defaultMediaRow); } }
/// <summary> /// Create the #transform for the given main transform. /// </summary> /// <param name="patchId">patch GUID from patch authoring.</param> /// <param name="mainTransform">transform generated by torch.</param> /// <param name="mediaRow">media authored into patch.</param> /// <param name="productCode">output string to receive ProductCode.</param> public Output BuildPairedTransform(string patchId, Output mainTransform, MediaRow mediaRow, ref string productCode) { Output pairedTransform = new Output(null); pairedTransform.Type = OutputType.Transform; pairedTransform.Codepage = mainTransform.Codepage; // lookup productVersion property to correct summaryInformation string newProductVersion = null; Table mainPropertyTable = mainTransform.Tables["Property"]; if (mainPropertyTable != null) { foreach (Row row in mainPropertyTable.Rows) { if ("ProductVersion" == (string)row[0]) { newProductVersion = (string)row[1]; } } } // TODO: build class for manipulating SummaryInformation table Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"]; // add required properties Hashtable mainSummaryRows = new Hashtable(); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow; } if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags)) { Row mainSummaryRow = mainSummaryTable.CreateRow(null); mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags; mainSummaryRow[1] = "0"; } // copy summary information from core transform Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]); foreach (Row mainSummaryRow in mainSummaryTable.Rows) { string value = (string)mainSummaryRow[1]; switch ((SummaryInformation.Transform)mainSummaryRow[0]) { case SummaryInformation.Transform.ProductCodes: string[] propertyData = value.Split(';'); string oldProductVersion = propertyData[0].Substring(38); string upgradeCode = propertyData[2]; productCode = propertyData[0].Substring(0, 38); if (newProductVersion == null) { newProductVersion = oldProductVersion; } // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode); break; case SummaryInformation.Transform.ValidationFlags: // TODO: ensure this row exists in mainSummaryTable!!!! // TODO: author these settings in patch XML or set in torch.exe int i = Convert.ToInt32(value); i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingRow; i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingRow; i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingTable; i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingTable; i |= (int)SummaryInformation.TransformFlags.ErrorUpdateMissingRow; i |= (int)SummaryInformation.TransformFlags.ValidateProduct; mainSummaryRow[1] = value = i.ToString(); break; } Row pairedSummaryRow = pairedSummaryTable.CreateRow(null); pairedSummaryRow[0] = mainSummaryRow[0]; pairedSummaryRow[1] = value; } if (productCode == null) { throw new InvalidOperationException("Could not determine ProductCode from transform summary information"); } // copy File table Table mainFileTable = mainTransform.Tables["File"]; Table mainWixFileTable = mainTransform.Tables["WixFile"]; if (mainFileTable != null) { FileRowCollection mainFileRows = new FileRowCollection(); mainFileRows.AddRange(mainFileTable.Rows); Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); foreach (Row mainWixFileRow in mainWixFileTable.Rows) { FileRow mainFileRow = mainFileRows[(string)mainWixFileRow[0]]; // set File.Sequence to non null to satisfy transform bind mainFileRow.Sequence = 1; // delete's don't need rows in the paired transform if (mainFileRow.Operation == RowOperation.Delete) { continue; } FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null); pairedFileRow.Operation = RowOperation.Modify; for (int i = 0; i < mainFileRow.Fields.Length; i++) { object value = mainFileRow[i]; pairedFileRow[i] = value; } // override authored media for patch bind // TODO: consider using File/@DiskId for patch media mainFileRow.DiskId = mediaRow.DiskId; mainWixFileRow[5] = mediaRow.DiskId; // suppress any change to File.Sequence to avoid bloat mainFileRow.Fields[7].Modified = false; // force File row to appear in the transform if (RowOperation.Modify == mainFileRow.Operation) { mainFileRow.Operation = RowOperation.Modify; pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; pairedFileRow.Fields[6].Modified = true; pairedFileRow.Operation = RowOperation.Modify; } else if (RowOperation.Add == mainFileRow.Operation) { // set msidbFileAttributesPatchAdded pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded; pairedFileRow.Fields[6].Modified = true; pairedFileRow.Operation = RowOperation.Add; } else { pairedFileRow.Attributes = mainFileRow.Attributes; pairedFileRow.Fields[6].Modified = false; } } } // add Media row to pairedTransform Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]); Row pairedMediaRow = pairedMediaTable.CreateRow(null); pairedMediaRow.Operation = RowOperation.Add; for (int i = 0; i < mediaRow.Fields.Length; i++) { pairedMediaRow[i] = mediaRow[i]; } // add PatchPackage for this Media Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]); pairedPackageTable.Operation = TableOperation.Add; Row pairedPackageRow = pairedPackageTable.CreateRow(null); pairedPackageRow.Operation = RowOperation.Add; pairedPackageRow[0] = patchId; pairedPackageRow[1] = mediaRow.DiskId; // add property to both identify client patches and whether those patches are removable or not string patchPropertyId = new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper(); int allowRemoval = 0; Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"]; if (null != msiPatchMetadataTable) { foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows) { if (string.Empty == (string)msiPatchMetadataRow[0] && "AllowRemoval" == (string)msiPatchMetadataRow[1]) { allowRemoval = Convert.ToInt32((string)msiPatchMetadataRow[2]); } } } Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]); pairedPropertyTable.Operation = TableOperation.Add; Row pairedPropertyRow = pairedPropertyTable.CreateRow(null); pairedPropertyRow.Operation = RowOperation.Add; pairedPropertyRow[0] = string.Format(CultureInfo.InvariantCulture, "_{0}.AllowRemoval", patchPropertyId); pairedPropertyRow[1] = allowRemoval.ToString(); return(pairedTransform); }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers) { Row row; switch (this.Name) { case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; case "WixAction": row = new WixActionRow(sourceLineNumbers, this); break; case "WixComplexReference": row = new WixComplexReferenceRow(sourceLineNumbers, this); break; case "WixFile": row = new WixFileRow(sourceLineNumbers, this); break; case "WixMedia": row = new WixMediaRow(sourceLineNumbers, this); break; case "WixMerge": row = new WixMergeRow(sourceLineNumbers, this); break; case "WixProperty": row = new WixPropertyRow(sourceLineNumbers, this); break; case "WixSimpleReference": row = new WixSimpleReferenceRow(sourceLineNumbers, this); break; case "WixVariable": row = new WixVariableRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } this.rows.Add(row); return(row); }
/// <summary> /// Creates a work item to create a cabinet. /// </summary> /// <param name="output">Output for the current database.</param> /// <param name="cabinetDir">Directory to create cabinet in.</param> /// <param name="mediaRow">MediaRow containing information about the cabinet.</param> /// <param name="fileRows">Collection of files in this cabinet.</param> /// <param name="fileTransfers">Array of files to be transfered.</param> /// <returns>created CabinetWorkItem object</returns> private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, FileRowCollection fileRows, ArrayList fileTransfers) { CabinetWorkItem cabinetWorkItem = null; string tempCabinetFile = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet); // check for an empty cabinet if (0 == fileRows.Count) { string cabinetName = mediaRow.Cabinet; // remove the leading '#' from the embedded cabinet name to make the warning easier to understand if (cabinetName.StartsWith("#", StringComparison.Ordinal)) { cabinetName = cabinetName.Substring(1); } // If building a patch, remind them to run -p for torch. if (OutputType.Patch == output.Type) { this.core.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true)); } else { this.core.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName)); } } CabinetBuildOption cabinetBuildOption = this.FileManager.ResolveCabinet(fileRows, ref tempCabinetFile); // create a cabinet work item if it's not being skipped if (CabinetBuildOption.BuildAndCopy == cabinetBuildOption || CabinetBuildOption.BuildAndMove == cabinetBuildOption) { int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet). Cab.CompressionLevel compressionLevel = this.defaultCompressionLevel; if (mediaRow.HasExplicitCompressionLevel) { compressionLevel = mediaRow.CompressionLevel; } cabinetWorkItem = new CabinetWorkItem(fileRows, tempCabinetFile, maxThreshold, compressionLevel, this.FileManager); } else // reuse the cabinet from the cabinet cache. { this.core.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, tempCabinetFile)); try { // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output) // causing the project to look like it perpetually needs a rebuild until all of the reused // cabinets get newer timestamps. File.SetLastWriteTime(tempCabinetFile, DateTime.Now); } catch (Exception e) { this.core.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, tempCabinetFile, e.Message)); } } if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) { Table streamsTable = output.EnsureTable(this.core.TableDefinitions["_Streams"]); Row streamRow = streamsTable.CreateRow(null); streamRow[0] = mediaRow.Cabinet.Substring(1); streamRow[1] = tempCabinetFile; } else { string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); FileTransfer transfer; if (FileTransfer.TryCreate(tempCabinetFile, destinationPath, CabinetBuildOption.BuildAndMove == cabinetBuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer)) { transfer.Built = true; fileTransfers.Add(transfer); } } return cabinetWorkItem; }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumberCollection sourceLineNumbers) { Row row; switch (this.Name) { case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "ChainMsiPackage": row = new ChainMsiPackageRow(sourceLineNumbers, this); break; case "Component": row = new ComponentRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "PayloadInfo": row = new PayloadInfoRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; case "WixAction": row = new WixActionRow(sourceLineNumbers, this); break; case "WixComplexReference": row = new WixComplexReferenceRow(sourceLineNumbers, this); break; case "WixFile": row = new WixFileRow(sourceLineNumbers, this); break; case "WixMedia": row = new WixMediaRow(sourceLineNumbers, this); break; case "WixMediaTemplate": row = new WixMediaTemplateRow(sourceLineNumbers, this); break; case "WixMerge": row = new WixMergeRow(sourceLineNumbers, this); break; case "WixProperty": row = new WixPropertyRow(sourceLineNumbers, this); break; case "WixSimpleReference": row = new WixSimpleReferenceRow(sourceLineNumbers, this); break; case "WixVariable": row = new WixVariableRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } this.rows.Add(row); return row; }
/// <summary> /// Resolve the layout path of a media. /// </summary> /// <param name="mediaRow">The media's row.</param> /// <param name="layoutDirectory">The layout directory for the setup image.</param> /// <returns>The layout path for the media.</returns> public virtual string ResolveMedia(MediaRow mediaRow, string layoutDirectory) { if (mediaRow == null) { throw new ArgumentNullException("mediaRow"); } string mediaLayoutDirectory = mediaRow.Layout; if (null == mediaLayoutDirectory) { mediaLayoutDirectory = layoutDirectory; } else if (!Path.IsPathRooted(mediaLayoutDirectory)) { mediaLayoutDirectory = Path.Combine(layoutDirectory, mediaLayoutDirectory); } return mediaLayoutDirectory; }
/// <summary> /// Assign files to cabinets based on Media authoring. /// </summary> /// <param name="mediaTable"></param> /// <param name="mergeModuleMediaRow"></param> /// <param name="fileRows"></param> private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, FileRowCollection fileRows) { if (OutputType.Module != this.output.Type) { if (null != mediaTable) { Dictionary<string, MediaRow> cabinetMediaRows = new Dictionary<string, MediaRow>(StringComparer.InvariantCultureIgnoreCase); foreach (MediaRow mediaRow in mediaTable.Rows) { // If the Media row has a cabinet, make sure it is unique across all Media rows. if (!String.IsNullOrEmpty(mediaRow.Cabinet)) { MediaRow existingRow; if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) { this.core.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); this.core.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); } else { cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); } } this.mediaRows.Add(mediaRow); } } foreach (MediaRow mediaRow in this.mediaRows) { if (null != mediaRow.Cabinet) { this.cabinets.Add(mediaRow, new FileRowCollection()); } } } foreach (FileRow fileRow in fileRows) { if (OutputType.Module == output.Type) { ((FileRowCollection)this.cabinets[mergeModuleMediaRow]).Add(fileRow); } else { MediaRow mediaRow = this.mediaRows[fileRow.DiskId]; // When building a product, if the current file is not to be compressed or if // the package set not to be compressed, don't cab it. if (OutputType.Product == output.Type && (YesNoType.No == fileRow.Compressed || (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed))) { uncompressedFileRows.Add(fileRow); } else // file in a Module or marked compressed { FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[mediaRow]; if (null != cabinetFileRow) { cabinetFileRow.Add(fileRow); } else { this.core.OnMessage(WixErrors.ExpectedMediaCabinet(fileRow.SourceLineNumbers, fileRow.File, fileRow.DiskId)); } } } } }