public override SignatureVerificationResult VerifySignature(string path, string parent) { // Let the base class take care of verifying the AuthentiCode/StrongName SignatureVerificationResult svr = base.VerifySignature(path, parent); if (VerifyRecursive) { if (PEHeader.ImageSectionHeaders.Select(s => s.SectionName).Contains(".wixburn")) { Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagSectionHeader, ".wixburn"); Log.WriteMessage(LogVerbosity.Detailed, SignCheckResources.WixBundle, svr.FullPath); Unbinder unbinder = null; try { Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagExtractingFileContents, svr.TempPath); unbinder = new Unbinder(); unbinder.Message += UnbinderEventHandler; Output o = unbinder.Unbind(svr.FullPath, OutputType.Bundle, svr.TempPath); if (Directory.Exists(svr.TempPath)) { foreach (string file in Directory.EnumerateFiles(svr.TempPath, "*.*", SearchOption.AllDirectories)) { SignatureVerificationResult bundleEntryResult = VerifyFile(Path.GetFullPath(file), svr.Filename, Path.GetFileName(file)); //CheckAndUpdateExclusion(bundleEntryResult, "*"+Path.GetFileName(file), file, svr.Filename); svr.NestedResults.Add(bundleEntryResult); } } Directory.Delete(svr.TempPath, recursive: true); } finally { unbinder.DeleteTempFiles(); } } } // TODO: Check for SFXCAB, IronMan, etc. return(svr); }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Microsoft.Tools.WindowsInstallerXml.Binder binder = null; Differ differ = null; Unbinder unbinder = null; TempFileCollection tempFileCollection = null; try { // parse the command line this.ParseCommandLine(args); // validate the inputs if (this.xmlInputs && this.adminImage) { this.messageHandler.Display(this, WixErrors.IllegalCommandlineArgumentCombination("a", "xi")); this.showHelp = true; } string[] allValidExtensions = new string[] { wixMstExtension, wixOutExtension, wixPdbExtension, msiExtension }; string[] expectedSingleInputExtensions = new string[] { wixMstExtension, wixOutExtension }; string[] expectedDoubleInputXmlExtensions = new string[] { wixOutExtension, wixPdbExtension }; string[] expectedDoubleInputMsiExtensions = new string[] { msiExtension }; // Validate that all inputs have the correct extension and we dont have too many inputs. if (1 == this.inputFiles.Count) { string inputFile = this.inputFiles[0]; bool hasValidExtension = false; foreach (string extension in expectedSingleInputExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; break; } } if (!hasValidExtension) { bool missingInput = false; // Check if its using an extension that could be valid in other scenarios. foreach (string validExtension in allValidExtensions) { if (String.Equals(Path.GetExtension(inputFile), validExtension, StringComparison.OrdinalIgnoreCase)) { this.messageHandler.Display(this, WixErrors.WrongFileExtensionForNumberOfInputs(Path.GetExtension(inputFile), inputFile)); missingInput = true; break; } } if (!missingInput) { this.messageHandler.Display(this, WixErrors.UnexpectedFileExtension(inputFile, String.Join(", ", expectedSingleInputExtensions))); } } } else if (2 == this.inputFiles.Count) { foreach (string inputFile in inputFiles) { bool hasValidExtension = false; string[] expectedExtensions = allValidExtensions; if (this.xmlInputs) { foreach (string extension in expectedDoubleInputXmlExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; expectedExtensions = expectedDoubleInputXmlExtensions; break; } } } else { foreach (string extension in expectedDoubleInputMsiExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; expectedExtensions = expectedDoubleInputMsiExtensions; break; } } } if (!hasValidExtension) { this.messageHandler.Display(this, WixErrors.UnexpectedFileExtension(inputFile, String.Join(", ", expectedExtensions))); } } } else { this.showHelp = true; } // exit if there was an error parsing the command line or with a file extension (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return(this.messageHandler.LastErrorNumber); } if (null == this.outputFile) { this.showHelp = true; } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(TorchStrings.HelpMessage); AppCommon.DisplayToolFooter(); return(this.messageHandler.LastErrorNumber); } foreach (string parameter in this.invalidArgs) { this.messageHandler.Display(this, WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; binder = new Microsoft.Tools.WindowsInstallerXml.Binder(); differ = new Differ(); unbinder = new Unbinder(); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); unbinder.AddExtension(wixExtension); binder.AddExtension(wixExtension); differ.AddExtension(wixExtension); } binder.Message += new MessageEventHandler(this.messageHandler.Display); differ.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); binder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); tempFileCollection = new TempFileCollection(Environment.GetEnvironmentVariable("WIX_TEMP")); binder.WixVariableResolver = new WixVariableResolver(); differ.PreserveUnchangedRows = this.preserveUnchangedRows; differ.ShowPedanticMessages = this.showPedanticMessages; unbinder.SuppressExtractCabinets = true; unbinder.IsAdminImage = this.adminImage; if (null == this.exportBasePath) { this.exportBasePath = tempFileCollection.BasePath; } // load and process the inputs Output transform; if (1 == this.inputFiles.Count) { transform = Output.Load(this.inputFiles[0], false, false); if (OutputType.Transform != transform.Type) { this.messageHandler.Display(this, WixErrors.InvalidWixTransform(this.inputFiles[0])); return(this.messageHandler.LastErrorNumber); } } else // 2 inputs { Output targetOutput; Output updatedOutput; if (this.xmlInputs) { // load the target database if (String.Equals(Path.GetExtension(inputFiles[0]), wixPdbExtension, StringComparison.OrdinalIgnoreCase)) { Pdb targetPdb = Pdb.Load(this.inputFiles[0], false, false); targetOutput = targetPdb.Output; } else { targetOutput = Output.Load(this.inputFiles[0], false, false); } // load the updated database if (String.Equals(Path.GetExtension(inputFiles[1]), wixPdbExtension, StringComparison.OrdinalIgnoreCase)) { Pdb updatedPdb = Pdb.Load(this.inputFiles[1], false, false); updatedOutput = updatedPdb.Output; } else { updatedOutput = Output.Load(this.inputFiles[1], false, false); } this.xmlOutput = true; } else { // load the target database targetOutput = unbinder.Unbind(this.inputFiles[0], OutputType.Product, Path.Combine(this.exportBasePath, "targetBinaries")); // load the updated database updatedOutput = unbinder.Unbind(this.inputFiles[1], OutputType.Product, Path.Combine(this.exportBasePath, "updatedBinaries")); } // diff the target and updated databases transform = differ.Diff(targetOutput, updatedOutput, this.validationFlags); if (null == transform.Tables || 0 >= transform.Tables.Count) { throw new WixException(WixErrors.NoDifferencesInTransform(transform.SourceLineNumbers)); } } // output the transform if (null != transform) { // If either the user selected xml output or gave xml input, save as xml output. // With xml inputs, many funtions of the binder have not been performed on the inputs (ie. file sequencing). This results in bad IDT files which cannot be put in a transform. if (this.xmlOutput) { transform.Save(this.outputFile, null, null, tempFileCollection.BasePath); } else { binder.Bind(transform, this.outputFile); } } } catch (WixException we) { if (we is WixInvalidIdtException) { // make sure the IDT files stay around this.tidy = false; } this.messageHandler.Display(this, we.Error); } catch (Exception e) { // make sure the files stay around for debugging this.tidy = false; this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != binder) { if (this.tidy) { if (!binder.DeleteTempFiles()) { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, binder.TempFilesLocation); } } else { Console.WriteLine(TorchStrings.INF_BinderTempDirLocatedAt, binder.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, binder.TempFilesLocation); } } else { Console.WriteLine(TorchStrings.INF_UnbinderTempDirLocatedAt, binder.TempFilesLocation); } } if (null != tempFileCollection) { if (this.tidy) { try { Directory.Delete(tempFileCollection.BasePath, true); } catch (DirectoryNotFoundException) { // if the path doesn't exist, then there is nothing for us to worry about } catch { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, tempFileCollection.BasePath); } } else { Console.WriteLine(TorchStrings.INF_TorchTempDirLocatedAt, tempFileCollection.BasePath); } } } return(this.messageHandler.LastErrorNumber); }
/// <summary> /// Compare two result files. /// </summary> /// <param name="expectedResult">The expected result file.</param> /// <param name="actualResult">The actual result file.</param> /// <returns>Any differences found.</returns> public static ArrayList CompareResults(string expectedResult, string actualResult) { ArrayList differences = new ArrayList(); Output targetOutput; Output updatedOutput; OutputType outputType; string extension = Path.GetExtension(expectedResult); if (String.Compare(extension, ".msi", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Product; } else if (String.Compare(extension, ".msm", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Module; } else if (String.Compare(extension, ".msp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Patch; } else if (String.Compare(extension, ".mst", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Transform; } else if (String.Compare(extension, ".pcp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.PatchCreation; } else if (String.Compare(extension, ".wixout", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Unknown; } else { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot determine the type of msi database file based on file extension '{0}'.", extension)); } if (outputType != OutputType.Unknown) { Unbinder unbinder = new Unbinder(); unbinder.SuppressDemodularization = true; // don't allow concurrent calls to Unbind try { mutex.WaitOne(); targetOutput = unbinder.Unbind(expectedResult, outputType, null); updatedOutput = unbinder.Unbind(actualResult, outputType, null); unbinder.DeleteTempFiles(); } finally { mutex.ReleaseMutex(); } } else { targetOutput = Output.Load(expectedResult, false, false); updatedOutput = Output.Load(actualResult, false, false); } differences.AddRange(CompareOutput(targetOutput, updatedOutput)); // If the Output type is a Patch, then compare the patch's transforms if (outputType == OutputType.Patch) { // Compare transforms foreach (SubStorage targetTransform in targetOutput.SubStorages) { SubStorage updatedTransform = null; // Find the same transform in the other patch foreach (SubStorage transform in updatedOutput.SubStorages) { if (transform.Name == targetTransform.Name) { updatedTransform = transform; break; } } if (null != updatedTransform) { // Both patch's have this transform ArrayList transformDifferences = CompareUnit.CompareOutput(targetTransform.Data, updatedTransform.Data); // add a description of the transforms being compared if (0 < transformDifferences.Count) { transformDifferences.Insert(0, String.Concat("Differences found while comparing the transform ", targetTransform.Name, " from the two patches")); differences.AddRange(transformDifferences); } } else { differences.Add(String.Format("The {0} tranform has been dropped", targetTransform.Name)); } } // Check if the updated patch has had transforms added foreach (SubStorage updatedTransform in updatedOutput.SubStorages) { SubStorage targetTransform = null; foreach (SubStorage transform in targetOutput.SubStorages) { if (transform.Name == updatedTransform.Name) { targetTransform = transform; break; } } if (targetTransform == null) { differences.Add(String.Format("The {0} tranform has been added", updatedTransform.Name)); } } } // add a description of the files being compared if (0 < differences.Count) { differences.Insert(0, "Differences found while comparing:"); differences.Insert(1, expectedResult); differences.Insert(2, actualResult); } return differences; }
/// <summary> /// Compare two result files. /// </summary> /// <param name="expectedResult">The expected result file.</param> /// <param name="actualResult">The actual result file.</param> /// <param name="tables">The list of tables to compare</param> /// <returns>Any differences found.</returns> public static ArrayList CompareResults(string expectedResult, string actualResult, params string[] tables) { ArrayList differences = new ArrayList(); Output targetOutput; Output updatedOutput; expectedResult = Environment.ExpandEnvironmentVariables(expectedResult); actualResult = Environment.ExpandEnvironmentVariables(actualResult); OutputType outputType; string extension = Path.GetExtension(expectedResult); if (String.Compare(extension, ".msi", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Product; } else if (String.Compare(extension, ".msm", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Module; } else if (String.Compare(extension, ".msp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Patch; } else if (String.Compare(extension, ".mst", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Transform; } else if (String.Compare(extension, ".pcp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.PatchCreation; } else if (String.Compare(extension, ".wixout", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Unknown; } else { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot determine the type of msi database file based on file extension '{0}'.", extension)); } if (outputType != OutputType.Unknown) { Unbinder unbinder = new Unbinder(); unbinder.SuppressDemodularization = true; targetOutput = unbinder.Unbind(expectedResult, outputType, null); updatedOutput = unbinder.Unbind(actualResult, outputType, null); } else { targetOutput = Output.Load(expectedResult, false, false); updatedOutput = Output.Load(actualResult, false, false); } differences.AddRange(CompareOutput(targetOutput, updatedOutput, tables)); // If the Output type is a Patch, then compare the patch's transforms if (outputType == OutputType.Patch) { // Compare transforms foreach (SubStorage targetTransform in targetOutput.SubStorages) { SubStorage updatedTransform = null; // Find the same transform in the other patch foreach (SubStorage transform in updatedOutput.SubStorages) { if (transform.Name == targetTransform.Name) { updatedTransform = transform; break; } } if (null != updatedTransform) { // Both patch's have this transform ArrayList transformDifferences = Verifier.CompareOutput(targetTransform.Data, updatedTransform.Data); // add a description of the transforms being compared if (0 < transformDifferences.Count) { transformDifferences.Insert(0, String.Concat("Differences found while comparing the transform ", targetTransform.Name, " from the two patches")); differences.AddRange(transformDifferences); } } else { differences.Add(String.Format("The {0} tranform has been dropped", targetTransform.Name)); } } // Check if the updated patch has had transforms added foreach (SubStorage updatedTransform in updatedOutput.SubStorages) { SubStorage targetTransform = null; foreach (SubStorage transform in targetOutput.SubStorages) { if (transform.Name == updatedTransform.Name) { targetTransform = transform; break; } } if (targetTransform == null) { differences.Add(String.Format("The {0} tranform has been added", updatedTransform.Name)); } } } // add a description of the files being compared if (0 < differences.Count) { differences.Insert(0, "Differences found while comparing:"); differences.Insert(1, expectedResult); differences.Insert(2, actualResult); } return(differences); }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Decompiler decompiler = null; Mutator mutator = null; Unbinder unbinder = null; try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return(this.messageHandler.LastErrorNumber); } if (null == this.inputFile) { this.showHelp = true; } else if (null == this.outputFile) { if (null == this.outputDirectory) { this.outputFile = Path.ChangeExtension(Path.GetFileName(this.inputFile), ".wxs"); } else { this.outputFile = Path.Combine(this.outputDirectory, Path.ChangeExtension(Path.GetFileName(this.inputFile), ".wxs")); } } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(DarkStrings.HelpMessage); AppCommon.DisplayToolFooter(); return(this.messageHandler.LastErrorNumber); } foreach (string parameter in this.invalidArgs) { this.messageHandler.Display(this, WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; // create the decompiler and mutator decompiler = new Decompiler(); mutator = new Mutator(); mutator.Core = new HarvesterCore(new MessageEventHandler(this.messageHandler.Display)); unbinder = new Unbinder(); // read the configuration file (dark.exe.config) AppCommon.ReadConfiguration(this.extensionList); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); decompiler.AddExtension(wixExtension); unbinder.AddExtension(wixExtension); } // set options decompiler.SuppressCustomTables = this.suppressCustomTables; decompiler.SuppressDroppingEmptyTables = this.suppressDroppingEmptyTables; decompiler.SuppressRelativeActionSequencing = this.suppressRelativeActionSequencing; decompiler.SuppressUI = this.suppressUI; decompiler.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); if (!String.IsNullOrEmpty(this.exportBasePath)) { decompiler.ExportFilePath = this.exportBasePath; } unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); decompiler.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); // print friendly message saying what file is being decompiled Console.WriteLine(Path.GetFileName(this.inputFile)); // unbind // TODO: passing a bundle to the decompiler without the /x parameter specified stumbles here // as the exportBasePath will be null. Need a design decision whether to throw an // message below or throw a message here Output output = unbinder.Unbind(this.inputFile, this.outputType, this.exportBasePath); if (null != output) { if (OutputType.Patch == this.outputType || OutputType.Transform == this.outputType || this.outputXml) { output.Save(this.outputFile, null, new WixVariableResolver(), null); } else // decompile { Wix.Wix wix = decompiler.Decompile(output); // output if (null != wix) { XmlTextWriter writer = null; // mutate the Wix document if (!mutator.Mutate(wix)) { return(this.messageHandler.LastErrorNumber); } try { Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(this.outputFile))); writer = new XmlTextWriter(this.outputFile, System.Text.Encoding.UTF8); writer.Indentation = 4; writer.IndentChar = ' '; writer.QuoteChar = '"'; writer.Formatting = Formatting.Indented; writer.WriteStartDocument(); wix.OutputXml(writer); writer.WriteEndDocument(); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.FileWriteError(this.outputFile, e.Message)); return(this.messageHandler.LastErrorNumber); } finally { if (null != writer) { writer.Close(); } } } } } } catch (WixException we) { this.messageHandler.Display(this, we.Error); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != decompiler) { if (this.tidy) { if (!decompiler.DeleteTempFiles()) { Console.WriteLine(DarkStrings.WAR_FailedToDeleteTempDir, decompiler.TempFilesLocation); } } else { Console.WriteLine(DarkStrings.INF_TempDirLocatedAt, decompiler.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(DarkStrings.WAR_FailedToDeleteTempDir, unbinder.TempFilesLocation); } } else { Console.WriteLine(DarkStrings.INF_TempDirLocatedAt, unbinder.TempFilesLocation); } } } return(this.messageHandler.LastErrorNumber); }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Microsoft.Tools.WindowsInstallerXml.Binder binder = null; Differ differ = null; Unbinder unbinder = null; TempFileCollection tempFileCollection = null; try { // parse the command line this.ParseCommandLine(args); // validate the inputs if (this.xmlInputs && this.adminImage) { this.messageHandler.Display(this, WixErrors.IllegalCommandlineArgumentCombination("a", "xi")); this.showHelp = true; } string[] allValidExtensions = new string[] { wixMstExtension, wixOutExtension, wixPdbExtension, msiExtension }; string[] expectedSingleInputExtensions = new string[] { wixMstExtension, wixOutExtension }; string[] expectedDoubleInputXmlExtensions = new string[] { wixOutExtension, wixPdbExtension }; string[] expectedDoubleInputMsiExtensions = new string[] { msiExtension }; // Validate that all inputs have the correct extension and we dont have too many inputs. if (1 == this.inputFiles.Count) { string inputFile = this.inputFiles[0]; bool hasValidExtension = false; foreach (string extension in expectedSingleInputExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; break; } } if (!hasValidExtension) { bool missingInput = false; // Check if its using an extension that could be valid in other scenarios. foreach (string validExtension in allValidExtensions) { if (String.Equals(Path.GetExtension(inputFile), validExtension, StringComparison.OrdinalIgnoreCase)) { this.messageHandler.Display(this, WixErrors.WrongFileExtensionForNumberOfInputs(Path.GetExtension(inputFile), inputFile)); missingInput = true; break; } } if (!missingInput) { this.messageHandler.Display(this, WixErrors.UnexpectedFileExtension(inputFile, String.Join(", ", expectedSingleInputExtensions))); } } } else if (2 == this.inputFiles.Count) { foreach (string inputFile in inputFiles) { bool hasValidExtension = false; string[] expectedExtensions = allValidExtensions; if (this.xmlInputs) { foreach (string extension in expectedDoubleInputXmlExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; expectedExtensions = expectedDoubleInputXmlExtensions; break; } } } else { foreach (string extension in expectedDoubleInputMsiExtensions) { if (String.Equals(Path.GetExtension(inputFile), extension, StringComparison.OrdinalIgnoreCase)) { hasValidExtension = true; expectedExtensions = expectedDoubleInputMsiExtensions; break; } } } if (!hasValidExtension) { this.messageHandler.Display(this, WixErrors.UnexpectedFileExtension(inputFile, String.Join(", ", expectedExtensions))); } } } else { this.showHelp = true; } // exit if there was an error parsing the command line or with a file extension (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return this.messageHandler.LastErrorNumber; } if (null == this.outputFile) { this.showHelp = true; } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(TorchStrings.HelpMessage); AppCommon.DisplayToolFooter(); return this.messageHandler.LastErrorNumber; } foreach (string parameter in this.invalidArgs) { this.messageHandler.Display(this, WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; binder = new Microsoft.Tools.WindowsInstallerXml.Binder(); differ = new Differ(); unbinder = new Unbinder(); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); unbinder.AddExtension(wixExtension); binder.AddExtension(wixExtension); differ.AddExtension(wixExtension); } binder.Message += new MessageEventHandler(this.messageHandler.Display); differ.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); binder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); tempFileCollection = new TempFileCollection(Environment.GetEnvironmentVariable("WIX_TEMP")); binder.WixVariableResolver = new WixVariableResolver(); differ.PreserveUnchangedRows = this.preserveUnchangedRows; differ.ShowPedanticMessages = this.showPedanticMessages; unbinder.SuppressExtractCabinets = true; unbinder.IsAdminImage = this.adminImage; if (null == this.exportBasePath) { this.exportBasePath = tempFileCollection.BasePath; } // load and process the inputs Output transform; if (1 == this.inputFiles.Count) { transform = Output.Load(this.inputFiles[0], false, false); if (OutputType.Transform != transform.Type) { this.messageHandler.Display(this, WixErrors.InvalidWixTransform(this.inputFiles[0])); return this.messageHandler.LastErrorNumber; } } else // 2 inputs { Output targetOutput; Output updatedOutput; if (this.xmlInputs) { // load the target database if (String.Equals(Path.GetExtension(inputFiles[0]), wixPdbExtension, StringComparison.OrdinalIgnoreCase)) { Pdb targetPdb = Pdb.Load(this.inputFiles[0], false, false); targetOutput = targetPdb.Output; } else { targetOutput = Output.Load(this.inputFiles[0], false, false); } // load the updated database if (String.Equals(Path.GetExtension(inputFiles[1]), wixPdbExtension, StringComparison.OrdinalIgnoreCase)) { Pdb updatedPdb = Pdb.Load(this.inputFiles[1], false, false); updatedOutput = updatedPdb.Output; } else { updatedOutput = Output.Load(this.inputFiles[1], false, false); } this.xmlOutput = true; } else { // load the target database targetOutput = unbinder.Unbind(this.inputFiles[0], OutputType.Product, Path.Combine(this.exportBasePath, "targetBinaries")); // load the updated database updatedOutput = unbinder.Unbind(this.inputFiles[1], OutputType.Product, Path.Combine(this.exportBasePath, "updatedBinaries")); } // diff the target and updated databases transform = differ.Diff(targetOutput, updatedOutput, this.validationFlags); if (null == transform.Tables || 0 >= transform.Tables.Count) { throw new WixException(WixErrors.NoDifferencesInTransform(transform.SourceLineNumbers)); } } // output the transform if (null != transform) { // If either the user selected xml output or gave xml input, save as xml output. // With xml inputs, many funtions of the binder have not been performed on the inputs (ie. file sequencing). This results in bad IDT files which cannot be put in a transform. if (this.xmlOutput) { transform.Save(this.outputFile, null, null, tempFileCollection.BasePath); } else { binder.Bind(transform, this.outputFile); } } } catch (WixException we) { if (we is WixInvalidIdtException) { // make sure the IDT files stay around this.tidy = false; } this.messageHandler.Display(this, we.Error); } catch (Exception e) { // make sure the files stay around for debugging this.tidy = false; this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != binder) { if (this.tidy) { if (!binder.DeleteTempFiles()) { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, binder.TempFilesLocation); } } else { Console.WriteLine(TorchStrings.INF_BinderTempDirLocatedAt, binder.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, binder.TempFilesLocation); } } else { Console.WriteLine(TorchStrings.INF_UnbinderTempDirLocatedAt, binder.TempFilesLocation); } } if (null != tempFileCollection) { if (this.tidy) { try { Directory.Delete(tempFileCollection.BasePath, true); } catch (DirectoryNotFoundException) { // if the path doesn't exist, then there is nothing for us to worry about } catch { Console.WriteLine(TorchStrings.WAR_FailedToDeleteTempDir, tempFileCollection.BasePath); } } else { Console.WriteLine(TorchStrings.INF_TorchTempDirLocatedAt, tempFileCollection.BasePath); } } } return this.messageHandler.LastErrorNumber; }
/// <summary> /// Extracts files from a merge module and creates corresponding ComponentGroup WiX authoring. /// </summary> private void MeltModule() { Decompiler decompiler = null; Unbinder unbinder = null; Melter melter = null; try { // create the decompiler, unbinder, and melter decompiler = new Decompiler(); unbinder = new Unbinder(); melter = new Melter(decompiler, id); // read the configuration file (melt.exe.config) AppCommon.ReadConfiguration(this.extensionList); // load all extensions ExtensionManager extensionManager = new ExtensionManager(); foreach (string extension in this.extensionList) { extensionManager.Load(extension); } foreach (IDecompilerExtension extension in extensionManager.Create <IDecompilerExtension>()) { decompiler.AddExtension(extension); } foreach (IUnbinderExtension extension in extensionManager.Create <IUnbinderExtension>()) { unbinder.AddExtension(extension); } // set options decompiler.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.SuppressDemodularization = true; // print friendly message saying what file is being decompiled Console.WriteLine(Path.GetFileName(this.inputFile)); // unbind Output output = unbinder.Unbind(this.inputFile, this.outputType, this.exportBasePath); if (null != output) { Wix.Wix wix = melter.Melt(output); if (null != wix) { XmlTextWriter writer = null; try { writer = new XmlTextWriter(this.outputFile, System.Text.Encoding.UTF8); writer.Indentation = 4; writer.IndentChar = ' '; writer.QuoteChar = '"'; writer.Formatting = Formatting.Indented; writer.WriteStartDocument(); wix.OutputXml(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } } } finally { if (null != decompiler) { if (this.tidy) { if (!decompiler.DeleteTempFiles()) { Console.WriteLine(MeltStrings.WAR_FailedToDeleteTempDir, decompiler.TempFilesLocation); } } else { Console.WriteLine(MeltStrings.INF_TempDirLocatedAt, decompiler.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(MeltStrings.WAR_FailedToDeleteTempDir, unbinder.TempFilesLocation); } } else { Console.WriteLine(MeltStrings.INF_TempDirLocatedAt, unbinder.TempFilesLocation); } } } }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Decompiler decompiler = null; Mutator mutator = null; Unbinder unbinder = null; try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return this.messageHandler.LastErrorNumber; } if (null == this.inputFile) { this.showHelp = true; } else if (null == this.outputFile) { if (null == this.outputDirectory) { this.outputFile = Path.ChangeExtension(Path.GetFileName(this.inputFile), ".wxs"); } else { this.outputFile = Path.Combine(this.outputDirectory, Path.ChangeExtension(Path.GetFileName(this.inputFile), ".wxs")); } } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(DarkStrings.HelpMessage); AppCommon.DisplayToolFooter(); return this.messageHandler.LastErrorNumber; } foreach (string parameter in this.invalidArgs) { this.messageHandler.Display(this, WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; // create the decompiler and mutator decompiler = new Decompiler(); mutator = new Mutator(); mutator.Core = new HarvesterCore(new MessageEventHandler(this.messageHandler.Display)); unbinder = new Unbinder(); // read the configuration file (dark.exe.config) AppCommon.ReadConfiguration(this.extensionList); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); decompiler.AddExtension(wixExtension); unbinder.AddExtension(wixExtension); } // set options decompiler.SuppressCustomTables = this.suppressCustomTables; decompiler.SuppressDroppingEmptyTables = this.suppressDroppingEmptyTables; decompiler.SuppressRelativeActionSequencing = this.suppressRelativeActionSequencing; decompiler.SuppressUI = this.suppressUI; decompiler.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); if (!String.IsNullOrEmpty(this.exportBasePath)) { decompiler.ExportFilePath = this.exportBasePath; } unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); decompiler.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); // print friendly message saying what file is being decompiled Console.WriteLine(Path.GetFileName(this.inputFile)); // unbind // TODO: passing a bundle to the decompiler without the /x parameter specified stumbles here // as the exportBasePath will be null. Need a design decision whether to throw an // message below or throw a message here Output output = unbinder.Unbind(this.inputFile, this.outputType, this.exportBasePath); if (null != output) { if (OutputType.Patch == this.outputType || OutputType.Transform == this.outputType || this.outputXml) { output.Save(this.outputFile, null, new WixVariableResolver(), null); } else // decompile { Wix.Wix wix = decompiler.Decompile(output); // output if (null != wix) { XmlTextWriter writer = null; // mutate the Wix document if (!mutator.Mutate(wix)) { return this.messageHandler.LastErrorNumber; } try { Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(this.outputFile))); writer = new XmlTextWriter(this.outputFile, System.Text.Encoding.UTF8); writer.Indentation = 4; writer.IndentChar = ' '; writer.QuoteChar = '"'; writer.Formatting = Formatting.Indented; writer.WriteStartDocument(); wix.OutputXml(writer); writer.WriteEndDocument(); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.FileWriteError(this.outputFile, e.Message)); return this.messageHandler.LastErrorNumber; } finally { if (null != writer) { writer.Close(); } } } } } } catch (WixException we) { this.messageHandler.Display(this, we.Error); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != decompiler) { if (this.tidy) { if (!decompiler.DeleteTempFiles()) { Console.WriteLine(DarkStrings.WAR_FailedToDeleteTempDir, decompiler.TempFilesLocation); } } else { Console.WriteLine(DarkStrings.INF_TempDirLocatedAt, decompiler.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(DarkStrings.WAR_FailedToDeleteTempDir, unbinder.TempFilesLocation); } } else { Console.WriteLine(DarkStrings.INF_TempDirLocatedAt, unbinder.TempFilesLocation); } } } return this.messageHandler.LastErrorNumber; }
/// <summary> /// Compare two result files. /// </summary> /// <param name="expectedResult">The expected result file.</param> /// <param name="actualResult">The actual result file.</param> /// <returns>Any differences found.</returns> public static ArrayList CompareResults(string expectedResult, string actualResult) { ArrayList differences = new ArrayList(); Output targetOutput; Output updatedOutput; OutputType outputType; string extension = Path.GetExtension(expectedResult); if (String.Compare(extension, ".msi", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Product; } else if (String.Compare(extension, ".msm", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Module; } else if (String.Compare(extension, ".msp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Patch; } else if (String.Compare(extension, ".mst", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Transform; } else if (String.Compare(extension, ".pcp", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.PatchCreation; } else if (String.Compare(extension, ".wixout", true, CultureInfo.InvariantCulture) == 0) { outputType = OutputType.Unknown; } else { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot determine the type of msi database file based on file extension '{0}'.", extension)); } if (outputType != OutputType.Unknown) { Unbinder unbinder = new Unbinder(); unbinder.SuppressDemodularization = true; targetOutput = unbinder.Unbind(expectedResult, outputType, null); updatedOutput = unbinder.Unbind(actualResult, outputType, null); } else { targetOutput = Output.Load(expectedResult, false, false); updatedOutput = Output.Load(actualResult, false, false); } Differ differ = new Differ(); differ.SuppressKeepingSpecialRows = true; Output transform = differ.Diff(targetOutput, updatedOutput); foreach (Table table in transform.Tables) { switch (table.Operation) { case TableOperation.Add: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table has been added.", table.Name)); break; case TableOperation.Drop: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table has been dropped.", table.Name)); continue; } // index the target rows for better error messages Hashtable targetRows = new Hashtable(); Table targetTable = targetOutput.Tables[table.Name]; if (null != targetTable) { foreach (Row row in targetTable.Rows) { string primaryKey = row.GetPrimaryKey('/'); // only index rows with primary keys since these are the ones that can be modified if (null != primaryKey) { targetRows.Add(primaryKey, row); } } } foreach (Row row in table.Rows) { switch (row.Operation) { case RowOperation.Add: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has been added.", table.Name, row.ToString())); break; case RowOperation.Delete: differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has been deleted.", table.Name, row.ToString())); break; case RowOperation.Modify: if (("_SummaryInformation" != table.Name || (9 != (int)row[0] && 12 != (int)row[0] && 13 != (int)row[0] && 18 != (int)row[0])) && ("Property" != table.Name || "ProductCode" != (string)row[0])) { string primaryKey = row.GetPrimaryKey('/'); Row targetRow = (Row)targetRows[primaryKey]; differences.Add(String.Format(CultureInfo.InvariantCulture, "The {0} table, row '{1}' has changed to '{2}'.", table.Name, targetRow.ToString(), row.ToString())); } break; default: throw new InvalidOperationException("Unknown diff row."); } } } // add a description of the files being compared if (0 < differences.Count) { differences.Insert(0, "Differences found while comparing:"); differences.Insert(1, expectedResult); differences.Insert(2, actualResult); } return(differences); }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Decompiler decompiler = null; Mutator mutator = null; Unbinder unbinder = null; try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return(this.messageHandler.LastErrorNumber); } if (null == this.inputFile || null == this.outputFile) { this.showHelp = true; } if (this.showLogo) { Assembly darkAssembly = Assembly.GetExecutingAssembly(); Console.WriteLine("Microsoft (R) Windows Installer Xml Decompiler Version {0}", darkAssembly.GetName().Version.ToString()); Console.WriteLine("Copyright (C) Microsoft Corporation 2003. All rights reserved.\n"); Console.WriteLine(); } if (this.showHelp) { Console.WriteLine(" usage: dark.exe [-?] [-nologo] database.msi source.wxs"); Console.WriteLine(); Console.WriteLine(" -ext extension assembly or \"class, assembly\""); Console.WriteLine(" -nologo skip printing dark logo information"); Console.WriteLine(" -notidy do not delete temporary files (useful for debugging)"); Console.WriteLine(" -sdet suppress dropping empty tables (adds EnsureTable as appropriate)"); Console.WriteLine(" -sras suppress relative action sequencing (use explicit sequence numbers)"); Console.WriteLine(" -sui suppress decompiling UI-related tables"); Console.WriteLine(" -sw<N> suppress warning with specific message ID"); Console.WriteLine(" -v verbose output"); Console.WriteLine(" -wx treat warnings as errors"); Console.WriteLine(" -x <path> export binaries from cabinets and embedded binaries to the provided path"); Console.WriteLine(" -xo output xml instead of WiX source code (mandatory for transforms and patches)"); Console.WriteLine(" -? this help information"); Console.WriteLine(); Console.WriteLine("Environment variables:"); Console.WriteLine(" WIX_TEMP overrides the temporary directory used for cab extraction, binary extraction, ..."); Console.WriteLine(); Console.WriteLine("Common extensions:"); Console.WriteLine(" .wxi - Windows installer Xml Include file"); Console.WriteLine(" .wxl - Windows installer Xml Localization file"); Console.WriteLine(" .wxs - Windows installer Xml Source file"); Console.WriteLine(" .wixlib - Windows installer Xml Library file (in XML format)"); Console.WriteLine(" .wixobj - Windows installer Xml Object file (in XML format)"); Console.WriteLine(" .wixout - Windows installer Xml Output file (in XML format)"); Console.WriteLine(); Console.WriteLine(" .msi - Windows installer Product Database"); Console.WriteLine(" .msm - Windows installer Merge Module"); Console.WriteLine(" .msp - Windows installer Patch"); Console.WriteLine(" .mst - Windows installer Transform"); Console.WriteLine(" .pcp - Windows installer Patch Creation Package"); Console.WriteLine(); Console.WriteLine("For more information see: http://wix.sourceforge.net"); return(this.messageHandler.LastErrorNumber); } // create the decompiler and mutator decompiler = new Decompiler(); mutator = new Mutator(); unbinder = new Unbinder(); // read the configuration file (dark.exe.config) AppCommon.ReadConfiguration(this.extensionList); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); decompiler.AddExtension(wixExtension); unbinder.AddExtension(wixExtension); } // set options decompiler.SuppressDroppingEmptyTables = this.suppressDroppingEmptyTables; decompiler.SuppressRelativeActionSequencing = this.suppressRelativeActionSequencing; decompiler.SuppressUI = this.suppressUI; decompiler.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); decompiler.Message += new MessageEventHandler(this.messageHandler.Display); mutator.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); // print friendly message saying what file is being decompiled Console.WriteLine(Path.GetFileName(this.inputFile)); // unbind Output output = unbinder.Unbind(this.inputFile, this.outputType, this.exportBasePath); if (null != output) { if (OutputType.Patch == this.outputType || OutputType.Transform == this.outputType || this.outputXml) { output.Save(this.outputFile, null, new WixVariableResolver(), null); } else // decompile { Wix.Wix wix = decompiler.Decompile(output); // output if (null != wix) { XmlTextWriter writer = null; // mutate the Wix document if (!mutator.Mutate(wix)) { return(this.messageHandler.LastErrorNumber); } try { writer = new XmlTextWriter(this.outputFile, System.Text.Encoding.UTF8); writer.Indentation = 4; writer.IndentChar = ' '; writer.QuoteChar = '"'; writer.Formatting = Formatting.Indented; writer.WriteStartDocument(); wix.OutputXml(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } } } } catch (WixException we) { this.messageHandler.Display(this, we.Error); } catch (Exception e) { this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != decompiler) { if (this.tidy) { if (!decompiler.DeleteTempFiles()) { Console.WriteLine("Warning, failed to delete temporary directory: {0}", decompiler.TempFilesLocation); } } else { Console.WriteLine("Temporary directory located at '{0}'.", decompiler.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine("Warning, failed to delete temporary directory: {0}", unbinder.TempFilesLocation); } } else { Console.WriteLine("Temporary directory located at '{0}'.", unbinder.TempFilesLocation); } } } return(this.messageHandler.LastErrorNumber); }
/// <summary> /// Extracts files from a merge module and creates corresponding ComponentGroup WiX authoring. /// </summary> private void MeltModule() { Decompiler decompiler = null; Unbinder unbinder = null; Melter melter = null; try { // create the decompiler, unbinder, and melter decompiler = new Decompiler(); unbinder = new Unbinder(); melter = new Melter(decompiler, id); // read the configuration file (melt.exe.config) AppCommon.ReadConfiguration(this.extensionList); // load any extensions foreach (string extension in this.extensionList) { WixExtension wixExtension = WixExtension.Load(extension); decompiler.AddExtension(wixExtension); unbinder.AddExtension(wixExtension); } // set options decompiler.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.SuppressDemodularization = true; decompiler.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); melter.Message += new MessageEventHandler(this.messageHandler.Display); // print friendly message saying what file is being decompiled Console.WriteLine(Path.GetFileName(this.inputFile)); // unbind Output output = unbinder.Unbind(this.inputFile, this.outputType, this.exportBasePath); if (null != output) { Wix.Wix wix = melter.Melt(output); if (null != wix) { XmlTextWriter writer = null; try { writer = new XmlTextWriter(this.outputFile, System.Text.Encoding.UTF8); writer.Indentation = 4; writer.IndentChar = ' '; writer.QuoteChar = '"'; writer.Formatting = Formatting.Indented; writer.WriteStartDocument(); wix.OutputXml(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } } } finally { if (null != decompiler) { if (this.tidy) { if (!decompiler.DeleteTempFiles()) { Console.WriteLine(MeltStrings.WAR_FailedToDeleteTempDir, decompiler.TempFilesLocation); } } else { Console.WriteLine(MeltStrings.INF_TempDirLocatedAt, decompiler.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine(MeltStrings.WAR_FailedToDeleteTempDir, unbinder.TempFilesLocation); } } else { Console.WriteLine(MeltStrings.INF_TempDirLocatedAt, unbinder.TempFilesLocation); } } } }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { Microsoft.Tools.WindowsInstallerXml.Binder binder = null; Differ differ = null; Unbinder unbinder = null; TempFileCollection tempFileCollection = null; try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (this.messageHandler.EncounteredError) { return(this.messageHandler.LastErrorNumber); } // validate the inputs if (1 == this.inputFiles.Count) { // Validate that if its a single input, it is a wixout to be converted to an mst. if (0 != String.Compare(Path.GetExtension(this.inputFiles[0]), ".wixout", true, CultureInfo.InvariantCulture)) { this.showHelp = true; } } else if (2 == this.inputFiles.Count) { string expectedExtension = ".msi"; if (this.xmlInputs) { expectedExtension = ".wixout"; } // Validate that all inputs have the correct extension foreach (string inputFile in inputFiles) { if (0 != String.Compare(Path.GetExtension(inputFile), expectedExtension, true, CultureInfo.InvariantCulture)) { this.messageHandler.Display(this, WixErrors.UnexpectedFileExtension(this.inputFiles[0], expectedExtension)); this.showHelp = true; } } } else { this.showHelp = true; } if (null == this.outputFile) { this.showHelp = true; } if (this.showLogo) { Assembly torchAssembly = Assembly.GetExecutingAssembly(); Console.WriteLine("Microsoft (R) Windows Installer Xml Transform Builder Version {0}", torchAssembly.GetName().Version.ToString()); Console.WriteLine("Copyright (C) Microsoft Corporation 2003. All rights reserved.\n"); Console.WriteLine(); } if (this.showHelp) { Console.WriteLine(" usage: torch.exe [-?] [options] targetInput updatedInput -out outputFile"); Console.WriteLine(); Console.WriteLine(" -nologo skip printing logo information"); Console.WriteLine(" -notidy do not delete temporary files (useful for debugging)"); Console.WriteLine(" -p preserve unmodified content in the output"); Console.WriteLine(" -sw<N> suppress warning with specific message ID"); Console.WriteLine(" -v verbose output"); Console.WriteLine(" -wx treat warnings as errors"); Console.WriteLine(" -xi input xml instead of MSI format"); Console.WriteLine(" -xo output xml instead of MST format (set by default if -xi is present"); Console.WriteLine(" -? this help information"); Console.WriteLine(); Console.WriteLine("Environment variables:"); Console.WriteLine(" WIX_TEMP overrides the temporary directory used for cab extraction, binary extraction, ..."); Console.WriteLine(); Console.WriteLine("Common extensions:"); Console.WriteLine(" .wxi - Windows installer Xml Include file"); Console.WriteLine(" .wxl - Windows installer Xml Localization file"); Console.WriteLine(" .wxs - Windows installer Xml Source file"); Console.WriteLine(" .wixlib - Windows installer Xml Library file (in XML format)"); Console.WriteLine(" .wixobj - Windows installer Xml Object file (in XML format)"); Console.WriteLine(" .wixout - Windows installer Xml Output file (in XML format)"); Console.WriteLine(); Console.WriteLine(" .msi - Windows installer Product Database"); Console.WriteLine(" .msm - Windows installer Merge Module"); Console.WriteLine(" .msp - Windows installer Patch"); Console.WriteLine(" .mst - Windows installer Transform"); Console.WriteLine(" .pcp - Windows installer Patch Creation Package"); Console.WriteLine(); Console.WriteLine("For more information see: http://wix.sourceforge.net"); return(this.messageHandler.LastErrorNumber); } binder = new Microsoft.Tools.WindowsInstallerXml.Binder(); differ = new Differ(); unbinder = new Unbinder(); binder.Message += new MessageEventHandler(this.messageHandler.Display); differ.Message += new MessageEventHandler(this.messageHandler.Display); unbinder.Message += new MessageEventHandler(this.messageHandler.Display); binder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); unbinder.TempFilesLocation = Environment.GetEnvironmentVariable("WIX_TEMP"); tempFileCollection = new TempFileCollection(Environment.GetEnvironmentVariable("WIX_TEMP")); binder.WixVariableResolver = new WixVariableResolver(); differ.PreserveUnchangedRows = this.preserveUnchangedRows; unbinder.SuppressExtractCabinets = true; // load and process the inputs Output transform; if (1 == this.inputFiles.Count) { transform = Output.Load(this.inputFiles[0], false, false); if (OutputType.Transform != transform.Type) { this.messageHandler.Display(this, WixErrors.InvalidWixTransform(this.inputFiles[0])); return(this.messageHandler.LastErrorNumber); } } else // 2 inputs { Output targetOutput; Output updatedOutput; if (this.xmlInputs) { // load the target database targetOutput = Output.Load(this.inputFiles[0], false, false); // load the updated database updatedOutput = Output.Load(this.inputFiles[1], false, false); } else { // load the target database targetOutput = unbinder.Unbind(this.inputFiles[0], OutputType.Product, Path.Combine(tempFileCollection.BasePath, "targetBinaries")); // load the updated database updatedOutput = unbinder.Unbind(this.inputFiles[1], OutputType.Product, Path.Combine(tempFileCollection.BasePath, "updatedBinaries")); } // diff the target and updated databases transform = differ.Diff(targetOutput, updatedOutput); if (null == transform.Tables || 0 >= transform.Tables.Count) { throw new WixException(WixErrors.NoDifferencesInTransform(transform.SourceLineNumbers)); } } // output the transform if (null != transform) { // If either the user selected xml output or gave xml input, save as xml output. // With xml inputs, many funtions of the binder have not been performed on the inputs (ie. file sequencing). This results in bad IDT files which cannot be put in a transform. if (this.xmlOutput || this.xmlInputs) { transform.Save(this.outputFile, null, null, null); } else { binder.Bind(transform, this.outputFile); } } } catch (WixException we) { if (we is WixInvalidIdtException) { // make sure the IDT files stay around this.tidy = false; } this.messageHandler.Display(this, we.Error); } catch (Exception e) { // make sure the files stay around for debugging this.tidy = false; this.messageHandler.Display(this, WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } finally { if (null != binder) { if (this.tidy) { if (!binder.DeleteTempFiles()) { Console.WriteLine("Warning, failed to delete temporary directory: {0}", binder.TempFilesLocation); } } else { Console.WriteLine("Binder temporary directory located at '{0}'.", binder.TempFilesLocation); } } if (null != unbinder) { if (this.tidy) { if (!unbinder.DeleteTempFiles()) { Console.WriteLine("Warning, failed to delete temporary directory: {0}", binder.TempFilesLocation); } } else { Console.WriteLine("Unbinder temporary directory located at '{0}'.", binder.TempFilesLocation); } } if (null != tempFileCollection) { if (this.tidy) { try { Directory.Delete(tempFileCollection.BasePath, true); } catch { Console.WriteLine("Warning, failed to delete temporary directory: {0}", tempFileCollection.BasePath); } } else { Console.WriteLine("Torch temporary directory located at '{0}'.", tempFileCollection.BasePath); } } } return(this.messageHandler.LastErrorNumber); }