@joebigelow / wix-1 / commits / 164c29af

Partial fix for the weirdly broken...

IWindowsInstallerDecompileContext.TreatProductAsModule. https://github.com/wixtoolset/issues/issues/7607

Bob Arnson committed Jul 11, 2023 at 21:19 UTC 164c29aff8d6581a3277c9fd0810ea56356c3e69
5 files changed +82 -7
src/api/wix/WixToolset.Extensibility/Data/IWindowsInstallerDecompileContext.cs
+2 -1
@@ -93,7 +93,8 @@ namespace WixToolset.Extensibility.Data
93 bool SuppressUI { get; set; }
94
95 /// <summary>
96 - /// Gets or sets whether the decompiler should use module logic on a product output.
96 + /// Gets or sets whether the decompiler should keep modularization
97 + /// GUIDs (true) or remove them (default/false).
98 /// </summary>
99 bool TreatProductAsModule { get; set; }
100 }
src/wix/WixToolset.Core.WindowsInstaller/Decompile/Decompiler.cs
+4 -4
@@ -1188,11 +1188,11 @@ namespace WixToolset.Core.WindowsInstaller.Decompile
1188 var fileName = xFile?.Attribute("Name")?.Value;
1189
1190 // set the source (done here because it requires information from the Directory table)
1191 - if (OutputType.Module == this.OutputType)
1191 + if (OutputType.Module == this.OutputType && !this.TreatProductAsModule)
1192 {
1193 xFile.SetAttributeValue("Source", String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, fileId, '.', this.ModularizationGuid.Substring(1, 36).Replace('-', '_')));
1194 }
1195 - else if (fileCompressed == "yes" || (fileCompressed != "no" && this.Compressed) || (OutputType.Package == this.OutputType && this.TreatProductAsModule))
1195 + else if (fileCompressed == "yes" || (fileCompressed != "no" && this.Compressed) || OutputType.Module == this.OutputType)
1196 {
1197 xFile.SetAttributeValue("Source", String.Concat(this.BaseSourcePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, fileId));
1198 }
@@ -1898,7 +1898,7 @@ namespace WixToolset.Core.WindowsInstaller.Decompile
1898 private void FinalizeSequenceTables(TableIndexedCollection tables)
1899 {
1900 // finalize the normal sequence tables
1901 - if (OutputType.Package == this.OutputType && !this.TreatProductAsModule)
1901 + if (OutputType.Package == this.OutputType)
1902 {
1903 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
1904 {
@@ -2039,7 +2039,7 @@ namespace WixToolset.Core.WindowsInstaller.Decompile
2039 }
2040 }
2041 }
2042 - else if (OutputType.Module == this.OutputType || this.TreatProductAsModule) // finalize the Module sequence tables
2042 + else if (OutputType.Module == this.OutputType) // finalize the Module sequence tables
2043 {
2044 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
2045 {
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerDecompiler.cs
+11 -2
@@ -92,8 +92,17 @@ namespace WixToolset.Core.WindowsInstaller
92 var extractFilesFolder = context.SuppressExtractCabinets || (String.IsNullOrEmpty(context.CabinetExtractFolder) && String.IsNullOrEmpty(context.ExtractFolder)) ? null :
93 String.IsNullOrEmpty(context.CabinetExtractFolder) ? Path.Combine(context.ExtractFolder, "File") : context.CabinetExtractFolder;
94
95 - var outputType = context.TreatProductAsModule ? OutputType.Module : context.DecompileType;
96 - var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, fileSystem, pathResolver, context.DecompilePath, null, outputType, context.ExtractFolder, extractFilesFolder, context.IntermediateFolder, enableDemodularization: true, skipSummaryInfo: false);
95 + // IWindowsInstallerDecompileContext.TreatProductAsModule is broken. So broken, in fact,
96 + // that it's been broken since WiX v3.0 in 2008. It was introduced (according to lore)
97 + // to support Melt, which decompiles merge modules into fragments so you can consume
98 + // merge modules without actually going through the black box that is mergemod.dll. But
99 + // the name is wrong: It's not TreatProductAsModule; if anything it should instead be
100 + // TreatModuleAsProduct, though even that's wrong (because you want a fragment, not a
101 + // product/package). In WiX v5, rename to `KeepModularizeIds` (or something better) to
102 + // reflect the functionality.
103 + var demodularize = !context.TreatProductAsModule;
104 + var sectionType = context.DecompileType;
105 + var unbindCommand = new UnbindDatabaseCommand(this.Messaging, backendHelper, fileSystem, pathResolver, context.DecompilePath, null, sectionType, context.ExtractFolder, extractFilesFolder, context.IntermediateFolder, demodularize, skipSummaryInfo: false);
106 var output = unbindCommand.Execute();
107 var extractedFilePaths = unbindCommand.ExportedFiles;
108
src/wix/test/WixToolsetTest.CoreIntegration/DecompileFixture.cs
+41
@@ -3,10 +3,18 @@
3 namespace WixToolsetTest.CoreIntegration
4 {
5 using System;
6 + using System.Diagnostics;
7 using System.IO;
8 using WixInternal.Core.TestPackage;
9 using WixInternal.TestSupport;
10 + using WixToolset.Core;
11 + using WixToolset.Core.WindowsInstaller;
12 + using WixToolset.Data;
13 + using WixToolset.Extensibility;
14 + using WixToolset.Extensibility.Data;
15 + using WixToolset.Extensibility.Services;
16 using Xunit;
17 + using static NuGet.Packaging.PackagingConstants;
18
19 public class DecompileFixture
20 {
@@ -98,5 +106,38 @@ namespace WixToolsetTest.CoreIntegration
106 {
107 DecompileAndCompare("ui.msi", extract: false, "ExpectedUI.wxs", "TestData", "Decompile");
108 }
109 +
110 + [Fact]
111 + public void CanDecompileMergeModuleWithTreatProductAsModule()
112 + {
113 + using (var fs = new DisposableFileSystem())
114 + {
115 + var intermediateFolder = fs.GetFolder();
116 + var outputFolder = fs.GetFolder();
117 + var extractPath = Path.Combine(intermediateFolder, "$extracted");
118 + var outputPath = Path.Combine(intermediateFolder, @"Actual.wxs");
119 + var sourceFolder = TestData.Get("TestData", "DecompileTargetDirMergeModule");
120 +
121 + var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider();
122 + serviceProvider.AddWindowsInstallerBackend();
123 + var extensionManager = serviceProvider.GetService<IExtensionManager>();
124 + var context = serviceProvider.GetService<IWindowsInstallerDecompileContext>();
125 +
126 + context.Extensions = Array.Empty<BaseWindowsInstallerDecompilerExtension>();
127 + context.ExtensionData = extensionManager.GetServices<IExtensionData>();
128 + context.DecompilePath = Path.Combine(sourceFolder, "MergeModule1.msm");
129 + context.DecompileType = OutputType.Module;
130 + context.TreatProductAsModule = true;
131 + context.IntermediateFolder = intermediateFolder;
132 + context.ExtractFolder = outputFolder;
133 + context.CabinetExtractFolder = outputFolder;
134 +
135 + var decompiler = serviceProvider.GetService<IWindowsInstallerDecompiler>();
136 + var result = decompiler.Decompile(context);
137 +
138 + result.Document.Save(outputPath);
139 + WixAssert.CompareXml(Path.Combine(sourceFolder, "ExpectedModularizationGuids.wxs"), outputPath);
140 + }
141 + }
142 }
143 }
src/wix/test/WixToolsetTest.CoreIntegration/TestData/DecompileTargetDirMergeModule/ExpectedModularizationGuids.wxs new
+24
@@ -0,0 +1,24 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Module Codepage="65001" Id="MergeModule1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Language="1033" Version="1.0.0.0" InstallerVersion="200" Guid="{F844F0E3-8CB4-4A0F-973E-31C4F9338382}">
4 + <Binary Id="Binary1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" SourceFile="Expected.wxs" />
5 + <Directory Id="ProgramFilesFolder.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Name="PFiles">
6 + <Directory Id="WixTestDir.F844F0E3_8CB4_4A0F_973E_31C4F9338382" ShortName="7bhhvaai" Name="WiX Toolset Test Directory">
7 + <Component Id="ModuleComponent1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Guid="{D86EC5A2-9576-4699-BDC3-00586FF72CBE}" Bitness="always32">
8 + <File Id="File1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" ShortName="gahushls.wxs" Name="MergeModule.wxs" KeyPath="yes" Source="SourceDir\File\File1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" />
9 + </Component>
10 + </Directory>
11 + </Directory>
12 + <Directory Id="MergeRedirectFolder.F844F0E3_8CB4_4A0F_973E_31C4F9338382">
13 + <Component Id="ModuleComponent2.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Guid="{BB222EE8-229B-4051-9443-49E348F0CC77}" Bitness="always32">
14 + <File Id="File2.F844F0E3_8CB4_4A0F_973E_31C4F9338382" ShortName="sfmxqeab.wxs" Name="MergeModule.wxs" KeyPath="yes" Source="SourceDir\File\File2.F844F0E3_8CB4_4A0F_973E_31C4F9338382" />
15 + </Component>
16 + </Directory>
17 + <SummaryInformation Description="MergeModule1" Manufacturer="WiX Toolset contributors" />
18 + <StandardDirectory Id="TARGETDIR">
19 + <Component Id="ModuleComponent3.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Guid="{63A2B2B1-32BE-46FF-8863-4C85A2745F62}" Bitness="always32">
20 + <RegistryValue KeyPath="yes" Id="Reg1.F844F0E3_8CB4_4A0F_973E_31C4F9338382" Root="HKLM" Key="SOFTWARE\WiX Toolset\MergeModuleDecompileTest" Name="DoesntReallyMatter" Value="Hello" Type="string" />
21 + </Component>
22 + </StandardDirectory>
23 + </Module>
24 +</Wix>