/// <summary> /// Creates cabinet files. /// </summary> /// <param name="output">Output to generate image for.</param> /// <param name="fileRows">The indexed file rows.</param> /// <param name="fileTransfers">Array of files to be transfered.</param> /// <param name="mediaRows">The indexed media rows.</param> /// <param name="layoutDirectory">The directory in which the image should be layed out.</param> /// <param name="compressed">Flag if source image should be compressed.</param> /// <returns>The uncompressed file rows.</returns> private FileRowCollection CreateCabinetFiles(Output output, FileRowCollection fileRows, ArrayList fileTransfers, MediaRowCollection mediaRows, string layoutDirectory, bool compressed, AutoMediaAssigner autoMediaAssigner) { this.SetCabbingThreadCount(); // Send Binder object to Facilitate NewCabNamesCallBack Callback CabinetBuilder cabinetBuilder = new CabinetBuilder(this.cabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); // Supply Compile MediaTemplate Attributes to Cabinet Builder int MaximumCabinetSizeForLargeFileSplitting; int MaximumUncompressedMediaSize; this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize); cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting; cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize; if (null != this.MessageHandler) { cabinetBuilder.Message += new MessageEventHandler(this.MessageHandler); } foreach (DictionaryEntry entry in autoMediaAssigner.Cabinets) { MediaRow mediaRow = (MediaRow)entry.Key; FileRowCollection files = (FileRowCollection)entry.Value; string cabinetDir = this.FileManager.ResolveMedia(mediaRow, layoutDirectory); CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(output, cabinetDir, mediaRow, files, fileTransfers); if (null != cabinetWorkItem) { cabinetBuilder.Enqueue(cabinetWorkItem); } } // stop processing if an error previously occurred if (this.core.EncounteredError) { return null; } // create queued cabinets with multiple threads int cabError = cabinetBuilder.CreateQueuedCabinets(); if (0 != cabError) { this.core.EncounteredError = true; return null; } return autoMediaAssigner.UncompressedFileRows; }
private bool BindDatabase(Output output, string databaseFile) { foreach (BinderExtension extension in this.extensions) { extension.DatabaseInitialize(output); } bool compressed = false; FileRowCollection fileRows = new FileRowCollection(OutputType.Patch == output.Type); bool longNames = false; MediaRowCollection mediaRows = new MediaRowCollection(); Hashtable suppressModularizationIdentifiers = null; StringCollection suppressedTableNames = new StringCollection(); Table propertyTable = output.Tables["Property"]; this.WriteBuildInfoTable(output, databaseFile); // gather all the wix variables Table wixVariableTable = output.Tables["WixVariable"]; if (null != wixVariableTable) { foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows) { this.WixVariableResolver.AddVariable(wixVariableRow); } } // gather all the suppress modularization identifiers Table wixSuppressModularizationTable = output.Tables["WixSuppressModularization"]; if (null != wixSuppressModularizationTable) { suppressModularizationIdentifiers = new Hashtable(wixSuppressModularizationTable.Rows.Count); foreach (Row row in wixSuppressModularizationTable.Rows) { suppressModularizationIdentifiers[row[0]] = null; } } // localize fields, resolve wix variables, and resolve file paths Hashtable cabinets = new Hashtable(); ArrayList delayedFields = new ArrayList(); this.ResolveFields(output.Tables, cabinets, delayedFields); // if there are any fields to resolve later, create the cache to populate during bind IDictionary<string, string> variableCache = null; if (0 < delayedFields.Count) { variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); } this.LocalizeUI(output.Tables); // process the summary information table before the other tables string modularizationGuid = this.BindDatabaseSummaryInfo(output, out longNames, out compressed); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // modularize identifiers and add tables with real streams to the import tables if (OutputType.Module == output.Type) { foreach (Table table in output.Tables) { table.Modularize(modularizationGuid, suppressModularizationIdentifiers); } // Reset the special property lists after modularization. The linker creates these properties before modularization // so we have to reconstruct them for merge modules after modularization in the binder. Table wixPropertyTable = output.Tables["WixProperty"]; if (null != wixPropertyTable) { // Create lists of the properties that contribute to the special lists of properties. SortedList adminProperties = new SortedList(); SortedList secureProperties = new SortedList(); SortedList hiddenProperties = new SortedList(); foreach (WixPropertyRow wixPropertyRow in wixPropertyTable.Rows) { if (wixPropertyRow.Admin) { adminProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Hidden) { hiddenProperties[wixPropertyRow.Id] = null; } if (wixPropertyRow.Secure) { secureProperties[wixPropertyRow.Id] = null; } } if (0 < adminProperties.Count || 0 < hiddenProperties.Count || 0 < secureProperties.Count) { Table table = output.Tables["Property"]; foreach (Row propertyRow in table.Rows) { if ("AdminProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(adminProperties); } if ("MsiHiddenProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(hiddenProperties); } if ("SecureCustomProperties" == (string)propertyRow[0]) { propertyRow[1] = GetPropertyListString(secureProperties); } } } } } // merge unreal table data into the real tables // this must occur after all variables and source paths have been resolved this.MergeUnrealTables(output.Tables); if (this.core.EncounteredError) { return false; } if (OutputType.Patch == output.Type) { foreach (SubStorage substorage in output.SubStorages) { Output transform = (Output)substorage.Data; this.ResolveFields(transform.Tables, cabinets, null); this.MergeUnrealTables(transform.Tables); } } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // index the File table for quicker access later // this must occur after the unreal data has been merged in Table fileTable = output.Tables["File"]; if (null != fileTable) { fileRows.AddRange(fileTable.Rows); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // add binder variables for all properties propertyTable = output.Tables["Property"]; if (null != propertyTable) { foreach (Row propertyRow in propertyTable.Rows) { string property = propertyRow[0].ToString(); // set the ProductCode if its generated if (OutputType.Product == output.Type && "ProductCode" == property && "*" == propertyRow[1].ToString()) { propertyRow[1] = Common.GenerateGuid(); // Update the target ProductCode in any instance transforms foreach (SubStorage subStorage in output.SubStorages) { Output subStorageOutput = (Output)subStorage.Data; if (OutputType.Transform != subStorageOutput.Type) { continue; } Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"]; foreach (Row row in instanceSummaryInformationTable.Rows) { if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0]) { row[1] = ((string)row[1]).Replace("*", (string)propertyRow[1]); break; } } } } // add the property name and value to the variableCache if (0 != delayedFields.Count) { string key = String.Concat("property.", Demodularize(output, modularizationGuid, property)); variableCache[key] = (string)propertyRow[1]; } } } // extract files that come from cabinet files (this does not extract files from merge modules) this.ExtractCabinets(cabinets); // retrieve files and their information from merge modules if (OutputType.Product == output.Type) { this.ProcessMergeModules(output, fileRows); } else if (OutputType.Patch == output.Type) { // merge transform data into the output object this.CopyTransformData(output, fileRows); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // assign files to media AutoMediaAssigner autoMediaAssigner = new AutoMediaAssigner(output, this.core, compressed); autoMediaAssigner.AssignFiles(fileRows); // update file version, hash, assembly, etc.. information this.core.OnMessage(WixVerboses.UpdatingFileInformation()); Hashtable indexedFileRows = this.UpdateFileInformation(output, fileRows, autoMediaAssigner.MediaRows, variableCache, modularizationGuid); // set generated component guids this.SetComponentGuids(output); // With the Component Guids set now we can create instance transforms. this.CreateInstanceTransforms(output); this.ValidateComponentGuids(output); this.UpdateControlText(output); if (0 < delayedFields.Count) { this.ResolveDelayedFields(output, delayedFields, variableCache, modularizationGuid); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // Extended binder extensions can be called now that fields are resolved. foreach (BinderExtension extension in this.extensions) { BinderExtensionEx extensionEx = extension as BinderExtensionEx; if (null != extensionEx) { output.EnsureTable(this.core.TableDefinitions["WixBindUpdatedFiles"]); extensionEx.DatabaseAfterResolvedFields(output); } } Table updatedFiles = output.Tables["WixBindUpdatedFiles"]; if (null != updatedFiles) { foreach (Row updatedFile in updatedFiles.Rows) { FileRow updatedFileRow = (FileRow)indexedFileRows[updatedFile[0]]; this.UpdateFileRow(output, null, modularizationGuid, indexedFileRows, updatedFileRow, true); } } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // create cabinet files and process uncompressed files string layoutDirectory = Path.GetDirectoryName(databaseFile); FileRowCollection uncompressedFileRows = null; if (!this.suppressLayout || OutputType.Module == output.Type) { this.core.OnMessage(WixVerboses.CreatingCabinetFiles()); uncompressedFileRows = this.CreateCabinetFiles(output, fileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, autoMediaAssigner); } if (OutputType.Patch == output.Type) { // copy output data back into the transforms this.CopyTransformData(output, null); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // add back suppressed tables which must be present prior to merging in modules if (OutputType.Product == output.Type) { Table wixMergeTable = output.Tables["WixMerge"]; if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count) { foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) { string sequenceTableName = sequence.ToString(); Table sequenceTable = output.Tables[sequenceTableName]; if (null == sequenceTable) { sequenceTable = output.EnsureTable(this.core.TableDefinitions[sequenceTableName]); } if (0 == sequenceTable.Rows.Count) { suppressedTableNames.Add(sequenceTableName); } } } } foreach (BinderExtension extension in this.extensions) { extension.DatabaseFinalize(output); } // generate database file this.core.OnMessage(WixVerboses.GeneratingDatabase()); string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile)); this.GenerateDatabase(output, tempDatabaseFile, false, false); FileTransfer transfer; if (FileTransfer.TryCreate(tempDatabaseFile, databaseFile, true, output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future { transfer.Built = true; this.fileTransfers.Add(transfer); } // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } // Output the output to a file if (null != this.pdbFile) { Pdb pdb = new Pdb(null); pdb.Output = output; pdb.Save(this.pdbFile, null, this.WixVariableResolver, this.TempFilesLocation); } // merge modules if (OutputType.Product == output.Type) { this.core.OnMessage(WixVerboses.MergingModules()); this.MergeModules(tempDatabaseFile, output, fileRows, suppressedTableNames); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } } // inspect the MSI prior to running ICEs InspectorCore inspectorCore = new InspectorCore(this.MessageHandler); foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) { inspectorExtension.Core = inspectorCore; inspectorExtension.InspectDatabase(tempDatabaseFile, output); // reset inspectorExtension.Core = null; } if (inspectorCore.EncounteredError) { return false; } // validate the output if there is an MSI validator if (null != this.validator) { Stopwatch stopwatch = Stopwatch.StartNew(); // set the output file for source line information this.validator.Output = output; this.core.OnMessage(WixVerboses.ValidatingDatabase()); this.core.EncounteredError = !this.validator.Validate(tempDatabaseFile); stopwatch.Stop(); this.core.OnMessage(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); // stop processing if an error previously occurred if (this.core.EncounteredError) { return false; } } // process uncompressed files if (!this.suppressLayout) { this.ProcessUncompressedFiles(tempDatabaseFile, uncompressedFileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, longNames); } // layout media try { this.core.OnMessage(WixVerboses.LayingOutMedia()); this.LayoutMedia(this.fileTransfers, this.suppressAclReset); } finally { if (!String.IsNullOrEmpty(this.contentsFile)) { this.CreateContentsFile(this.contentsFile, fileRows); } if (!String.IsNullOrEmpty(this.outputsFile)) { this.CreateOutputsFile(this.outputsFile, this.fileTransfers, this.pdbFile); } if (!String.IsNullOrEmpty(this.builtOutputsFile)) { this.CreateBuiltOutputsFile(this.builtOutputsFile, this.fileTransfers, this.pdbFile); } } return !this.core.EncounteredError; }