/// <summary> /// Extracts files from a binary Wixlib. /// </summary> public void ExtractBinaryWixlibFiles() { Dictionary<string, string> mapCabinetFileIdToFileName = Retina.GetCabinetFileIdToFileNameMap(this.inputFile); if (0 == mapCabinetFileIdToFileName.Count) { this.messageHandler.Display(this, WixWarnings.NotABinaryWixlib(this.inputFile)); return; } // extract the files using their cabinet names ("0", "1", etc.) using (WixExtractCab extractor = new WixExtractCab()) { extractor.Extract(this.inputFile, Path.GetDirectoryName(this.inputFile)); } // the same file can be authored multiple times in the same Wixlib Dictionary<string, bool> uniqueFiles = new Dictionary<string, bool>(); // rename those files to what was authored foreach (KeyValuePair<string, string> kvp in mapCabinetFileIdToFileName) { string cabinetFileId = Path.Combine(Path.GetDirectoryName(this.inputFile), kvp.Key); string fileName = Path.Combine(Path.GetDirectoryName(this.inputFile), kvp.Value); uniqueFiles[fileName] = true; Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(this.inputFile), Path.GetDirectoryName(fileName))); if (File.Exists(fileName)) { File.Delete(fileName); } File.Move(cabinetFileId, fileName); } foreach (string fileName in uniqueFiles.Keys) { Console.WriteLine(fileName); } }
/// <summary> /// Gets the attached container from the exe and extracts its contents to the output directory. /// </summary> /// <param name="outputDirectory">Directory to write extracted files to.</param> /// <returns>True if successful, false otherwise</returns> public bool ExtractAttachedContainer(string outputDirectory, string tempDirectory) { // No attached container to extract if (this.AttachedContainerAddress == 0 || this.AttachedContainerSize == 0) { return false; } if (this.invalidBundle) { return false; } Directory.CreateDirectory(outputDirectory); string tempCabPath = Path.Combine(tempDirectory, "attached.cab"); this.binaryReader.BaseStream.Seek(this.AttachedContainerAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize); } using (WixExtractCab extract = new WixExtractCab()) { extract.Extract(tempCabPath, outputDirectory); } foreach (DictionaryEntry entry in this.attachedContainerPayloadNames) { string sourcePath = Path.Combine(outputDirectory, (string)entry.Key); string destinationPath = Path.Combine(outputDirectory, (string)entry.Value); Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); File.Delete(destinationPath); File.Move(sourcePath, destinationPath); } return true; }
/// <summary> /// Gets the UX container from the exe and extracts its contents to the output directory. /// </summary> /// <param name="outputDirectory">Directory to write extracted files to.</param> /// <returns>True if successful, false otherwise</returns> public bool ExtractUXContainer(string outputDirectory, string tempDirectory) { // No UX container to extract if (this.UXAddress == 0 || this.UXSize == 0) { return false; } if (this.invalidBundle) { return false; } Directory.CreateDirectory(outputDirectory); string tempCabPath = Path.Combine(tempDirectory, "ux.cab"); string manifestOriginalPath = Path.Combine(outputDirectory, "0"); string manifestPath = Path.Combine(outputDirectory, "manifest.xml"); this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); } using (WixExtractCab extract = new WixExtractCab()) { extract.Extract(tempCabPath, outputDirectory); } Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); File.Delete(manifestPath); File.Move(manifestOriginalPath, manifestPath); XmlDocument document = new XmlDocument(); document.Load(manifestPath); XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable); namespaceManager.AddNamespace("burn", BurnCommon.BurnNamespace); XmlNodeList uxPayloads = document.SelectNodes("/burn:BurnManifest/burn:UX/burn:Payload", namespaceManager); XmlNodeList payloads = document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager); foreach (XmlNode uxPayload in uxPayloads) { XmlNode sourcePathNode = uxPayload.Attributes.GetNamedItem("SourcePath"); XmlNode filePathNode = uxPayload.Attributes.GetNamedItem("FilePath"); string sourcePath = Path.Combine(outputDirectory, sourcePathNode.Value); string destinationPath = Path.Combine(outputDirectory, filePathNode.Value); Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); File.Delete(destinationPath); File.Move(sourcePath, destinationPath); } foreach (XmlNode payload in payloads) { XmlNode sourcePathNode = payload.Attributes.GetNamedItem("SourcePath"); XmlNode filePathNode = payload.Attributes.GetNamedItem("FilePath"); XmlNode packagingNode = payload.Attributes.GetNamedItem("Packaging"); string sourcePath = sourcePathNode.Value; string destinationPath = filePathNode.Value; string packaging = packagingNode.Value; if (packaging.Equals("embedded", StringComparison.OrdinalIgnoreCase)) { this.attachedContainerPayloadNames.Add(new DictionaryEntry(sourcePath, destinationPath)); } } return true; }
/// <summary> /// Saves an outputs cab to a path on disk. /// </summary> /// <param name="path">Path to save outputs cab to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the outputs cab.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <returns>Returns true if a cabinet existed or was created, false otherwise.</returns> public bool SaveCab(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { bool hasCab = false; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } hasCab = true; } else { int index = 0; Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); if (null != tempFilesLocation) { // resolve paths to files and create the output cabinet file if (0 == this.sections.Count) { Output.ResolveSectionFiles(this.tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } else { foreach (Section section in this.sections) { Output.ResolveSectionFiles(section.Tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the output xml to the end of the newly created cabinet file hasCab = true; } } return hasCab; }
/// <summary> /// Retrieve files and their information from merge modules. /// </summary> /// <param name="output">Internal representation of the msi database to operate upon.</param> /// <param name="fileRows">The indexed file rows.</param> private void ProcessMergeModules(Output output, FileRowCollection fileRows) { Table wixMergeTable = output.Tables["WixMerge"]; if (null != wixMergeTable) { IMsmMerge2 merge = NativeMethods.GetMsmMerge(); // Get the output's minimum installer version int outputInstallerVersion = int.MinValue; Table summaryInformationTable = output.Tables["_SummaryInformation"]; if (null != summaryInformationTable) { foreach (Row row in summaryInformationTable.Rows) { if (14 == (int)row[0]) { outputInstallerVersion = Convert.ToInt32(row[1], CultureInfo.InvariantCulture); break; } } } foreach (Row row in wixMergeTable.Rows) { bool containsFiles = false; WixMergeRow wixMergeRow = (WixMergeRow)row; try { // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module. using (Database db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly)) { if (db.TableExists("File") && db.TableExists("Component")) { Hashtable uniqueModuleFileIdentifiers = System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable(); using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) { // add each file row from the merge module into the file row collection (check for errors along the way) while (true) { using (Record record = view.Fetch()) { if (null == record) { break; } // NOTE: this is very tricky - the merge module file rows are not added to the // file table because they should not be created via idt import. Instead, these // rows are created by merging in the actual modules FileRow fileRow = new FileRow(null, this.core.TableDefinitions["File"]); fileRow.File = record[1]; fileRow.Compressed = wixMergeRow.FileCompression; fileRow.Directory = record[2]; fileRow.DiskId = wixMergeRow.DiskId; fileRow.FromModule = true; fileRow.PatchGroup = -1; fileRow.Source = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat), Path.DirectorySeparatorChar, record[1]); FileRow collidingFileRow = fileRows[fileRow.File]; FileRow collidingModuleFileRow = (FileRow)uniqueModuleFileIdentifiers[fileRow.File]; if (null == collidingFileRow && null == collidingModuleFileRow) { fileRows.Add(fileRow); // keep track of file identifiers in this merge module uniqueModuleFileIdentifiers.Add(fileRow.File, fileRow); } else // collision(s) detected { // case-sensitive collision with another merge module or a user-authored file identifier if (null != collidingFileRow) { this.core.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, collidingFileRow.File)); } // case-insensitive collision with another file identifier in the same merge module if (null != collidingModuleFileRow) { this.core.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, fileRow.File, collidingModuleFileRow.File)); } } containsFiles = true; } } } } // Get the summary information to detect the Schema using (SummaryInformation summaryInformation = new SummaryInformation(db)) { string moduleInstallerVersionString = summaryInformation.GetProperty(14); try { int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture); if (moduleInstallerVersion > outputInstallerVersion) { this.core.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleInstallerVersion, outputInstallerVersion)); } } catch (FormatException) { throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile, moduleInstallerVersionString)); } } } } catch (FileNotFoundException) { throw new WixException(WixErrors.FileNotFound(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile)); } catch (Win32Exception) { throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile)); } // if the module has files and creating layout if (containsFiles && !this.suppressLayout) { bool moduleOpen = false; short mergeLanguage; try { mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); } catch (System.FormatException) { this.core.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); continue; } try { merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); moduleOpen = true; string safeMergeId = wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat); // extract the module cabinet, then explode all of the files to a temp directory string moduleCabPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, safeMergeId, ".module.cab"); merge.ExtractCAB(moduleCabPath); string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId); Directory.CreateDirectory(mergeIdPath); using (WixExtractCab extractCab = new WixExtractCab()) { try { extractCab.Extract(moduleCabPath, mergeIdPath); } catch (FileNotFoundException) { throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); } catch { throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); } } } catch (COMException ce) { throw new WixException(WixErrors.UnableToOpenModule(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile, ce.Message)); } finally { if (moduleOpen) { merge.CloseModule(); } } } } } }
/// <summary> /// Extracts embedded cabinets for resolved data. /// </summary> /// <param name="cabinets">Collection of cabinets containing resolved data.</param> private void ExtractCabinets(Hashtable cabinets) { foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } }
/// <summary> /// Write files from Cab to disk. /// </summary> /// <param name="cabFileSpec">Specifies the path to the CAB containing the files.</param> /// <param name="diskId">DiskId of the cab.</param> private void ExtractFilesFromCab(string cabFileSpec, int diskId) { WixExtractCab extractCab = null; string extractDir = this.extractFolder; if (!this.processingModule) { extractDir = Path.Combine(extractDir, diskId.ToString()); } if (Directory.Exists(extractDir)) { Directory.Delete(extractDir, true); } try { if (File.Exists(cabFileSpec)) { extractCab = new WixExtractCab(); Directory.CreateDirectory(extractDir); extractCab.Extract(cabFileSpec, extractDir); } } catch (WixCabExtractionException) { this.core.OnMessage(WixErrors.CabExtractionFailed(cabFileSpec, extractDir)); } finally { if (null != extractCab) { try { extractCab.Close(); } catch (WixCabExtractionException) { this.core.OnMessage(WixErrors.CabClosureFailed(cabFileSpec)); } } } }
/// <summary> /// Extract the cabinets from a database. /// </summary> /// <param name="output">The output to use when finding cabinets.</param> /// <param name="database">The database containing the cabinets.</param> /// <param name="databaseFile">The location of the database file.</param> /// <param name="exportBasePath">The path where the files should be exported.</param> private void ExtractCabinets(Output output, Database database, string databaseFile, string exportBasePath) { string databaseBasePath = Path.GetDirectoryName(databaseFile); StringCollection cabinetFiles = new StringCollection(); SortedList embeddedCabinets = new SortedList(); // index all of the cabinet files if (OutputType.Module == output.Type) { embeddedCabinets.Add(0, "MergeModule.CABinet"); } else if (null != output.Tables["Media"]) { foreach (MediaRow mediaRow in output.Tables["Media"].Rows) { if (null != mediaRow.Cabinet) { if (OutputType.Product == output.Type || (OutputType.Transform == output.Type && RowOperation.Add == mediaRow.Operation)) { if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) { embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); } else { cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); } } } } } // extract the embedded cabinet files from the database if (0 < embeddedCabinets.Count) { using (View streamsView = database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) { foreach (int diskId in embeddedCabinets.Keys) { using(Record record = new Record(1)) { record.SetString(1, (string)embeddedCabinets[diskId]); streamsView.Execute(record); } using (Record record = streamsView.Fetch()) { if (null != record) { // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not case-sensitive, // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work string cabinetFile = Path.Combine(this.TempFilesLocation, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); // ensure the parent directory exists System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); using (FileStream fs = System.IO.File.Create(cabinetFile)) { int bytesRead; byte[] buffer = new byte[512]; while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } cabinetFiles.Add(cabinetFile); } else { // TODO: warning about missing embedded cabinet } } } } } // extract the cabinet files if (0 < cabinetFiles.Count) { string fileDirectory = Path.Combine(exportBasePath, "File"); // delete the directory and its files to prevent cab extraction due to an existing file if (Directory.Exists(fileDirectory)) { Directory.Delete(fileDirectory, true); } // ensure the directory exists or extraction will fail Directory.CreateDirectory(fileDirectory); foreach (string cabinetFile in cabinetFiles) { using (WixExtractCab extractCab = new WixExtractCab()) { try { extractCab.Extract(cabinetFile, fileDirectory); } catch (FileNotFoundException) { throw new WixException(WixErrors.FileNotFound(SourceLineNumberCollection.FromFileName(databaseFile), cabinetFile)); } } } } }
/// <summary> /// Merges in any modules to the output database. /// </summary> /// <param name="databasePath">Path to database.</param> /// <param name="output">Output that specifies database and modules to merge.</param> /// <remarks>Expects that output's database has already been generated.</remarks> private void MergeModules(string databasePath, Output output) { Debug.Assert(OutputType.Product == output.Type); if (0 == output.Modules.Count) // no work to do { return; } IMsmMerge2 merge = null; bool commit = false; bool logOpen = false; bool databaseOpen = false; bool moduleOpen = false; try { bool foundError = false; MsmMerge msm = new MsmMerge(); merge = (IMsmMerge2)msm; merge.OpenLog(String.Concat(this.tempFiles.BasePath, Path.DirectorySeparatorChar, "merge.log")); logOpen = true; merge.OpenDatabase(databasePath); databaseOpen = true; // process all the merge rows foreach (MergeRow mergeRow in output.Modules) { string mergeModulePath = null; try { mergeModulePath = this.extension.FileResolutionHandler(mergeRow.SourceFile, FileResolutionType.Module); } catch (WixFileNotFoundException wfnfe) { this.OnMessage(WixErrors.BinderExtensionMissingFile(mergeRow.SourceLineNumbers, ErrorLevel.Normal, wfnfe.Message)); foundError = true; continue; } try { merge.OpenModule(mergeModulePath, mergeRow.Language); } catch (COMException ce) { if (-2147023273 == ce.ErrorCode) // 0x80070657 - ERROR_INSTALL_LANGUAGE_UNSUPPORTED { throw new WixUnknownMergeLanguageException(mergeRow.SourceLineNumbers, mergeRow.Id, mergeModulePath, mergeRow.Language, ce); } else { throw; } } moduleOpen = true; ConnectToFeature connection = output.ModulesToFeatures[mergeRow.Id]; if (null == connection) { throw new WixMergeModuleMissingFeatureException(mergeRow.SourceLineNumbers, mergeRow.Id); } string configData = mergeRow.ConfigurationData; if (null != configData) { ConfigurationCallback callback = new ConfigurationCallback(configData); merge.MergeEx(connection.PrimaryFeature, mergeRow.Directory, callback); } else { merge.Merge(connection.PrimaryFeature, mergeRow.Directory); } /* IMsmErrors errorCollection = null; merge.get_Errors(out errorCollection); long count = errorCollection.get_Count(); if (0 < count) { throw new WixMergeFailureException(null, this.tempFiles.BasePath, count, null); } */ foreach (string connectTo in connection.ConnectFeatures) { merge.Connect(connectTo); } // if the module has files and creating layout if (mergeRow.HasFiles && !this.suppressLayout) { string hashedMergeId = mergeRow.Id.GetHashCode().ToString("X4", CultureInfo.InvariantCulture.NumberFormat); // extract the module cabinet, then explode all of the files to a temp directory string moduleCabPath = String.Concat(this.tempFiles.BasePath, Path.DirectorySeparatorChar, hashedMergeId, ".module.cab"); merge.ExtractCAB(moduleCabPath); string mergeIdPath = String.Concat(this.tempFiles.BasePath, Path.DirectorySeparatorChar, "MergeId.", hashedMergeId); Directory.CreateDirectory(mergeIdPath); WixExtractCab extCab = null; try { extCab = new WixExtractCab(); extCab.Extract(moduleCabPath, mergeIdPath); } catch (WixCabExtractionException wce) { COMException comException = wce.InnerException as COMException; foundError = true; if (null != comException && 0x80070002 == unchecked((uint)comException.ErrorCode)) { extCab = null; // Cab doesn't exist, so drop the object. this.OnMessage(WixErrors.CabFileDoesNotExist(moduleCabPath, mergeModulePath, mergeIdPath)); } else { this.OnMessage(WixErrors.CabExtractionFailed(moduleCabPath, mergeModulePath, mergeIdPath)); } } finally { if (null != extCab) { try { extCab.Close(); } catch (WixCabExtractionException) { this.OnMessage(WixErrors.CabClosureFailed(moduleCabPath)); } } } } moduleOpen = false; merge.CloseModule(); } commit = !foundError; // if all seems to have progressed cleanly, feel free to commit the changes to the database } finally { if (moduleOpen) { merge.CloseModule(); } if (databaseOpen) { merge.CloseDatabase(commit); } if (logOpen) { merge.CloseLog(); } } // create a Hashtable of all the suppressed sequence types Hashtable suppressedTableNames = new Hashtable(); if (output.SuppressAdminSequence) { suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminExecute)] = null; suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminUI)] = null; } if (output.SuppressAdvertiseSequence) { suppressedTableNames[Action.SequenceTypeToString(SequenceType.advertiseExecute)] = null; } if (output.SuppressUISequence) { suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminUI)] = null; suppressedTableNames[Action.SequenceTypeToString(SequenceType.installUI)] = null; } using (Database db = new Database(databasePath, OpenDatabase.Direct)) { OutputTable suppressActionOutputTable = output.OutputTables["SuppressAction"]; // suppress individual actions if (null != suppressActionOutputTable) { foreach (OutputRow outputRow in suppressActionOutputTable.OutputRows) { if (db.TableExists((string)outputRow.Row[0])) { Row row = outputRow.Row; string query = String.Format("SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]); using (View view = db.OpenExecuteView(query)) { Record record; if (view.Fetch(out record)) { this.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString())); view.Modify(ModifyView.Delete, record); record.Close(); } } } } } // query for merge module actions in suppressed sequences and drop them foreach (string tableName in suppressedTableNames.Keys) { if (!db.TableExists(tableName)) { continue; } using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) { Record resultRecord; while (view.Fetch(out resultRecord)) { this.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName)); resultRecord.Close(); } } // drop suppressed sequences using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) { } // delete the validation rows using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) { Record record = new Record(1); record.SetString(1, tableName); view.Execute(record); } } // now update the Attributes column for the files from the Merge Modules using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) { foreach (FileMediaInformation fmi in output.FileMediaInformationCollection) { if (!fmi.IsInModule) { continue; } Record record = new Record(1); record.SetString(1, fmi.File); view.Execute(record); Record recordUpdate; view.Fetch(out recordUpdate); if (null == recordUpdate) { throw new WixMergeFailureException(null, this.tempFiles.BasePath, 1, null); } recordUpdate.SetInteger(1, fmi.Sequence); // update the file attributes to match the compression specified // on the Merge element or on the Package element int attributes = 0; // get the current value if its not null if (!recordUpdate.IsNull(2)) { attributes = recordUpdate.GetInteger(2); } if (FileCompressionValue.Yes == fmi.FileCompression) { attributes |= MsiInterop.MsidbFileAttributesCompressed; } else if (FileCompressionValue.No == fmi.FileCompression) { attributes |= MsiInterop.MsidbFileAttributesNoncompressed; } else // not specified { Debug.Assert(FileCompressionValue.NotSpecified == fmi.FileCompression); // clear any compression bits attributes &= ~MsiInterop.MsidbFileAttributesCompressed; attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed; } recordUpdate.SetInteger(2, attributes); view.Modify(ModifyView.Update, recordUpdate); } } db.Commit(); } }