public void CanBuildSimpleModule() { var folder = TestData.Get(@"TestData\SimpleModule"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Module.wxs"), "-loc", Path.Combine(folder, "Module.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msm") }); result.AssertSuccess(); var msmPath = Path.Combine(intermediateFolder, @"bin\test.msm"); Assert.True(File.Exists(msmPath)); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb"))); var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); var dirSymbols = section.Symbols.OfType <DirectorySymbol>().OrderBy(d => d.Id.Id).ToList(); WixAssert.CompareLineByLine(new[] { "MergeRedirectFolder\tTARGETDIR\t.", "NotTheMergeRedirectFolder\tTARGETDIR\t.", "TARGETDIR\t\tSourceDir" }, dirSymbols.Select(d => String.Join("\t", d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray()); var fileSymbols = section.Symbols.OfType <FileSymbol>().OrderBy(d => d.Id.Id).ToList(); WixAssert.CompareLineByLine(new[] { $"File1\t{Path.Combine(folder, @"data\test.txt")}\ttest.txt", $"File2\t{Path.Combine(folder, @"data\test.txt")}\ttest.txt", }, fileSymbols.Select(fileSymbol => String.Join("\t", fileSymbol.Id.Id, fileSymbol[FileSymbolFields.Source].AsPath().Path, fileSymbol[FileSymbolFields.Source].PreviousValue.AsPath().Path)).ToArray()); var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); var fileRows = data.Tables["File"].Rows; Assert.Equal(new[] { "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE", }, fileRows.Select(r => r.FieldAsString(0)).ToArray()); var cabPath = Path.Combine(intermediateFolder, "msm-test.cab"); Query.ExtractStream(msmPath, "MergeModule.CABinet", cabPath); var files = Query.GetCabinetFiles(cabPath); Assert.Equal(new[] { "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE", }, files.Select(f => Path.Combine(f.Path, f.Name)).ToArray()); } }
public void CanBuildSetProperty() { var folder = TestData.Get(@"TestData\SetProperty"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(baseFolder, @"bin\test.msi") }); result.AssertSuccess(); var output = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb"), false); var caRows = output.Tables["CustomAction"].Rows.Single(); Assert.Equal("SetINSTALLLOCATION", caRows.FieldAsString(0)); Assert.Equal("51", caRows.FieldAsString(1)); Assert.Equal("INSTALLLOCATION", caRows.FieldAsString(2)); Assert.Equal("[INSTALLFOLDER]", caRows.FieldAsString(3)); } }
public void CanLoadPdbGeneratedByBuildViaWixOutput() { var folder = TestData.Get(@"TestData\MultiFileCompressed"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-d", "MediaTemplateCompressionLevel", "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msi") }); result.AssertSuccess(); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi"))); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\cab1.cab"))); var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb"); Assert.True(File.Exists(pdbPath)); var wixOutput = WixOutput.Read(pdbPath); var output = WindowsInstallerData.Load(wixOutput, suppressVersionCheck: true); Assert.NotNull(output); } }
public CopyTransformDataCommand(IMessaging messaging, WindowsInstallerData output, TableDefinitionCollection tableDefinitions, bool copyOutFileRows) { this.Messaging = messaging; this.Output = output; this.TableDefinitions = tableDefinitions; this.CopyOutFileRows = copyOutFileRows; }
public CreateInstanceTransformsCommand(IntermediateSection section, WindowsInstallerData output, TableDefinitionCollection tableDefinitions, IBackendHelper backendHelper) { this.Section = section; this.Output = output; this.TableDefinitions = tableDefinitions; this.BackendHelper = backendHelper; }
public ModularizeCommand(WindowsInstallerData output, string modularizationSuffix, IEnumerable <WixSuppressModularizationSymbol> suppressSymbols) { this.Output = output; this.ModularizationSuffix = modularizationSuffix; // Gather all the unique suppress modularization identifiers. this.SuppressModularizationIdentifiers = new HashSet <string>(suppressSymbols.Select(s => s.SuppressIdentifier)); }
/// <summary> /// Instantiates a new Differ class. /// </summary> public GenerateTransformCommand(IMessaging messaging, WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, bool preserveUnchangedRows, bool showPedanticMessages) { this.messaging = messaging; this.TargetOutput = targetOutput; this.UpdatedOutput = updatedOutput; this.PreserveUnchangedRows = preserveUnchangedRows; this.ShowPedanticMessages = showPedanticMessages; }
public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable <SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable <FileFacade> fileFacades) { this.Messaging = messaging; this.Output = output; this.SubStorages = subStorages; this.TableDefinitions = tableDefinitions; this.FileFacades = fileFacades; }
/// <summary> /// Generates the WixFile table based on a path to an admin image msi and an Output. /// </summary> /// <param name="databaseFile">The path to the msi database file in an admin image.</param> /// <param name="output">The Output that represents the msi database.</param> private void GenerateWixFileTable(string databaseFile, WindowsInstallerData output) { throw new NotImplementedException(); #if TODO_FIX_UNBINDING_FILES var adminRootPath = Path.GetDirectoryName(databaseFile); var componentDirectoryIndex = new Hashtable(); var componentTable = output.Tables["Component"]; foreach (var row in componentTable.Rows) { componentDirectoryIndex.Add(row[0], row[2]); } // Index full source paths for all directories var directoryDirectoryParentIndex = new Hashtable(); var directoryFullPathIndex = new Hashtable(); var directorySourceNameIndex = new Hashtable(); var directoryTable = output.Tables["Directory"]; foreach (var row in directoryTable.Rows) { directoryDirectoryParentIndex.Add(row[0], row[1]); if (null == row[1]) { directoryFullPathIndex.Add(row[0], adminRootPath); } else { directorySourceNameIndex.Add(row[0], GetAdminSourceName((string)row[2])); } } foreach (DictionaryEntry directoryEntry in directoryDirectoryParentIndex) { if (!directoryFullPathIndex.ContainsKey(directoryEntry.Key)) { this.GetAdminFullPath((string)directoryEntry.Key, directoryDirectoryParentIndex, directorySourceNameIndex, directoryFullPathIndex); } } var fileTable = output.Tables["File"]; var wixFileTable = output.EnsureTable(this.TableDefinitions["WixFile"]); foreach (var row in fileTable.Rows) { var wixFileRow = new WixFileRow(null, this.TableDefinitions["WixFile"]); wixFileRow.File = (string)row[0]; wixFileRow.Directory = (string)componentDirectoryIndex[(string)row[1]]; wixFileRow.Source = Path.Combine((string)directoryFullPathIndex[wixFileRow.Directory], GetAdminSourceName((string)row[2])); if (!File.Exists(wixFileRow.Source)) { throw new WixException(ErrorMessages.WixFileNotFound(wixFileRow.Source)); } wixFileTable.Rows.Add(wixFileRow); } #endif }
public ExtractCabinetsCommand(WindowsInstallerData output, Database database, string inputFilePath, string exportBasePath, string intermediateFolder, bool treatOutputAsModule = false) { this.Output = output; this.Database = database; this.InputFilePath = inputFilePath; this.ExportBasePath = exportBasePath; this.IntermediateFolder = intermediateFolder; this.TreatOutputAsModule = treatOutputAsModule; }
public Row CreateRow(IntermediateSection section, IntermediateSymbol symbol, WindowsInstallerData output, TableDefinition tableDefinition) { var table = output.EnsureTable(tableDefinition); var row = table.CreateRow(symbol.SourceLineNumbers); row.SectionId = section.Id; return row; }
private WindowsInstallerData GetWindowsInstallerData() { if (this.WiData == null) { using var wixOutput = WixOutput.Read(this.PackagePdb); this.WiData = WindowsInstallerData.Load(wixOutput); } return(this.WiData); }
public void CanBuildWithDefaultProductLanguage() { var folder = TestData.Get(@"TestData", "Language"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), "-loc", Path.Combine(folder, "Package.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", Path.Combine(baseFolder, "obj"), "-o", Path.Combine(baseFolder, @"bin\test.msi") }); result.AssertSuccess(); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); var directorySymbols = section.Symbols.OfType <DirectorySymbol>(); WixAssert.CompareLineByLine(new[] { "INSTALLFOLDER:Example Corporation\\MsiPackage", "ProgramFilesFolder:PFiles", "TARGETDIR:SourceDir" }, directorySymbols.OrderBy(s => s.Id.Id).Select(s => s.Id.Id + ":" + s.Name).ToArray()); var propertySymbol = section.Symbols.OfType <PropertySymbol>().Single(p => p.Id.Id == "ProductLanguage"); Assert.Equal("0", propertySymbol.Value); var summaryPlatform = section.Symbols.OfType <SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage); Assert.Equal("Intel;0", summaryPlatform.Value); var summaryCodepage = section.Symbols.OfType <SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.Codepage); Assert.Equal("1252", summaryCodepage.Value); var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var directoryRows = data.Tables["Directory"].Rows; WixAssert.CompareLineByLine(new[] { "d4EceYatXTyy8HXPt5B6DT9Rj.wE:u7-b4gch|Example Corporation", "INSTALLFOLDER:oekcr5lq|MsiPackage", "ProgramFilesFolder:PFiles", "TARGETDIR:SourceDir" }, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(2)).ToArray()); } }
public void CanBuildSimpleModule() { var folder = TestData.Get(@"TestData\SimpleModule"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Module.wxs"), "-loc", Path.Combine(folder, "Module.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msm") }); result.AssertSuccess(); var msmPath = Path.Combine(intermediateFolder, @"bin\test.msm"); Assert.True(File.Exists(msmPath)); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb"))); var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); var fileSymbol = section.Symbols.OfType <FileSymbol>().Single(); Assert.Equal("filyIq8rqcxxf903Hsn5K9L0SWV73g", fileSymbol.Id.Id); Assert.Equal(Path.Combine(folder, @"data\test.txt"), fileSymbol[FileSymbolFields.Source].AsPath().Path); Assert.Equal(@"test.txt", fileSymbol[FileSymbolFields.Source].PreviousValue.AsPath().Path); var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); var fileRows = data.Tables["File"].Rows; Assert.Equal(new[] { "filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE" }, fileRows.Select(r => r.FieldAsString(0)).ToArray()); var cabPath = Path.Combine(intermediateFolder, "msm-test.cab"); Query.ExtractStream(msmPath, "MergeModule.CABinet", cabPath); var files = Query.GetCabinetFiles(cabPath); Assert.Equal(new[] { "filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE" }, files.Select(f => Path.Combine(f.Path, f.Name)).ToArray()); } }
public void CanBuildInstanceTransform() { var folder = TestData.Get(@"TestData\InstanceTransform"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msi") }); result.AssertSuccess(); var output = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb"), false); var substorage = output.SubStorages.Single(); Assert.Equal("I1", substorage.Name); var data = substorage.Data; Assert.Equal(new[] { "_SummaryInformation", "Property", "Upgrade" }, data.Tables.Select(t => t.Name).ToArray()); Assert.Equal(new[] { "INSTANCEPROPERTY\tI1", "ProductName\tMsiPackage (Instance 1)", }, JoinRows(data.Tables["Property"])); Assert.Equal(new[] { "{047730A5-30FE-4A62-A520-DA9381B8226A}\t\t1.0.0.0\t1033\t1\t\tWIX_UPGRADE_DETECTED", "{047730A5-30FE-4A62-A520-DA9381B8226A}\t\t1.0.0.0\t1033\t1\t0\t0", "{047730A5-30FE-4A62-A520-DA9381B8226A}\t1.0.0.0\t\t1033\t2\t\tWIX_DOWNGRADE_DETECTED", "{047730A5-30FE-4A62-A520-DA9381B8226A}\t1.0.0.0\t\t1033\t2\t0\t0" }, JoinRows(data.Tables["Upgrade"])); } }
public PackageInstaller(WixTestContext testContext, string filename) { this.Package = Path.Combine(testContext.TestDataFolder, $"{filename}.msi"); this.PackagePdb = Path.Combine(testContext.TestDataFolder, $"{filename}.wixpdb"); this.TestContext = testContext; using var wixOutput = WixOutput.Read(this.PackagePdb); var intermediate = Intermediate.Load(wixOutput); var section = intermediate.Sections.Single(); var platformSummary = section.Symbols.OfType <SummaryInformationSymbol>().Single(s => s.PropertyId == SummaryInformationType.PlatformAndLanguage); var platformString = platformSummary.Value.Split(new char[] { ';' }, 2)[0]; this.IsX64 = platformString != "Intel"; this.WiData = WindowsInstallerData.Load(wixOutput); }
public void CanGetWithMultiNestedSubdirectory() { var folder = TestData.Get(@"TestData"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); var result = WixRunner.Execute(new[] { "build", "-arch", "x64", Path.Combine(folder, "Directory", "Nested.wxs"), Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"), "-bindpath", Path.Combine(folder, "SingleFile", "data"), "-intermediateFolder", intermediateFolder, "-o", msiPath }); result.AssertSuccess(); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); var dirSymbols = section.Symbols.OfType <WixToolset.Data.Symbols.DirectorySymbol>().ToList(); Assert.Equal(new[] { "BinFolder:ProgramFilesFolder:Example Corporation\\Test Product\\bin", "ProgramFilesFolder:TARGETDIR:PFiles", "TARGETDIR::SourceDir" }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray()); var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var directoryRows = data.Tables["Directory"].Rows; Assert.Equal(new[] { "d4EceYatXTyy8HXPt5B6DT9Rj.wE:ProgramFilesFolder:u7-b4gch|Example Corporation", "dSJ1pgiASlW7kJTu0wqsGBklJsS0:d4EceYatXTyy8HXPt5B6DT9Rj.wE:vjj-gxay|Test Product", "BinFolder:dSJ1pgiASlW7kJTu0wqsGBklJsS0:bin", "ProgramFilesFolder:TARGETDIR:PFiles", "TARGETDIR::SourceDir" }, directoryRows.Select(r => r.FieldAsString(0) + ":" + r.FieldAsString(1) + ":" + r.FieldAsString(2)).ToArray()); } }
public void CanMergeModule() { var folder = TestData.Get(@"TestData\SimpleMerge"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var msiPath = Path.Combine(intermediateFolder, @"bin\test.msi"); var cabPath = Path.Combine(intermediateFolder, @"bin\cab1.cab"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, ".data"), "-intermediateFolder", intermediateFolder, "-o", msiPath }); result.AssertSuccess(); Assert.True(File.Exists(msiPath)); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb"))); var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); Assert.Empty(section.Symbols.OfType <FileSymbol>()); var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); Assert.Null(data.Tables["File"]); var results = Query.QueryDatabase(msiPath, new[] { "File" }); Assert.Equal(new[] { "File:filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent.243FB739_4D05_472F_9CFB_EF6B1017B6DE\ttest.txt\t17\t\t\t512\t0" }, results); var files = Query.GetCabinetFiles(cabPath); Assert.Equal(new[] { "filyIq8rqcxxf903Hsn5K9L0SWV73g.243FB739_4D05_472F_9CFB_EF6B1017B6DE" }, files.Select(f => f.Name).ToArray()); } }
public void CanGetDefaultName() { var folder = TestData.Get(@"TestData"); using (var fs = new DisposableFileSystem()) { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Directory", "DefaultName.wxs"), Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"), "-bindpath", Path.Combine(folder, "SingleFile", "data"), "-intermediateFolder", intermediateFolder, "-o", msiPath }); result.AssertSuccess(); var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var section = intermediate.Sections.Single(); var dirSymbols = section.Symbols.OfType <WixToolset.Data.Symbols.DirectorySymbol>().ToList(); WixAssert.CompareLineByLine(new[] { "BinFolder\tCompanyFolder\t.", "CompanyFolder\tProgramFilesFolder\tExample Corporation", "ProgramFilesFolder\tTARGETDIR\tPFiles", "TARGETDIR\t\tSourceDir" }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray()); var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); var directoryRows = data.Tables["Directory"].Rows; WixAssert.CompareLineByLine(new[] { "BinFolder\tCompanyFolder\t.", "CompanyFolder\tProgramFilesFolder\tu7-b4gch|Example Corporation", "ProgramFilesFolder\tTARGETDIR\tPFiles", "TARGETDIR\t\tSourceDir" }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray()); } }
public void CanBuildManualUpgrade() { var folder = TestData.Get(@"TestData\ManualUpgrade"); using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(); var result = WixRunner.Execute(new[] { "build", Path.Combine(folder, "Package.wxs"), Path.Combine(folder, "PackageComponents.wxs"), "-loc", Path.Combine(folder, "Package.en-us.wxl"), "-bindpath", Path.Combine(folder, "data"), "-intermediateFolder", intermediateFolder, "-o", Path.Combine(intermediateFolder, @"bin\test.msi") }, out var messages); Assert.Equal(0, result); var pdbPath = Path.Combine(intermediateFolder, @"bin\test.wixpdb"); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi"))); Assert.True(File.Exists(pdbPath)); Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\MsiPackage\test.txt"))); var intermediate = Intermediate.Load(pdbPath); var section = intermediate.Sections.Single(); var upgradeSymbol = section.Symbols.OfType <UpgradeSymbol>().Single(); Assert.False(upgradeSymbol.ExcludeLanguages); Assert.True(upgradeSymbol.IgnoreRemoveFailures); Assert.False(upgradeSymbol.VersionMaxInclusive); Assert.True(upgradeSymbol.VersionMinInclusive); Assert.Equal("13.0.0", upgradeSymbol.VersionMax); Assert.Equal("12.0.0", upgradeSymbol.VersionMin); Assert.False(upgradeSymbol.OnlyDetect); Assert.Equal("BLAHBLAHBLAH", upgradeSymbol.ActionProperty); var pdb = WindowsInstallerData.Load(pdbPath, suppressVersionCheck: false); var secureProperties = pdb.Tables["Property"].Rows.Where(row => row.GetKey() == "SecureCustomProperties").Single(); Assert.Contains("BLAHBLAHBLAH", secureProperties.FieldAsString(1)); } }
private WindowsInstallerData GetData(string path) { var ext = Path.GetExtension(path); if (".msi".Equals(ext, StringComparison.OrdinalIgnoreCase)) { using (var database = new Database(path, OpenDatabase.ReadOnly)) { var exportBasePath = Path.Combine(this.IntermediateFolder, "_msi"); // TODO: come up with a better path. var isAdminImage = false; // TODO: need a better way to set this var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, database, path, OutputType.Product, exportBasePath, this.IntermediateFolder, isAdminImage, suppressDemodularization: true, skipSummaryInfo: true); return(command.Execute()); } } else // assume .wixpdb (or .wixout) { var data = WindowsInstallerData.Load(path, true); return(data); } }
/// <summary> /// See <see cref="IWindowsInstallerBackendBinderExtension.TryProcessSymbol(IntermediateSection, IntermediateSymbol, WindowsInstallerData, TableDefinitionCollection)"/> /// </summary> public virtual bool TryProcessSymbol(IntermediateSection section, IntermediateSymbol symbol, WindowsInstallerData data, TableDefinitionCollection tableDefinitions) { if (this.TableDefinitions.Any(t => t.SymbolDefinition == symbol.Definition)) { return(this.BackendHelper.TryAddSymbolToMatchingTableDefinitions(section, symbol, data, tableDefinitions)); } return(false); }
private void GenerateDatabase(WindowsInstallerData output, string databaseFile) { var command = new GenerateDatabaseCommand(this.Messaging, null, null, output, databaseFile, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns: true, suppressAddingValidationRows: true, useSubdirectory: false); command.Execute(); }
public WindowsInstallerData Execute() { var transform = new WindowsInstallerData(new SourceLineNumber(this.TransformFile)); transform.Type = OutputType.Transform; // get the summary information table using (var summaryInformation = new SummaryInformation(this.TransformFile)) { var table = transform.EnsureTable(this.TableDefinitions["_SummaryInformation"]); for (var i = 1; 19 >= i; i++) { var value = summaryInformation.GetProperty(i); if (0 < value.Length) { var row = table.CreateRow(transform.SourceLineNumbers); row[0] = i; row[1] = value; } } } // create a schema msi which hopefully matches the table schemas in the transform var schemaOutput = new WindowsInstallerData(null); var msiDatabaseFile = Path.Combine(this.IntermediateFolder, "schema.msi"); foreach (var tableDefinition in this.TableDefinitions) { // skip unreal tables and the Patch table if (!tableDefinition.Unreal && "Patch" != tableDefinition.Name) { schemaOutput.EnsureTable(tableDefinition); } } var addedRows = new Dictionary <string, Row>(); Table transformViewTable; // Bind the schema msi. this.GenerateDatabase(schemaOutput, msiDatabaseFile); // apply the transform to the database and retrieve the modifications using (var msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) { // apply the transform with the ViewTransform option to collect all the modifications msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform); // unbind the database var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); var transformViewOutput = unbindCommand.Execute(); // index the added and possibly modified rows (added rows may also appears as modified rows) transformViewTable = transformViewOutput.Tables["_TransformView"]; var modifiedRows = new Hashtable(); foreach (var row in transformViewTable.Rows) { var tableName = (string)row[0]; var columnName = (string)row[1]; var primaryKeys = (string)row[2]; if ("INSERT" == columnName) { var index = String.Concat(tableName, ':', primaryKeys); addedRows.Add(index, null); } else if ("CREATE" != columnName && "DELETE" != columnName && "DROP" != columnName && null != primaryKeys) // modified row { var index = String.Concat(tableName, ':', primaryKeys); modifiedRows[index] = row; } } // create placeholder rows for modified rows to make the transform insert the updated values when its applied foreach (Row row in modifiedRows.Values) { var tableName = (string)row[0]; var columnName = (string)row[1]; var primaryKeys = (string)row[2]; var index = String.Concat(tableName, ':', primaryKeys); // ignore information for added rows if (!addedRows.ContainsKey(index)) { var table = schemaOutput.Tables[tableName]; this.CreateRow(table, primaryKeys, true); } } } // Re-bind the schema output with the placeholder rows. this.GenerateDatabase(schemaOutput, msiDatabaseFile); // apply the transform to the database and retrieve the modifications using (var msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact)) { try { // apply the transform msiDatabase.ApplyTransform(this.TransformFile, TransformErrorConditions.All); // commit the database to guard against weird errors with streams msiDatabase.Commit(); } catch (Win32Exception ex) { if (0x65B == ex.NativeErrorCode) { // this commonly happens when the transform was built // against a database schema different from the internal // table definitions throw new WixException(ErrorMessages.TransformSchemaMismatch()); } } // unbind the database var unbindCommand = new UnbindDatabaseCommand(this.Messaging, msiDatabase, msiDatabaseFile, OutputType.Product, this.ExportBasePath, this.IntermediateFolder, false, false, skipSummaryInfo: true); var output = unbindCommand.Execute(); // index all the rows to easily find modified rows var rows = new Dictionary <string, Row>(); foreach (var table in output.Tables) { foreach (var row in table.Rows) { rows.Add(String.Concat(table.Name, ':', row.GetPrimaryKey('\t', " ")), row); } } // process the _TransformView rows into transform rows foreach (var row in transformViewTable.Rows) { var tableName = (string)row[0]; var columnName = (string)row[1]; var primaryKeys = (string)row[2]; var table = transform.EnsureTable(this.TableDefinitions[tableName]); if ("CREATE" == columnName) // added table { table.Operation = TableOperation.Add; } else if ("DELETE" == columnName) // deleted row { var deletedRow = this.CreateRow(table, primaryKeys, false); deletedRow.Operation = RowOperation.Delete; } else if ("DROP" == columnName) // dropped table { table.Operation = TableOperation.Drop; } else if ("INSERT" == columnName) // added row { var index = String.Concat(tableName, ':', primaryKeys); var addedRow = rows[index]; addedRow.Operation = RowOperation.Add; table.Rows.Add(addedRow); } else if (null != primaryKeys) // modified row { var index = String.Concat(tableName, ':', primaryKeys); // the _TransformView table includes information for added rows // that looks like modified rows so it sometimes needs to be ignored if (!addedRows.ContainsKey(index)) { var modifiedRow = rows[index]; // mark the field as modified var indexOfModifiedValue = -1; for (var i = 0; i < modifiedRow.TableDefinition.Columns.Length; ++i) { if (columnName.Equals(modifiedRow.TableDefinition.Columns[i].Name, StringComparison.Ordinal)) { indexOfModifiedValue = i; break; } } modifiedRow.Fields[indexOfModifiedValue].Modified = true; // move the modified row into the transform the first time its encountered if (RowOperation.None == modifiedRow.Operation) { modifiedRow.Operation = RowOperation.Modify; table.Rows.Add(modifiedRow); } } } else // added column { var column = table.Definition.Columns.Single(c => c.Name.Equals(columnName, StringComparison.Ordinal)); column.Added = true; } } } return(transform); }
public WindowsInstallerData Execute() { this.exportedFiles = new List <string>(); string modularizationGuid = null; var output = new WindowsInstallerData(new SourceLineNumber(this.DatabasePath)); View validationView = null; // set the output type output.Type = this.OutputType; Directory.CreateDirectory(this.IntermediateFolder); // get the codepage this.Database.Export("_ForceCodepage", this.IntermediateFolder, "_ForceCodepage.idt"); using (var sr = File.OpenText(Path.Combine(this.IntermediateFolder, "_ForceCodepage.idt"))) { string line; while (null != (line = sr.ReadLine())) { var data = line.Split('\t'); if (2 == data.Length) { output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture); } } } // get the summary information table if it exists; it won't if unbinding a transform if (!this.SkipSummaryInfo) { using (var summaryInformation = new SummaryInformation(this.Database)) { var table = new Table(this.TableDefinitions["_SummaryInformation"]); for (var i = 1; 19 >= i; i++) { var value = summaryInformation.GetProperty(i); if (0 < value.Length) { var row = table.CreateRow(output.SourceLineNumbers); row[0] = i; row[1] = value; } } output.Tables.Add(table); } } try { // open a view on the validation table if it exists if (this.Database.TableExists("_Validation")) { validationView = this.Database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?"); } // get the normal tables using (var tablesView = this.Database.OpenExecuteView("SELECT * FROM _Tables")) { foreach (var tableRecord in tablesView.Records) { var tableName = tableRecord.GetString(1); using (var tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) { var tableDefinition = this.GetTableDefinition(tableName, tableView, validationView); var table = new Table(tableDefinition); foreach (var rowRecord in tableView.Records) { var recordCount = rowRecord.GetFieldCount(); var row = table.CreateRow(output.SourceLineNumbers); for (var i = 0; recordCount > i && row.Fields.Length > i; i++) { if (rowRecord.IsNull(i + 1)) { if (!row.Fields[i].Column.Nullable) { // TODO: display an error for a null value in a non-nullable field OR // display a warning and put an empty string in the value to let the compiler handle it // (the second option is risky because the later code may make certain assumptions about // the contents of a row value) } } else { switch (row.Fields[i].Column.Type) { case ColumnType.Number: var success = false; var intValue = rowRecord.GetInteger(i + 1); if (row.Fields[i].Column.IsLocalizable) { success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); } else { success = row.BestEffortSetField(i, intValue); } if (!success) { this.Messaging.Write(WarningMessages.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); } break; case ColumnType.Object: var sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; if (null != this.ExportBasePath) { var relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile); // ensure the parent directory exists System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); using (var fs = System.IO.File.Create(sourceFile)) { int bytesRead; var buffer = new byte[512]; while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } this.exportedFiles.Add(sourceFile); } row[i] = sourceFile; break; default: var value = rowRecord.GetString(i + 1); switch (row.Fields[i].Column.Category) { case ColumnCategory.Guid: value = value.ToUpper(CultureInfo.InvariantCulture); break; } // de-modularize if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) { var modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); if (null == modularizationGuid) { var match = modularization.Match(value); if (match.Success) { modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); } } value = modularization.Replace(value, String.Empty); } // escape "$(" for the preprocessor value = value.Replace("$(", "$$("); // escape things that look like wix variables // TODO: Evaluate this requirement. //var matches = Common.WixVariableRegex.Matches(value); //for (var j = matches.Count - 1; 0 <= j; j--) //{ // value = value.Insert(matches[j].Index, "!"); //} row[i] = value; break; } } } } output.Tables.Add(table); } } } } finally { if (null != validationView) { validationView.Close(); } } // set the modularization guid as the PackageCode if (null != modularizationGuid) { var table = output.Tables["_SummaryInformation"]; foreach (var row in table.Rows) { if (9 == (int)row[0]) // PID_REVNUMBER { row[1] = modularizationGuid; } } } if (this.IsAdminImage) { this.GenerateWixFileTable(this.DatabasePath, output); this.GenerateSectionIds(output); } return(output); }
/// <summary> /// Creates section ids on rows which form logical groupings of resources. /// </summary> /// <param name="output">The Output that represents the msi database.</param> private void GenerateSectionIds(WindowsInstallerData output) { // First assign and index section ids for the tables that are in their own sections. this.AssignSectionIdsToTable(output.Tables["Binary"], 0); var componentSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["Component"], 0); var customActionSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["CustomAction"], 0); this.AssignSectionIdsToTable(output.Tables["Directory"], 0); var featureSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["Feature"], 0); this.AssignSectionIdsToTable(output.Tables["Icon"], 0); var digitalCertificateSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["MsiDigitalCertificate"], 0); this.AssignSectionIdsToTable(output.Tables["Property"], 0); // Now handle all the tables that rely on the first set of indexes but also produce their own indexes. Order matters here. var fileSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["File"], componentSectionIdIndex, 1, 0); var appIdSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Class"], componentSectionIdIndex, 2, 5); var odbcDataSourceSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDataSource"], componentSectionIdIndex, 1, 0); var odbcDriverSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDriver"], componentSectionIdIndex, 1, 0); var registrySectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Registry"], componentSectionIdIndex, 5, 0); var serviceInstallSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ServiceInstall"], componentSectionIdIndex, 11, 0); // Now handle all the tables which only rely on previous indexes and order does not matter. foreach (var table in output.Tables) { switch (table.Name) { case "WixFile": case "MsiFileHash": ConnectTableToSection(table, fileSectionIdIndex, 0); break; case "MsiAssembly": case "MsiAssemblyName": ConnectTableToSection(table, componentSectionIdIndex, 0); break; case "MsiPackageCertificate": case "MsiPatchCertificate": ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1); break; case "CreateFolder": case "FeatureComponents": case "MoveFile": case "ReserveCost": case "ODBCTranslator": ConnectTableToSection(table, componentSectionIdIndex, 1); break; case "TypeLib": ConnectTableToSection(table, componentSectionIdIndex, 2); break; case "Shortcut": case "Environment": ConnectTableToSection(table, componentSectionIdIndex, 3); break; case "RemoveRegistry": ConnectTableToSection(table, componentSectionIdIndex, 4); break; case "ServiceControl": ConnectTableToSection(table, componentSectionIdIndex, 5); break; case "IniFile": case "RemoveIniFile": ConnectTableToSection(table, componentSectionIdIndex, 7); break; case "AppId": ConnectTableToSection(table, appIdSectionIdIndex, 0); break; case "Condition": ConnectTableToSection(table, featureSectionIdIndex, 0); break; case "ODBCSourceAttribute": ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0); break; case "ODBCAttribute": ConnectTableToSection(table, odbcDriverSectionIdIndex, 0); break; case "AdminExecuteSequence": case "AdminUISequence": case "AdvtExecuteSequence": case "AdvtUISequence": case "InstallExecuteSequence": case "InstallUISequence": ConnectTableToSection(table, customActionSectionIdIndex, 0); break; case "LockPermissions": case "MsiLockPermissions": foreach (var row in table.Rows) { var lockObject = (string)row[0]; var tableName = (string)row[1]; switch (tableName) { case "File": row.SectionId = (string)fileSectionIdIndex[lockObject]; break; case "Registry": row.SectionId = (string)registrySectionIdIndex[lockObject]; break; case "ServiceInstall": row.SectionId = (string)serviceInstallSectionIdIndex[lockObject]; break; } } break; } } // Now pass the output to each unbinder extension to allow them to analyze the output and determine thier proper section ids. //foreach (IUnbinderExtension extension in this.unbinderExtensions) //{ // extension.GenerateSectionIds(output); //} }
private WixOutput CreateWixout(List <ITrackedFile> trackedFiles, Intermediate intermediate, WindowsInstallerData output) { WixOutput wixout; if (String.IsNullOrEmpty(this.OutputPdbPath)) { wixout = WixOutput.Create(); } else { var trackPdb = this.BackendHelper.TrackFile(this.OutputPdbPath, TrackedFileType.Final); trackedFiles.Add(trackPdb); wixout = WixOutput.Create(trackPdb.Path); } intermediate.Save(wixout); output.Save(wixout); wixout.Reopen(); return(wixout); }
public void Execute() { var transformFlags = 0; var targetOutput = new WindowsInstallerData(null); var updatedOutput = new WindowsInstallerData(null); // TODO: handle added columns // to generate a localized transform, both the target and updated // databases need to have the same code page. the only reason to // set different code pages is to support localized primary key // columns, but that would only support deleting rows. if this // becomes necessary, define a PreviousCodepage property on the // Output class and persist this throughout transform generation. targetOutput.Codepage = this.Transform.Codepage; updatedOutput.Codepage = this.Transform.Codepage; // remove certain Property rows which will be populated from summary information values string targetUpgradeCode = null; string updatedUpgradeCode = null; if (this.Transform.TryGetTable("Property", out var propertyTable)) { for (int i = propertyTable.Rows.Count - 1; i >= 0; i--) { Row row = propertyTable.Rows[i]; if ("ProductCode" == (string)row[0] || "ProductLanguage" == (string)row[0] || "ProductVersion" == (string)row[0] || "UpgradeCode" == (string)row[0]) { propertyTable.Rows.RemoveAt(i); if ("UpgradeCode" == (string)row[0]) { updatedUpgradeCode = (string)row[1]; } } } } var targetSummaryInfo = targetOutput.EnsureTable(this.TableDefinitions["_SummaryInformation"]); var updatedSummaryInfo = updatedOutput.EnsureTable(this.TableDefinitions["_SummaryInformation"]); var targetPropertyTable = targetOutput.EnsureTable(this.TableDefinitions["Property"]); var updatedPropertyTable = updatedOutput.EnsureTable(this.TableDefinitions["Property"]); // process special summary information values foreach (var row in this.Transform.Tables["_SummaryInformation"].Rows) { var summaryId = row.FieldAsInteger(0); var summaryData = row.FieldAsString(1); if ((int)SummaryInformation.Transform.CodePage == summaryId) { // convert from a web name if provided var codePage = summaryData; if (null == codePage) { codePage = "0"; } else { codePage = Common.GetValidCodePage(codePage).ToString(CultureInfo.InvariantCulture); } var previousCodePage = row.Fields[1].PreviousData; if (null == previousCodePage) { previousCodePage = "0"; } else { previousCodePage = Common.GetValidCodePage(previousCodePage).ToString(CultureInfo.InvariantCulture); } var targetCodePageRow = targetSummaryInfo.CreateRow(null); targetCodePageRow[0] = 1; // PID_CODEPAGE targetCodePageRow[1] = previousCodePage; var updatedCodePageRow = updatedSummaryInfo.CreateRow(null); updatedCodePageRow[0] = 1; // PID_CODEPAGE updatedCodePageRow[1] = codePage; } else if ((int)SummaryInformation.Transform.TargetPlatformAndLanguage == summaryId || (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage == summaryId) { // the target language var propertyData = summaryData.Split(';'); var lang = 2 == propertyData.Length ? propertyData[1] : "0"; var tempSummaryInfo = (int)SummaryInformation.Transform.TargetPlatformAndLanguage == summaryId ? targetSummaryInfo : updatedSummaryInfo; var tempPropertyTable = (int)SummaryInformation.Transform.TargetPlatformAndLanguage == summaryId ? targetPropertyTable : updatedPropertyTable; var productLanguageRow = tempPropertyTable.CreateRow(null); productLanguageRow[0] = "ProductLanguage"; productLanguageRow[1] = lang; // set the platform;language on the MSI to be generated var templateRow = tempSummaryInfo.CreateRow(null); templateRow[0] = 7; // PID_TEMPLATE templateRow[1] = summaryData; } else if ((int)SummaryInformation.Transform.ProductCodes == summaryId) { var propertyData = summaryData.Split(';'); var targetProductCodeRow = targetPropertyTable.CreateRow(null); targetProductCodeRow[0] = "ProductCode"; targetProductCodeRow[1] = propertyData[0].Substring(0, 38); var targetProductVersionRow = targetPropertyTable.CreateRow(null); targetProductVersionRow[0] = "ProductVersion"; targetProductVersionRow[1] = propertyData[0].Substring(38); var updatedProductCodeRow = updatedPropertyTable.CreateRow(null); updatedProductCodeRow[0] = "ProductCode"; updatedProductCodeRow[1] = propertyData[1].Substring(0, 38); var updatedProductVersionRow = updatedPropertyTable.CreateRow(null); updatedProductVersionRow[0] = "ProductVersion"; updatedProductVersionRow[1] = propertyData[1].Substring(38); // UpgradeCode is optional and may not exists in the target // or upgraded databases, so do not include a null-valued // UpgradeCode property. targetUpgradeCode = propertyData[2]; if (!String.IsNullOrEmpty(targetUpgradeCode)) { var targetUpgradeCodeRow = targetPropertyTable.CreateRow(null); targetUpgradeCodeRow[0] = "UpgradeCode"; targetUpgradeCodeRow[1] = targetUpgradeCode; // If the target UpgradeCode is specified, an updated // UpgradeCode is required. if (String.IsNullOrEmpty(updatedUpgradeCode)) { updatedUpgradeCode = targetUpgradeCode; } } if (!String.IsNullOrEmpty(updatedUpgradeCode)) { var updatedUpgradeCodeRow = updatedPropertyTable.CreateRow(null); updatedUpgradeCodeRow[0] = "UpgradeCode"; updatedUpgradeCodeRow[1] = updatedUpgradeCode; } } else if ((int)SummaryInformation.Transform.ValidationFlags == summaryId) { transformFlags = Convert.ToInt32(summaryData, CultureInfo.InvariantCulture); } else if ((int)SummaryInformation.Transform.Reserved11 == summaryId) { // PID_LASTPRINTED should be null for transforms row.Operation = RowOperation.None; } else { // add everything else as is var targetRow = targetSummaryInfo.CreateRow(null); targetRow[0] = row[0]; targetRow[1] = row[1]; var updatedRow = updatedSummaryInfo.CreateRow(null); updatedRow[0] = row[0]; updatedRow[1] = row[1]; } } // Validate that both databases have an UpgradeCode if the // authoring transform will validate the UpgradeCode; otherwise, // MsiCreateTransformSummaryinfo() will fail with 1620. if (((int)TransformFlags.ValidateUpgradeCode & transformFlags) != 0 && (String.IsNullOrEmpty(targetUpgradeCode) || String.IsNullOrEmpty(updatedUpgradeCode))) { this.Messaging.Write(ErrorMessages.BothUpgradeCodesRequired()); } string emptyFile = null; foreach (var table in this.Transform.Tables) { // Ignore unreal tables when building transforms except the _Stream table. // These tables are ignored when generating the database so there is no reason // to process them here. if (table.Definition.Unreal && "_Streams" != table.Name) { continue; } // process table operations switch (table.Operation) { case TableOperation.Add: updatedOutput.EnsureTable(table.Definition); break; case TableOperation.Drop: targetOutput.EnsureTable(table.Definition); continue; default: targetOutput.EnsureTable(table.Definition); updatedOutput.EnsureTable(table.Definition); break; } // process row operations foreach (var row in table.Rows) { switch (row.Operation) { case RowOperation.Add: var updatedTable = updatedOutput.EnsureTable(table.Definition); updatedTable.Rows.Add(row); continue; case RowOperation.Delete: var targetTable = targetOutput.EnsureTable(table.Definition); targetTable.Rows.Add(row); // fill-in non-primary key values foreach (var field in row.Fields) { if (!field.Column.PrimaryKey) { if (ColumnType.Number == field.Column.Type && !field.Column.IsLocalizable) { field.Data = field.Column.MinValue; } else if (ColumnType.Object == field.Column.Type) { if (null == emptyFile) { emptyFile = Path.Combine(this.IntermediateFolder, "empty"); } field.Data = emptyFile; } else { field.Data = "0"; } } } continue; } // Assure that the file table's sequence is populated if ("File" == table.Name) { foreach (var fileRow in table.Rows) { if (null == fileRow[7]) { if (RowOperation.Add == fileRow.Operation) { this.Messaging.Write(ErrorMessages.InvalidAddedFileRowWithoutSequence(fileRow.SourceLineNumbers, (string)fileRow[0])); break; } // Set to 1 to prevent invalid IDT file from being generated fileRow[7] = 1; } } } // process modified and unmodified rows var modifiedRow = false; var targetRow = table.Definition.CreateRow(null); var updatedRow = row; for (var i = 0; i < row.Fields.Length; i++) { var updatedField = row.Fields[i]; if (updatedField.Modified) { // set a different value in the target row to ensure this value will be modified during transform generation if (ColumnType.Number == updatedField.Column.Type && !updatedField.Column.IsLocalizable) { var data = updatedField.AsNullableInteger(); targetRow[i] = (data == 1) ? 2 : 1; } else if (ColumnType.Object == updatedField.Column.Type) { if (null == emptyFile) { emptyFile = Path.Combine(this.IntermediateFolder, "empty"); } targetRow[i] = emptyFile; } else { var data = updatedField.AsString(); targetRow[i] = (data == "0") ? "1" : "0"; } modifiedRow = true; } else if (ColumnType.Object == updatedField.Column.Type) { var objectField = (ObjectField)updatedField; // create an empty file for comparing against if (null == objectField.PreviousData) { if (null == emptyFile) { emptyFile = Path.Combine(this.IntermediateFolder, "empty"); } targetRow[i] = emptyFile; modifiedRow = true; } else if (!this.FileSystemManager.CompareFiles(objectField.PreviousData, (string)objectField.Data)) { targetRow[i] = objectField.PreviousData; modifiedRow = true; } } else // unmodified { if (null != updatedField.Data) { targetRow[i] = updatedField.Data; } } } // modified rows and certain special rows go in the target and updated msi databases if (modifiedRow || ("Property" == table.Name && ("ProductCode" == (string)row[0] || "ProductLanguage" == (string)row[0] || "ProductVersion" == (string)row[0] || "UpgradeCode" == (string)row[0]))) { var targetTable = targetOutput.EnsureTable(table.Definition); targetTable.Rows.Add(targetRow); var updatedTable = updatedOutput.EnsureTable(table.Definition); updatedTable.Rows.Add(updatedRow); } } } //foreach (BinderExtension extension in this.Extensions) //{ // extension.PostBind(this.Context); //} // Any errors encountered up to this point can cause errors during generation. if (this.Messaging.EncounteredError) { return; } var transformFileName = Path.GetFileNameWithoutExtension(this.OutputPath); var targetDatabaseFile = Path.Combine(this.IntermediateFolder, String.Concat(transformFileName, "_target.msi")); var updatedDatabaseFile = Path.Combine(this.IntermediateFolder, String.Concat(transformFileName, "_updated.msi")); try { if (!String.IsNullOrEmpty(emptyFile)) { using (var fileStream = File.Create(emptyFile)) { } } this.GenerateDatabase(targetOutput, targetDatabaseFile, keepAddedColumns: false); this.GenerateDatabase(updatedOutput, updatedDatabaseFile, keepAddedColumns: true); // make sure the directory exists Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); // create the transform file using (var targetDatabase = new Database(targetDatabaseFile, OpenDatabase.ReadOnly)) using (var updatedDatabase = new Database(updatedDatabaseFile, OpenDatabase.ReadOnly)) { if (updatedDatabase.GenerateTransform(targetDatabase, this.OutputPath)) { updatedDatabase.CreateTransformSummaryInfo(targetDatabase, this.OutputPath, (TransformErrorConditions)(transformFlags & 0xFFFF), (TransformValidations)((transformFlags >> 16) & 0xFFFF)); } else { this.Messaging.Write(ErrorMessages.NoDifferencesInTransform(this.Transform.SourceLineNumbers)); } } } finally { if (!String.IsNullOrEmpty(emptyFile)) { File.Delete(emptyFile); } } }
private void GenerateDatabase(WindowsInstallerData output, string outputPath, bool keepAddedColumns) { var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true); command.Execute(); }
public BindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, string intermediateFolder, WindowsInstallerData transform, string outputPath, TableDefinitionCollection tableDefinitions) { this.Messaging = messaging; this.BackendHelper = backendHelper; this.FileSystemManager = fileSystemManager; this.IntermediateFolder = intermediateFolder; this.Transform = transform; this.OutputPath = outputPath; this.TableDefinitions = tableDefinitions; }