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>