aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-11-29 22:03:26 -0800
committerRob Mensching <rob@firegiant.com>2017-11-29 22:03:26 -0800
commit71c52d5af2293d3eb79882ce36b0411f81185c11 (patch)
tree23dd116bdd6abc2b0f7b488f490d1b77faa41812 /src
parent0fa198ed8c6c6fc81e649466879752a99fe37d08 (diff)
downloadwix-71c52d5af2293d3eb79882ce36b0411f81185c11.tar.gz
wix-71c52d5af2293d3eb79882ce36b0411f81185c11.tar.bz2
wix-71c52d5af2293d3eb79882ce36b0411f81185c11.zip
Fix source path and cabinet processing
Diffstat (limited to 'src')
-rw-r--r--src/WixToolset.Core.Burn/Bundles/BurnReader.cs14
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs1
-rw-r--r--src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs7
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs32
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs60
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs12
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs42
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs27
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs2
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs20
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs22
-rw-r--r--src/WixToolset.Core/Cab/CabinetFileInfo.cs45
-rw-r--r--src/WixToolset.Core/Cab/Interop/CabInterop.cs316
-rw-r--r--src/WixToolset.Core/Cab/WixCreateCab.cs249
-rw-r--r--src/WixToolset.Core/Cab/WixEnumerateCab.cs89
-rw-r--r--src/WixToolset.Core/Cab/WixExtractCab.cs75
-rw-r--r--src/WixToolset.Core/Compiler.cs2
-rw-r--r--src/WixToolset.Core/Link/ResolveReferencesCommand.cs2
-rw-r--r--src/WixToolset.Core/Preprocess/IfContext.cs56
-rw-r--r--src/WixToolset.Core/Preprocess/IfState.cs22
-rw-r--r--src/WixToolset.Core/Preprocessor.cs2
-rw-r--r--src/WixToolset.Data.WindowsInstaller/ColumnDefinition.cs3
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs47
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.en-us.wxl11
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.wxs27
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/PackageComponents.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/data/test.txt1
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.en-us.wxl10
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wixproj48
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wxs16
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/data/test.txt1
-rw-r--r--src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj11
33 files changed, 352 insertions, 932 deletions
diff --git a/src/WixToolset.Core.Burn/Bundles/BurnReader.cs b/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
index 261ef7b4..3b3076c4 100644
--- a/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
+++ b/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
@@ -7,7 +7,7 @@ namespace WixToolset.Core.Burn.Bundles
7 using System.Collections.Generic; 7 using System.Collections.Generic;
8 using System.IO; 8 using System.IO;
9 using System.Xml; 9 using System.Xml;
10 using WixToolset.Core.Cab; 10 using WixToolset.Core.Native;
11 11
12 /// <summary> 12 /// <summary>
13 /// Burn PE reader for the WiX toolset. 13 /// Burn PE reader for the WiX toolset.
@@ -101,10 +101,8 @@ namespace WixToolset.Core.Burn.Bundles
101 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); 101 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize);
102 } 102 }
103 103
104 using (var extract = new WixExtractCab()) 104 var cabinet = new Cabinet(tempCabPath);
105 { 105 cabinet.Extract(outputDirectory);
106 extract.Extract(tempCabPath, outputDirectory);
107 }
108 106
109 Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); 107 Directory.CreateDirectory(Path.GetDirectoryName(manifestPath));
110 File.Delete(manifestPath); 108 File.Delete(manifestPath);
@@ -181,10 +179,8 @@ namespace WixToolset.Core.Burn.Bundles
181 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize); 179 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize);
182 } 180 }
183 181
184 using (WixExtractCab extract = new WixExtractCab()) 182 var cabinet = new Cabinet(tempCabPath);
185 { 183 cabinet.Extract(outputDirectory);
186 extract.Extract(tempCabPath, outputDirectory);
187 }
188 184
189 foreach (DictionaryEntry entry in this.attachedContainerPayloadNames) 185 foreach (DictionaryEntry entry in this.attachedContainerPayloadNames)
190 { 186 {
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs
index cde6d8f3..cbc4839a 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs
@@ -7,7 +7,6 @@ namespace WixToolset.Core.Burn.Bundles
7 using System.Diagnostics; 7 using System.Diagnostics;
8 using System.IO; 8 using System.IO;
9 using System.Linq; 9 using System.Linq;
10 using WixToolset.Core.Cab;
11 using WixToolset.Data; 10 using WixToolset.Data;
12 using WixToolset.Data.Rows; 11 using WixToolset.Data.Rows;
13 12
diff --git a/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
index 878ac200..c607dd20 100644
--- a/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
+++ b/src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
@@ -20,9 +20,9 @@
20 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " /> 20 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Extensibility\src\WixToolset.Extensibility\WixToolset.Extensibility.csproj') " />
21 21
22 <ProjectReference Include="$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " /> 22 <ProjectReference Include="$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj" Condition=" '$(Configuration)' == 'Debug' And Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " />
23 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " />
23 24
24 <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> 25 <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" />
25 <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" Condition=" '$(Configuration)' == 'Release' Or !Exists('$(WixToolsetRootFolder)\Core.Native\src\WixToolset.Core.Native\WixToolset.Core.Native.csproj') " />
26 </ItemGroup> 26 </ItemGroup>
27 27
28 <ItemGroup> 28 <ItemGroup>
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
index 30a19a4b..012998e6 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
@@ -123,7 +123,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
123 { 123 {
124 propertyRow.Value = Common.GenerateGuid(); 124 propertyRow.Value = Common.GenerateGuid();
125 125
126#if TODO_FIX_INSTANCE_TRANSFORM 126#if TODO_FIX_INSTANCE_TRANSFORM // Is this still necessary?
127
127 // Update the target ProductCode in any instance transforms. 128 // Update the target ProductCode in any instance transforms.
128 foreach (SubStorage subStorage in this.Output.SubStorages) 129 foreach (SubStorage subStorage in this.Output.SubStorages)
129 { 130 {
@@ -391,7 +392,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
391 command.ResolveMedia = this.ResolveMedia; 392 command.ResolveMedia = this.ResolveMedia;
392 command.TableDefinitions = this.TableDefinitions; 393 command.TableDefinitions = this.TableDefinitions;
393 command.TempFilesLocation = this.IntermediateFolder; 394 command.TempFilesLocation = this.IntermediateFolder;
394 command.WixMediaTable = output.Tables["WixMedia"]; 395 command.WixMediaTuples = section.Tuples.OfType<WixMediaTuple>();
395 command.Execute(); 396 command.Execute();
396 397
397 fileTransfers.AddRange(command.FileTransfers); 398 fileTransfers.AddRange(command.FileTransfers);
@@ -526,7 +527,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
526 } 527 }
527 528
528 this.FileTransfers = fileTransfers; 529 this.FileTransfers = fileTransfers;
529 this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source).ToList(); 530 this.ContentFilePaths = fileFacades.Select(r => r.WixFile.Source.Path).ToList();
530 531
531 // TODO: Eventually this gets removed 532 // TODO: Eventually this gets removed
532 var intermediate = new Intermediate(this.Intermediate.Id, new[] { section }, this.Intermediate.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Intermediate.EmbedFilePaths); 533 var intermediate = new Intermediate(this.Intermediate.Id, new[] { section }, this.Intermediate.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Intermediate.EmbedFilePaths);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs
index c25a497e..2cbcc8e1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs
@@ -4,11 +4,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System; 5 using System;
6 using System.Collections; 6 using System.Collections;
7 using System.Collections.Generic;
7 using System.IO; 8 using System.IO;
8 using System.Linq; 9 using System.Linq;
9 using System.Threading; 10 using System.Threading;
10 using WixToolset.Core.Bind; 11 using WixToolset.Core.Bind;
11 using WixToolset.Core.Cab; 12 using WixToolset.Core.Native;
12 using WixToolset.Data; 13 using WixToolset.Data;
13 14
14 /// <summary> 15 /// <summary>
@@ -137,7 +138,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
137 int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting 138 int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting
138 ulong maxPreCompressedSizeInBytes = 0; 139 ulong maxPreCompressedSizeInBytes = 0;
139 140
140 if (MaximumCabinetSizeForLargeFileSplitting != 0) 141 if (this.MaximumCabinetSizeForLargeFileSplitting != 0)
141 { 142 {
142 // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize 143 // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize
143 // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file 144 // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file
@@ -152,26 +153,33 @@ namespace WixToolset.Core.WindowsInstaller.Bind
152 if ((ulong)facade.File.FileSize >= maxPreCompressedSizeInBytes) 153 if ((ulong)facade.File.FileSize >= maxPreCompressedSizeInBytes)
153 { 154 {
154 // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting 155 // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting
155 maxCabinetSize = MaximumCabinetSizeForLargeFileSplitting; 156 maxCabinetSize = this.MaximumCabinetSizeForLargeFileSplitting;
156 } 157 }
157 } 158 }
158 } 159 }
159 } 160 }
160 161
161 // create the cabinet file 162 // create the cabinet file
163 var cabinetPath = Path.GetFullPath(cabinetWorkItem.CabinetFile);
162 string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); 164 string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile);
163 string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); 165 string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile);
164 166
165 using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileFacades.Count(), maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) 167 //using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileFacades.Count(), maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel))
166 { 168 //{
167 foreach (FileFacade facade in cabinetWorkItem.FileFacades) 169 // foreach (FileFacade facade in cabinetWorkItem.FileFacades)
168 { 170 // {
169 cab.AddFile(facade); 171 // cab.AddFile(facade);
170 } 172 // }
171 173
172 cab.Complete(newCabNamesCallBackAddress); 174 // cab.Complete(newCabNamesCallBackAddress);
173 } 175 //}
176
177 var files = cabinetWorkItem.FileFacades.Select(facade => new CabinetCompressFile(facade.WixFile.Source.Path, facade.File.File, facade.Hash.HashPart1, facade.Hash.HashPart2, facade.Hash.HashPart3, facade.Hash.HashPart4)).ToList();
178
179 var cabinetCompressionLevel = (CabinetCompressionLevel)cabinetWorkItem.CompressionLevel;
180
181 var cab = new Cabinet(cabinetPath);
182 cab.Compress(files, cabinetCompressionLevel, maxCabinetSize, cabinetWorkItem.MaxThreshold);
174 } 183 }
175 } 184 }
176} 185}
177
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
index df1ccecf..370d4b9c 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetResolver.cs
@@ -6,8 +6,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Core.Cab;
10 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
10 using WixToolset.Core.Native;
11 using WixToolset.Data; 11 using WixToolset.Data;
12 using WixToolset.Extensibility; 12 using WixToolset.Extensibility;
13 13
@@ -26,7 +26,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
26 26
27 public ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) 27 public ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades)
28 { 28 {
29 var filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); 29 var filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source.Path }).ToList();
30 30
31 ResolvedCabinet resolved = null; 31 ResolvedCabinet resolved = null;
32 32
@@ -58,45 +58,39 @@ namespace WixToolset.Core.WindowsInstaller.Bind
58 // 3. modified time changed 58 // 3. modified time changed
59 bool cabinetValid = true; 59 bool cabinetValid = true;
60 60
61 // Need to force garbage collection of WixEnumerateCab to ensure the handle 61 var cabinet = new Cabinet(resolved.Path);
62 // associated with it is closed before it is reused. 62 List<CabinetFileInfo> fileList = cabinet.Enumerate();
63 using (var wixEnumerateCab = new WixEnumerateCab())
64 {
65 List<CabinetFileInfo> fileList = wixEnumerateCab.Enumerate(resolved.Path);
66 63
67 if (filesWithPath.Count() != fileList.Count) 64 if (filesWithPath.Count() != fileList.Count)
68 { 65 {
69 cabinetValid = false; 66 cabinetValid = false;
70 } 67 }
71 else 68 else
69 {
70 int i = 0;
71 foreach (BindFileWithPath file in filesWithPath)
72 { 72 {
73 int i = 0; 73 // First check that the file identifiers match because that is quick and easy.
74 foreach (BindFileWithPath file in filesWithPath) 74 CabinetFileInfo cabFileInfo = fileList[i];
75 cabinetValid = (cabFileInfo.FileId == file.Id);
76 if (cabinetValid)
75 { 77 {
76 // First check that the file identifiers match because that is quick and easy. 78 // Still valid so ensure the file sizes are the same.
77 CabinetFileInfo cabFileInfo = fileList[i]; 79 FileInfo fileInfo = new FileInfo(file.Path);
78 cabinetValid = (cabFileInfo.FileId == file.Id); 80 cabinetValid = (cabFileInfo.Size == fileInfo.Length);
79 if (cabinetValid) 81 if (cabinetValid)
80 { 82 {
81 // Still valid so ensure the file sizes are the same. 83 // Still valid so ensure the source time stamp hasn't changed.
82 FileInfo fileInfo = new FileInfo(file.Path); 84 cabinetValid = cabFileInfo.SameAsDateTime(fileInfo.LastWriteTime);
83 cabinetValid = (cabFileInfo.Size == fileInfo.Length);
84 if (cabinetValid)
85 {
86 // Still valid so ensure the source time stamp hasn't changed. Thus we need
87 // to convert the source file time stamp into a cabinet compatible data/time.
88 Native.CabInterop.DateTimeToCabDateAndTime(fileInfo.LastWriteTime, out var sourceCabDate, out var sourceCabTime);
89 cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime);
90 }
91 }
92
93 if (!cabinetValid)
94 {
95 break;
96 } 85 }
86 }
97 87
98 i++; 88 if (!cabinetValid)
89 {
90 break;
99 } 91 }
92
93 i++;
100 } 94 }
101 } 95 }
102 96
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
index b5a436c5..a449397d 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
@@ -66,7 +66,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
66 66
67 public TableDefinitionCollection TableDefinitions { private get; set; } 67 public TableDefinitionCollection TableDefinitions { private get; set; }
68 68
69 public Table WixMediaTable { private get; set; } 69 public IEnumerable<WixMediaTuple> WixMediaTuples { private get; set; }
70 70
71 public IEnumerable<FileTransfer> FileTransfers => this.fileTransfers; 71 public IEnumerable<FileTransfer> FileTransfers => this.fileTransfers;
72 72
@@ -77,7 +77,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
77 /// <returns>The uncompressed file rows.</returns> 77 /// <returns>The uncompressed file rows.</returns>
78 public void Execute() 78 public void Execute()
79 { 79 {
80 var wixMediaRows = new RowDictionary<WixMediaRow>(this.WixMediaTable); 80 var wixMediaTuples = this.WixMediaTuples.ToDictionary(t => t.DiskId_);
81 81
82 this.lastCabinetAddedToMediaTable = new Dictionary<string, string>(); 82 this.lastCabinetAddedToMediaTable = new Dictionary<string, string>();
83 83
@@ -93,13 +93,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
93 93
94 foreach (var entry in this.FileRowsByCabinet) 94 foreach (var entry in this.FileRowsByCabinet)
95 { 95 {
96 var mediaRow = entry.Key; 96 var mediaTuple = entry.Key;
97 IEnumerable<FileFacade> files = entry.Value; 97 IEnumerable<FileFacade> files = entry.Value;
98 CompressionLevel compressionLevel = this.DefaultCompressionLevel; 98 CompressionLevel compressionLevel = this.DefaultCompressionLevel;
99 99
100 string mediaLayoutFolder = null; 100 string mediaLayoutFolder = null;
101 101
102 if (wixMediaRows.TryGetValue(mediaRow.Id.Id, out var wixMediaRow)) 102 if (wixMediaTuples.TryGetValue(mediaTuple.DiskId, out var wixMediaRow))
103 { 103 {
104 mediaLayoutFolder = wixMediaRow.Layout; 104 mediaLayoutFolder = wixMediaRow.Layout;
105 105
@@ -109,9 +109,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
109 } 109 }
110 } 110 }
111 111
112 string cabinetDir = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory); 112 string cabinetDir = this.ResolveMedia(mediaTuple, mediaLayoutFolder, this.LayoutDirectory);
113 113
114 CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(this.Output, cabinetDir, mediaRow, compressionLevel, files, this.fileTransfers); 114 CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(this.Output, cabinetDir, mediaTuple, compressionLevel, files, this.fileTransfers);
115 if (null != cabinetWorkItem) 115 if (null != cabinetWorkItem)
116 { 116 {
117 cabinetBuilder.Enqueue(cabinetWorkItem); 117 cabinetBuilder.Enqueue(cabinetWorkItem);
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
index 85b3b25a..a19a53f1 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
@@ -44,9 +44,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
44 this.AddFileTuple((FileTuple)tuple, output); 44 this.AddFileTuple((FileTuple)tuple, output);
45 break; 45 break;
46 46
47 case TupleDefinitionType.Media:
48 this.AddMediaTuple((MediaTuple)tuple, output);
49 break;
50
51 case TupleDefinitionType.Property:
52 this.AddPropertyTuple((PropertyTuple)tuple, output);
53 break;
54
47 case TupleDefinitionType.WixAction: 55 case TupleDefinitionType.WixAction:
48 this.AddWixActionTuple((WixActionTuple)tuple, output); 56 this.AddWixActionTuple((WixActionTuple)tuple, output);
49 break; 57 break;
58
59 case TupleDefinitionType.WixMedia:
60 // Ignored.
61 break;
50 62
51 default: 63 default:
52 this.AddTupleDefaultly(tuple, output); 64 this.AddTupleDefaultly(tuple, output);
@@ -76,6 +88,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind
76 row.Attributes = attributes; 88 row.Attributes = attributes;
77 } 89 }
78 90
91 private void AddMediaTuple(MediaTuple tuple, Output output)
92 {
93 if (this.Section.Type != SectionType.Module)
94 {
95 var table = output.EnsureTable(this.TableDefinitions["Media"]);
96 var row = (MediaRow)table.CreateRow(tuple.SourceLineNumbers);
97 row.DiskId = tuple.DiskId;
98 row.LastSequence = tuple.LastSequence;
99 row.DiskPrompt = tuple.DiskPrompt;
100 row.Cabinet = tuple.Cabinet;
101 row.VolumeLabel = tuple.VolumeLabel;
102 row.Source = tuple.Source;
103 }
104 }
105
106 private void AddPropertyTuple(PropertyTuple tuple, Output output)
107 {
108 if (String.IsNullOrEmpty(tuple.Value))
109 {
110 return;
111 }
112
113 var table = output.EnsureTable(this.TableDefinitions["Property"]);
114 var row = (PropertyRow)table.CreateRow(tuple.SourceLineNumbers);
115 row.Property = tuple.Property;
116 row.Value = tuple.Value;
117 }
118
79 private void AddWixActionTuple(WixActionTuple actionRow, Output output) 119 private void AddWixActionTuple(WixActionTuple actionRow, Output output)
80 { 120 {
81 // Get the table definition for the action (and ensure the proper table exists for a module). 121 // Get the table definition for the action (and ensure the proper table exists for a module).
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
index 32d1cfda..a31c8079 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
@@ -14,7 +14,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
14 using WixToolset.Msi; 14 using WixToolset.Msi;
15 using WixToolset.Core.Native; 15 using WixToolset.Core.Native;
16 using WixToolset.Core.Bind; 16 using WixToolset.Core.Bind;
17 using WixToolset.Core.Cab;
18 using WixToolset.Data.Tuples; 17 using WixToolset.Data.Tuples;
19 18
20 /// <summary> 19 /// <summary>
@@ -110,7 +109,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
110 wixFileRow.Directory_ = record[2]; 109 wixFileRow.Directory_ = record[2];
111 wixFileRow.DiskId = wixMergeRow.DiskId; 110 wixFileRow.DiskId = wixMergeRow.DiskId;
112 wixFileRow.PatchGroup = -1; 111 wixFileRow.PatchGroup = -1;
113 wixFileRow.Source = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]); 112 wixFileRow.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) };
114 //WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false); 113 //WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false);
115 //wixFileRow.Directory = record[2]; 114 //wixFileRow.Directory = record[2];
116 //wixFileRow.DiskId = wixMergeRow.DiskId; 115 //wixFileRow.DiskId = wixMergeRow.DiskId;
@@ -204,20 +203,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
204 string mergeIdPath = Path.Combine(this.IntermediateFolder, mergeId); 203 string mergeIdPath = Path.Combine(this.IntermediateFolder, mergeId);
205 Directory.CreateDirectory(mergeIdPath); 204 Directory.CreateDirectory(mergeIdPath);
206 205
207 using (var extractCab = new WixExtractCab()) 206 try
208 { 207 {
209 try 208 var cabinet = new Cabinet(moduleCabPath);
210 { 209 cabinet.Extract(mergeIdPath);
211 extractCab.Extract(moduleCabPath, mergeIdPath); 210 }
212 } 211 catch (FileNotFoundException)
213 catch (FileNotFoundException) 212 {
214 { 213 throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
215 throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); 214 }
216 } 215 catch
217 catch 216 {
218 { 217 throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
219 throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
220 }
221 } 218 }
222 } 219 }
223 catch (COMException ce) 220 catch (COMException ce)
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
index d71724d1..aa4382f5 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
@@ -105,7 +105,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
105 105
106 // finally put together the base media layout path and the relative file layout path 106 // finally put together the base media layout path and the relative file layout path
107 string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath); 107 string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath);
108 if (FileTransfer.TryCreate(facade.WixFile.Source, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out var transfer)) 108 if (FileTransfer.TryCreate(facade.WixFile.Source.Path, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out var transfer))
109 { 109 {
110 fileTransfers.Add(transfer); 110 fileTransfers.Add(transfer);
111 } 111 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
index 030bc4cc..a9eb2a8f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
@@ -57,27 +57,27 @@ namespace WixToolset.Core.WindowsInstaller.Bind
57 FileInfo fileInfo = null; 57 FileInfo fileInfo = null;
58 try 58 try
59 { 59 {
60 fileInfo = new FileInfo(file.WixFile.Source); 60 fileInfo = new FileInfo(file.WixFile.Source.Path);
61 } 61 }
62 catch (ArgumentException) 62 catch (ArgumentException)
63 { 63 {
64 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); 64 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
65 return; 65 return;
66 } 66 }
67 catch (PathTooLongException) 67 catch (PathTooLongException)
68 { 68 {
69 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); 69 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
70 return; 70 return;
71 } 71 }
72 catch (NotSupportedException) 72 catch (NotSupportedException)
73 { 73 {
74 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source)); 74 Messaging.Instance.OnMessage(WixDataErrors.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
75 return; 75 return;
76 } 76 }
77 77
78 if (!fileInfo.Exists) 78 if (!fileInfo.Exists)
79 { 79 {
80 Messaging.Instance.OnMessage(WixErrors.CannotFindFile(file.File.SourceLineNumbers, file.File.File, file.File.LongFileName, file.WixFile.Source)); 80 Messaging.Instance.OnMessage(WixErrors.CannotFindFile(file.File.SourceLineNumbers, file.File.File, file.File.LongFileName, file.WixFile.Source.Path));
81 return; 81 return;
82 } 82 }
83 83
@@ -85,7 +85,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
85 { 85 {
86 if (Int32.MaxValue < fileStream.Length) 86 if (Int32.MaxValue < fileStream.Length)
87 { 87 {
88 throw new WixException(WixErrors.FileTooLarge(file.File.SourceLineNumbers, file.WixFile.Source)); 88 throw new WixException(WixErrors.FileTooLarge(file.File.SourceLineNumbers, file.WixFile.Source.Path));
89 } 89 }
90 90
91 file.File.FileSize = Convert.ToInt32(fileStream.Length, CultureInfo.InvariantCulture); 91 file.File.FileSize = Convert.ToInt32(fileStream.Length, CultureInfo.InvariantCulture);
@@ -372,7 +372,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
372 // Navigator is cheaper than dom. Perhaps there is a cheaper API still. 372 // Navigator is cheaper than dom. Perhaps there is a cheaper API still.
373 try 373 try
374 { 374 {
375 XPathDocument doc = new XPathDocument(fileManifest.WixFile.Source); 375 XPathDocument doc = new XPathDocument(fileManifest.WixFile.Source.Path);
376 XPathNavigator nav = doc.CreateNavigator(); 376 XPathNavigator nav = doc.CreateNavigator();
377 nav.MoveToRoot(); 377 nav.MoveToRoot();
378 378
@@ -396,7 +396,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
396 } 396 }
397 if (!hasNextSibling) 397 if (!hasNextSibling)
398 { 398 {
399 Messaging.Instance.OnMessage(WixErrors.InvalidManifestContent(file.File.SourceLineNumbers, fileManifest.WixFile.Source)); 399 Messaging.Instance.OnMessage(WixErrors.InvalidManifestContent(file.File.SourceLineNumbers, fileManifest.WixFile.Source.Path));
400 return; 400 return;
401 } 401 }
402 402
@@ -434,11 +434,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
434 } 434 }
435 catch (FileNotFoundException fe) 435 catch (FileNotFoundException fe)
436 { 436 {
437 Messaging.Instance.OnMessage(WixErrors.FileNotFound(new SourceLineNumber(fileManifest.WixFile.Source), fe.FileName, "AssemblyManifest")); 437 Messaging.Instance.OnMessage(WixErrors.FileNotFound(new SourceLineNumber(fileManifest.WixFile.Source.Path), fe.FileName, "AssemblyManifest"));
438 } 438 }
439 catch (XmlException xe) 439 catch (XmlException xe)
440 { 440 {
441 Messaging.Instance.OnMessage(WixErrors.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source), "manifest", xe.Message)); 441 Messaging.Instance.OnMessage(WixErrors.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source.Path), "manifest", xe.Message));
442 } 442 }
443 443
444 if (!String.IsNullOrEmpty(win32Name)) 444 if (!String.IsNullOrEmpty(win32Name))
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs
index 229e75b4..7985c120 100644
--- a/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Unbind/ExtractCabinetsCommand.cs
@@ -7,7 +7,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
7 using System.Collections.Specialized; 7 using System.Collections.Specialized;
8 using System.Globalization; 8 using System.Globalization;
9 using System.IO; 9 using System.IO;
10 using WixToolset.Core.Cab; 10 using WixToolset.Core.Native;
11 using WixToolset.Data; 11 using WixToolset.Data;
12 using WixToolset.Data.Rows; 12 using WixToolset.Data.Rows;
13 using WixToolset.Msi; 13 using WixToolset.Msi;
@@ -88,9 +88,9 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
88 string cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); 88 string cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab"));
89 89
90 // ensure the parent directory exists 90 // ensure the parent directory exists
91 System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); 91 Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile));
92 92
93 using (FileStream fs = System.IO.File.Create(cabinetFile)) 93 using (FileStream fs = File.Create(cabinetFile))
94 { 94 {
95 int bytesRead; 95 int bytesRead;
96 byte[] buffer = new byte[512]; 96 byte[] buffer = new byte[512];
@@ -128,16 +128,14 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
128 128
129 foreach (string cabinetFile in cabinetFiles) 129 foreach (string cabinetFile in cabinetFiles)
130 { 130 {
131 using (var extractCab = new WixExtractCab()) 131 try
132 { 132 {
133 try 133 var cabinet = new Cabinet(cabinetFile);
134 { 134 cabinet.Extract(fileDirectory);
135 extractCab.Extract(cabinetFile, fileDirectory); 135 }
136 } 136 catch (FileNotFoundException)
137 catch (FileNotFoundException) 137 {
138 { 138 throw new WixException(WixErrors.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile));
139 throw new WixException(WixErrors.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile));
140 }
141 } 139 }
142 } 140 }
143 } 141 }
diff --git a/src/WixToolset.Core/Cab/CabinetFileInfo.cs b/src/WixToolset.Core/Cab/CabinetFileInfo.cs
deleted file mode 100644
index 816f9e3e..00000000
--- a/src/WixToolset.Core/Cab/CabinetFileInfo.cs
+++ /dev/null
@@ -1,45 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Cab
4{
5 /// <summary>
6 /// Properties of a file in a cabinet.
7 /// </summary>
8 public sealed class CabinetFileInfo
9 {
10 /// <summary>
11 /// Constructs CabinetFileInfo
12 /// </summary>
13 /// <param name="fileId">File Id</param>
14 /// <param name="date">Last modified date (MS-DOS time)</param>
15 /// <param name="time">Last modified time (MS-DOS time)</param>
16 public CabinetFileInfo(string fileId, ushort date, ushort time, int size)
17 {
18 this.FileId = fileId;
19 this.Date = date;
20 this.Time = time;
21 this.Size = size;
22 }
23
24 /// <summary>
25 /// Gets the file Id of the file.
26 /// </summary>
27 /// <value>file Id</value>
28 public string FileId { get; }
29
30 /// <summary>
31 /// Gets modified date (DOS format).
32 /// </summary>
33 public ushort Date { get; }
34
35 /// <summary>
36 /// Gets modified time (DOS format).
37 /// </summary>
38 public ushort Time { get; }
39
40 /// <summary>
41 /// Gets the size of the file in bytes.
42 /// </summary>
43 public int Size { get; }
44 }
45}
diff --git a/src/WixToolset.Core/Cab/Interop/CabInterop.cs b/src/WixToolset.Core/Cab/Interop/CabInterop.cs
deleted file mode 100644
index 6c1ae2c1..00000000
--- a/src/WixToolset.Core/Cab/Interop/CabInterop.cs
+++ /dev/null
@@ -1,316 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#if false
4
5namespace WixToolset.Cab.Interop
6{
7 using System;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Text;
10 using System.Runtime.InteropServices;
11 using WixToolset.Msi;
12 using WixToolset.Msi.Interop;
13
14 /// <summary>
15 /// The native methods.
16 /// </summary>
17 public sealed class NativeMethods
18 {
19 /// <summary>
20 /// Starts creating a cabinet.
21 /// </summary>
22 /// <param name="cabinetName">Name of cabinet to create.</param>
23 /// <param name="cabinetDirectory">Directory to create cabinet in.</param>
24 /// <param name="maxFiles">Maximum number of files that will be added to cabinet.</param>
25 /// <param name="maxSize">Maximum size of the cabinet.</param>
26 /// <param name="maxThreshold">Maximum threshold in the cabinet.</param>
27 /// <param name="compressionType">Type of compression to use in the cabinet.</param>
28 /// <param name="contextHandle">Handle to opened cabinet.</param>
29 [DllImport("winterop.dll", EntryPoint = "CreateCabBegin", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
30 internal static extern void CreateCabBegin(string cabinetName, string cabinetDirectory, uint maxFiles, uint maxSize, uint maxThreshold, uint compressionType, out IntPtr contextHandle);
31
32 /// <summary>
33 /// Adds a file to an open cabinet.
34 /// </summary>
35 /// <param name="file">Full path to file to add to cabinet.</param>
36 /// <param name="token">Name of file in cabinet.</param>
37 /// <param name="contextHandle">Handle to open cabinet.</param>
38 [DllImport("winterop.dll", EntryPoint = "CreateCabAddFile", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
39 internal static extern void CreateCabAddFile(string file, string token, MsiInterop.MSIFILEHASHINFO fileHash, IntPtr contextHandle);
40
41 /// <summary>
42 /// Closes a cabinet.
43 /// </summary>
44 /// <param name="contextHandle">Handle to open cabinet to close.</param>
45 /// <param name="newCabNamesCallBackAddress">Address of Binder's cabinet split callback</param>
46 [DllImport("winterop.dll", EntryPoint = "CreateCabFinish", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
47 internal static extern void CreateCabFinish(IntPtr contextHandle, IntPtr newCabNamesCallBackAddress);
48
49 /// <summary>
50 /// Cancels cabinet creation.
51 /// </summary>
52 /// <param name="contextHandle">Handle to open cabinet to cancel.</param>
53 [DllImport("winterop.dll", EntryPoint = "CreateCabCancel", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
54 internal static extern void CreateCabCancel(IntPtr contextHandle);
55
56 /// <summary>
57 /// Initializes cabinet extraction.
58 /// </summary>
59 [DllImport("winterop.dll", EntryPoint = "ExtractCabBegin", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
60 internal static extern void ExtractCabBegin();
61
62 /// <summary>
63 /// Extracts files from cabinet.
64 /// </summary>
65 /// <param name="cabinet">Path to cabinet to extract files from.</param>
66 /// <param name="extractDirectory">Directory to extract files to.</param>
67 [DllImport("winterop.dll", EntryPoint = "ExtractCab", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true, PreserveSig = false)]
68 internal static extern void ExtractCab(string cabinet, string extractDirectory);
69
70 /// <summary>
71 /// Cleans up after cabinet extraction.
72 /// </summary>
73 [DllImport("winterop.dll", EntryPoint = "ExtractCabFinish", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
74 internal static extern void ExtractCabFinish();
75
76 /// <summary>
77 /// Initializes cabinet enumeration.
78 /// </summary>
79 [DllImport("winterop.dll", EntryPoint = "EnumerateCabBegin", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
80 internal static extern void EnumerateCabBegin();
81
82 /// <summary>
83 /// Enumerates files from cabinet.
84 /// </summary>
85 /// <param name="cabinet">Path to cabinet to enumerate files from.</param>
86 /// <param name="notify">callback that gets each file.</param>
87 [DllImport("winterop.dll", EntryPoint = "EnumerateCab", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true, PreserveSig = false)]
88 internal static extern void EnumerateCab(string cabinet, CabInterop.PFNNOTIFY notify);
89
90 /// <summary>
91 /// Cleans up after cabinet enumeration.
92 /// </summary>
93 [DllImport("winterop.dll", EntryPoint = "EnumerateCabFinish", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
94 internal static extern void EnumerateCabFinish();
95
96 /// <summary>
97 /// Resets the DACL on an array of files to "empty".
98 /// </summary>
99 /// <param name="files">Array of file reset ACL to "empty".</param>
100 /// <param name="fileCount">Number of file paths in array.</param>
101 [DllImport("winterop.dll", EntryPoint = "ResetAcls", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
102 internal static extern void ResetAcls(string[] files, uint fileCount);
103
104 /// <summary>
105 /// Gets the hash of the pCertContext->pCertInfo->SubjectPublicKeyInfo using ::CryptHashPublicKeyInfo() which does not seem
106 /// to be exposed by .NET Frameowkr.
107 /// </summary>
108 /// <param name="certContext">Pointer to a CERT_CONTEXT struct with public key information to hash.</param>
109 /// <param name="fileCount">Number of file paths in array.</param>
110 [DllImport("winterop.dll", EntryPoint = "HashPublicKeyInfo", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
111 internal static extern void HashPublicKeyInfo(IntPtr certContext, byte[] publicKeyInfoHashed, ref uint sizePublicKeyInfoHashed);
112
113 /// <summary>
114 /// Converts file time to a local file time.
115 /// </summary>
116 /// <param name="fileTime">file time</param>
117 /// <param name="localTime">local file time</param>
118 /// <returns>true if successful, false otherwise</returns>
119 [DllImport("kernel32.dll", SetLastError = true)]
120 [return: MarshalAs(UnmanagedType.Bool)]
121 internal static extern bool FileTimeToLocalFileTime(ref long fileTime, ref long localTime);
122
123 /// <summary>
124 /// Converts file time to a MS-DOS time.
125 /// </summary>
126 /// <param name="fileTime">file time</param>
127 /// <param name="wFatDate">MS-DOS date</param>
128 /// <param name="wFatTime">MS-DOS time</param>
129 /// <returns>true if successful, false otherwise</returns>
130 [DllImport("kernel32.dll", SetLastError = true)]
131 [return: MarshalAs(UnmanagedType.Bool)]
132 internal static extern bool FileTimeToDosDateTime(ref long fileTime, out ushort wFatDate, out ushort wFatTime);
133 }
134
135 /// <summary>
136 /// Interop class for the winterop.dll.
137 /// </summary>
138 internal static class CabInterop
139 {
140 /// <summary>
141 /// Delegate type that's called by cabinet api for every file in cabinet.
142 /// </summary>
143 /// <param name="fdint">NOTIFICATIONTYPE</param>
144 /// <param name="pfdin">NOTIFICATION</param>
145 /// <returns>0 for success, -1 otherwise</returns>
146 public delegate Int32 PFNNOTIFY(NOTIFICATIONTYPE fdint, NOTIFICATION pfdin);
147
148 /// <summary>
149 /// Wraps FDINOTIFICATIONTYPE.
150 /// </summary>
151 public enum NOTIFICATIONTYPE : int
152 {
153 /// <summary>Info about the cabinet.</summary>
154 CABINET_INFO,
155 /// <summary>One or more files are continued.</summary>
156 PARTIAL_FILE,
157 /// <summary>Called for each file in cabinet.</summary>
158 COPY_FILE,
159 /// <summary>Called after all of the data has been written to a target file.</summary>
160 CLOSE_FILE_INFO,
161 /// <summary>A file is continued to the next cabinet.</summary>
162 NEXT_CABINET,
163 /// <summary>Called once after a call to FDICopy() starts scanning a CAB's CFFILE entries, and again when there are no more CFFILE entries.</summary>
164 ENUMERATE,
165 }
166
167 /// <summary>
168 /// Converts DateTime to MS-DOS date and time which cabinet uses.
169 /// </summary>
170 /// <param name="dateTime">DateTime</param>
171 /// <param name="cabDate">MS-DOS date</param>
172 /// <param name="cabTime">MS-DOS time</param>
173 public static void DateTimeToCabDateAndTime(DateTime dateTime, out ushort cabDate, out ushort cabTime)
174 {
175 // dateTime.ToLocalTime() does not match FileTimeToLocalFileTime() for some reason.
176 // so we need to call FileTimeToLocalFileTime() from kernel32.dll.
177 long filetime = dateTime.ToFileTime();
178 long localTime = 0;
179 NativeMethods.FileTimeToLocalFileTime(ref filetime, ref localTime);
180 NativeMethods.FileTimeToDosDateTime(ref localTime, out cabDate, out cabTime);
181 }
182
183 /// <summary>
184 /// Wraps FDINOTIFICATION.
185 /// </summary>
186 [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
187 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
188 public class NOTIFICATION
189 {
190 private int cb;
191 [MarshalAs(UnmanagedType.LPStr)]
192 private string psz1;
193 [MarshalAs(UnmanagedType.LPStr)]
194 private string psz2;
195 [MarshalAs(UnmanagedType.LPStr)]
196 private string psz3;
197 private IntPtr pv;
198
199 private IntPtr hf;
200
201 private ushort date;
202 private ushort time;
203 private ushort attribs;
204 private ushort setID;
205 private ushort cabinet;
206 private ushort folder;
207 private int fdie;
208
209 /// <summary>
210 /// Uncompressed size of file.
211 /// </summary>
212 public int Cb
213 {
214 get { return this.cb; }
215 }
216
217 /// <summary>
218 /// File name in cabinet.
219 /// </summary>
220 public String Psz1
221 {
222 get { return this.psz1; }
223 }
224
225 /// <summary>
226 /// Name of next disk.
227 /// </summary>
228 public string Psz2
229 {
230 get { return this.psz2; }
231 }
232
233 /// <summary>
234 /// Points to a 256 character buffer.
235 /// </summary>
236 public string Psz3
237 {
238 get { return this.psz3; }
239 }
240
241 /// <summary>
242 /// Value for client.
243 /// </summary>
244 public IntPtr Pv
245 {
246 get { return this.pv; }
247 }
248
249 /// <summary>
250 /// Not used.
251 /// </summary>
252 public Int32 Hf
253 {
254 get { return (Int32)this.hf; }
255 }
256
257 /// <summary>
258 /// Last modified MS-DOS date.
259 /// </summary>
260 public ushort Date
261 {
262 get { return this.date; }
263 }
264
265 /// <summary>
266 /// Last modified MS-DOS time.
267 /// </summary>
268 public ushort Time
269 {
270 get { return this.time; }
271 }
272
273 /// <summary>
274 /// File attributes.
275 /// </summary>
276 public ushort Attribs
277 {
278 get { return this.attribs; }
279 }
280
281 /// <summary>
282 /// Cabinet set ID (a random 16-bit number).
283 /// </summary>
284 public ushort SetID
285 {
286 get { return this.setID; }
287 }
288
289 /// <summary>
290 /// Cabinet number within cabinet set (0-based).
291 /// </summary>
292 public ushort Cabinet
293 {
294 get { return this.cabinet; }
295 }
296
297 /// <summary>
298 /// File's folder index.
299 /// </summary>
300 public ushort Folder
301 {
302 get { return this.folder; }
303 }
304
305 /// <summary>
306 /// Error code.
307 /// </summary>
308 public int Fdie
309 {
310 get { return this.fdie; }
311 }
312 }
313 }
314}
315
316#endif
diff --git a/src/WixToolset.Core/Cab/WixCreateCab.cs b/src/WixToolset.Core/Cab/WixCreateCab.cs
deleted file mode 100644
index 4ebdd1c0..00000000
--- a/src/WixToolset.Core/Cab/WixCreateCab.cs
+++ /dev/null
@@ -1,249 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Cab
4{
5 using System;
6 using System.Globalization;
7 using System.IO;
8 using System.Runtime.InteropServices;
9 using WixToolset.Core.Bind;
10 using WixToolset.Core.Native;
11 using WixToolset.Data;
12
13 /// <summary>
14 /// Wrapper class around interop with wixcab.dll to compress files into a cabinet.
15 /// </summary>
16 public sealed class WixCreateCab : IDisposable
17 {
18 private static readonly string CompressionLevelVariable = "WIX_COMPRESSION_LEVEL";
19 private IntPtr handle = IntPtr.Zero;
20 private bool disposed;
21 private int maxSize;
22
23 /// <summary>
24 /// Creates a cabinet.
25 /// </summary>
26 /// <param name="cabName">Name of cabinet to create.</param>
27 /// <param name="cabDir">Directory to create cabinet in.</param>
28 /// <param name="maxFiles">Maximum number of files that will be added to cabinet.</param>
29 /// <param name="maxSize">Maximum size of cabinet.</param>
30 /// <param name="maxThresh">Maximum threshold for each cabinet.</param>
31 /// <param name="compressionLevel">Level of compression to apply.</param>
32 public WixCreateCab(string cabName, string cabDir, int maxFiles, int maxSize, int maxThresh, CompressionLevel compressionLevel)
33 {
34 string compressionLevelVariable = Environment.GetEnvironmentVariable(CompressionLevelVariable);
35 this.maxSize = maxSize;
36
37 try
38 {
39 // Override authored compression level if environment variable is present.
40 if (!String.IsNullOrEmpty(compressionLevelVariable))
41 {
42 compressionLevel = WixCreateCab.CompressionLevelFromString(compressionLevelVariable);
43 }
44 }
45 catch (WixException)
46 {
47 throw new WixException(WixErrors.IllegalEnvironmentVariable(CompressionLevelVariable, compressionLevelVariable));
48 }
49
50 if (String.IsNullOrEmpty(cabDir))
51 {
52 cabDir = Directory.GetCurrentDirectory();
53 }
54
55 try
56 {
57 NativeMethods.CreateCabBegin(cabName, cabDir, (uint)maxFiles, (uint)maxSize, (uint)maxThresh, (uint)compressionLevel, out this.handle);
58 }
59 catch (COMException ce)
60 {
61 // If we get a "the file exists" error, we must have a full temp directory - so report the issue
62 if (0x80070050 == unchecked((uint)ce.ErrorCode))
63 {
64 throw new WixException(WixErrors.FullTempDirectory("WSC", Path.GetTempPath()));
65 }
66
67 throw;
68 }
69 }
70
71 /// <summary>
72 /// Destructor for cabinet creation.
73 /// </summary>
74 ~WixCreateCab()
75 {
76 this.Dispose();
77 }
78
79 /// <summary>
80 /// Converts a compression level from its string to its enum value.
81 /// </summary>
82 /// <param name="compressionLevel">Compression level as a string.</param>
83 /// <returns>CompressionLevel enum value</returns>
84 public static CompressionLevel CompressionLevelFromString(string compressionLevel)
85 {
86 switch (compressionLevel.ToLower(CultureInfo.InvariantCulture))
87 {
88 case "low":
89 return CompressionLevel.Low;
90 case "medium":
91 return CompressionLevel.Medium;
92 case "high":
93 return CompressionLevel.High;
94 case "none":
95 return CompressionLevel.None;
96 case "mszip":
97 return CompressionLevel.Mszip;
98 default:
99 throw new WixException(WixErrors.IllegalCompressionLevel(compressionLevel));
100 }
101 }
102
103 /// <summary>
104 /// Adds a file to the cabinet.
105 /// </summary>
106 /// <param name="fileFacade">The file facade of the file to add.</param>
107 public void AddFile(FileFacade fileFacade)
108 {
109 MsiInterop.MSIFILEHASHINFO hashInterop = new MsiInterop.MSIFILEHASHINFO();
110
111 if (null != fileFacade.Hash)
112 {
113 hashInterop.FileHashInfoSize = 20;
114 hashInterop.Data0 = (int)fileFacade.Hash[2];
115 hashInterop.Data1 = (int)fileFacade.Hash[3];
116 hashInterop.Data2 = (int)fileFacade.Hash[4];
117 hashInterop.Data3 = (int)fileFacade.Hash[5];
118
119 this.AddFile(fileFacade.WixFile.Source, fileFacade.File.File, hashInterop);
120 }
121 else
122 {
123 this.AddFile(fileFacade.WixFile.Source, fileFacade.File.File);
124 }
125 }
126
127 /// <summary>
128 /// Adds a file to the cabinet.
129 /// </summary>
130 /// <param name="file">The file to add.</param>
131 /// <param name="token">The token for the file.</param>
132 public void AddFile(string file, string token)
133 {
134 this.AddFile(file, token, null);
135 }
136
137 /// <summary>
138 /// Adds a file to the cabinet with an optional MSI file hash.
139 /// </summary>
140 /// <param name="file">The file to add.</param>
141 /// <param name="token">The token for the file.</param>
142 /// <param name="fileHash">The MSI file hash of the file.</param>
143 private void AddFile(string file, string token, MsiInterop.MSIFILEHASHINFO fileHash)
144 {
145 try
146 {
147 NativeMethods.CreateCabAddFile(file, token, fileHash, this.handle);
148 }
149 catch (COMException ce)
150 {
151 if (0x80004005 == unchecked((uint)ce.ErrorCode)) // E_FAIL
152 {
153 throw new WixException(WixErrors.CreateCabAddFileFailed());
154 }
155 else if (0x80070070 == unchecked((uint)ce.ErrorCode)) // ERROR_DISK_FULL
156 {
157 throw new WixException(WixErrors.CreateCabInsufficientDiskSpace());
158 }
159 else
160 {
161 throw;
162 }
163 }
164 catch (DirectoryNotFoundException)
165 {
166 throw new WixFileNotFoundException(file);
167 }
168 catch (FileNotFoundException)
169 {
170 throw new WixFileNotFoundException(file);
171 }
172 }
173
174 /// <summary>
175 /// Complete/commit the cabinet - this must be called before Dispose so that errors will be
176 /// reported on the same thread.
177 /// This Complete should be used with no Cabinet splitting as it has the split cabinet names callback address as Zero
178 /// </summary>
179 public void Complete()
180 {
181 this.Complete(IntPtr.Zero);
182 }
183
184 /// <summary>
185 /// Complete/commit the cabinet - this must be called before Dispose so that errors will be
186 /// reported on the same thread.
187 /// </summary>
188 /// <param name="newCabNamesCallBackAddress">Address of Binder's callback function for Cabinet Splitting</param>
189 public void Complete(IntPtr newCabNamesCallBackAddress)
190 {
191 if (IntPtr.Zero != this.handle)
192 {
193 try
194 {
195 if (newCabNamesCallBackAddress != IntPtr.Zero && this.maxSize != 0)
196 {
197 NativeMethods.CreateCabFinish(this.handle, newCabNamesCallBackAddress);
198 }
199 else
200 {
201 NativeMethods.CreateCabFinish(this.handle, IntPtr.Zero);
202 }
203
204 GC.SuppressFinalize(this);
205 this.disposed = true;
206 }
207 catch (COMException ce)
208 {
209 if (0x80004005 == unchecked((uint)ce.ErrorCode)) // E_FAIL
210 {
211 // This error seems to happen, among other situations, when cabbing more than 0xFFFF files
212 throw new WixException(WixErrors.FinishCabFailed());
213 }
214 else if (0x80070070 == unchecked((uint)ce.ErrorCode)) // ERROR_DISK_FULL
215 {
216 throw new WixException(WixErrors.CreateCabInsufficientDiskSpace());
217 }
218 else
219 {
220 throw;
221 }
222 }
223 finally
224 {
225 this.handle = IntPtr.Zero;
226 }
227 }
228 }
229
230 /// <summary>
231 /// Cancels ("rolls back") the creation of the cabinet.
232 /// Don't throw WiX errors from here, because we're in a different thread, and they won't be reported correctly.
233 /// </summary>
234 public void Dispose()
235 {
236 if (!this.disposed)
237 {
238 if (IntPtr.Zero != this.handle)
239 {
240 NativeMethods.CreateCabCancel(this.handle);
241 this.handle = IntPtr.Zero;
242 }
243
244 GC.SuppressFinalize(this);
245 this.disposed = true;
246 }
247 }
248 }
249}
diff --git a/src/WixToolset.Core/Cab/WixEnumerateCab.cs b/src/WixToolset.Core/Cab/WixEnumerateCab.cs
deleted file mode 100644
index 0b4055d6..00000000
--- a/src/WixToolset.Core/Cab/WixEnumerateCab.cs
+++ /dev/null
@@ -1,89 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Cab
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Core.Native;
8 using Handle = System.Int32;
9
10 /// <summary>
11 /// Wrapper class around interop with wixcab.dll to enumerate files from a cabinet.
12 /// </summary>
13 public sealed class WixEnumerateCab : IDisposable
14 {
15 private bool disposed;
16 private List<CabinetFileInfo> fileInfoList;
17 private CabInterop.PFNNOTIFY pfnNotify;
18
19 /// <summary>
20 /// Creates a cabinet enumerator.
21 /// </summary>
22 public WixEnumerateCab()
23 {
24 this.pfnNotify = new CabInterop.PFNNOTIFY(this.Notify);
25 NativeMethods.EnumerateCabBegin();
26 }
27
28 /// <summary>
29 /// Destructor for cabinet enumeration.
30 /// </summary>
31 ~WixEnumerateCab()
32 {
33 this.Dispose();
34 }
35
36 /// <summary>
37 /// Enumerates all files in a cabinet.
38 /// </summary>
39 /// <param name="cabinetFile">path to cabinet</param>
40 /// <returns>list of CabinetFileInfo</returns>
41 public List<CabinetFileInfo> Enumerate(string cabinetFile)
42 {
43 this.fileInfoList = new List<CabinetFileInfo>();
44
45 // the callback (this.Notify) will populate the list for each file in cabinet
46 NativeMethods.EnumerateCab(cabinetFile, this.pfnNotify);
47
48 return this.fileInfoList;
49 }
50
51 /// <summary>
52 /// Disposes the managed and unmanaged objects in this object.
53 /// </summary>
54 public void Dispose()
55 {
56 if (!this.disposed)
57 {
58 NativeMethods.EnumerateCabFinish();
59
60 GC.SuppressFinalize(this);
61 this.disposed = true;
62 }
63 }
64
65 /// <summary>
66 /// Delegate that's called for every file in cabinet.
67 /// </summary>
68 /// <param name="fdint">NOTIFICATIONTYPE</param>
69 /// <param name="pfdin">NOTIFICATION</param>
70 /// <returns>System.Int32</returns>
71 internal Handle Notify(CabInterop.NOTIFICATIONTYPE fdint, CabInterop.NOTIFICATION pfdin)
72 {
73 // This is FDI's way of notifying us of how many files total are in the cab, accurate even
74 // if the files are split into multiple folders - use it to allocate the precise size we need
75 if (CabInterop.NOTIFICATIONTYPE.ENUMERATE == fdint && 0 == this.fileInfoList.Count)
76 {
77 this.fileInfoList.Capacity = pfdin.Folder;
78 }
79
80 if (fdint == CabInterop.NOTIFICATIONTYPE.COPY_FILE)
81 {
82 CabinetFileInfo fileInfo = new CabinetFileInfo(pfdin.Psz1, pfdin.Date, pfdin.Time, pfdin.Cb);
83 this.fileInfoList.Add(fileInfo);
84 }
85
86 return 0; // tell cabinet api to skip this file.
87 }
88 }
89}
diff --git a/src/WixToolset.Core/Cab/WixExtractCab.cs b/src/WixToolset.Core/Cab/WixExtractCab.cs
deleted file mode 100644
index e776b08e..00000000
--- a/src/WixToolset.Core/Cab/WixExtractCab.cs
+++ /dev/null
@@ -1,75 +0,0 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Cab
4{
5 using System;
6 using WixToolset.Core.Native;
7
8 /// <summary>
9 /// Wrapper class around interop with wixcab.dll to extract files from a cabinet.
10 /// </summary>
11 public sealed class WixExtractCab : IDisposable
12 {
13 private bool disposed;
14
15 /// <summary>
16 /// Creates a cabinet extractor.
17 /// </summary>
18 public WixExtractCab()
19 {
20 NativeMethods.ExtractCabBegin();
21 }
22
23 /// <summary>
24 /// Destructor for cabinet extraction.
25 /// </summary>
26 ~WixExtractCab()
27 {
28 this.Dispose();
29 }
30
31 /// <summary>
32 /// Extracts all the files from a cabinet to a directory.
33 /// </summary>
34 /// <param name="cabinetFile">Cabinet file to extract from.</param>
35 /// <param name="extractDir">Directory to extract files to.</param>
36 public void Extract(string cabinetFile, string extractDir)
37 {
38 if (null == cabinetFile)
39 {
40 throw new ArgumentNullException("cabinetFile");
41 }
42
43 if (null == extractDir)
44 {
45 throw new ArgumentNullException("extractDir");
46 }
47
48 if (this.disposed)
49 {
50 throw new ObjectDisposedException("WixExtractCab");
51 }
52
53 if (!extractDir.EndsWith("\\", StringComparison.Ordinal))
54 {
55 extractDir = String.Concat(extractDir, "\\");
56 }
57
58 NativeMethods.ExtractCab(cabinetFile, extractDir);
59 }
60
61 /// <summary>
62 /// Disposes the managed and unmanaged objects in this object.
63 /// </summary>
64 public void Dispose()
65 {
66 if (!this.disposed)
67 {
68 NativeMethods.ExtractCabFinish();
69
70 GC.SuppressFinalize(this);
71 this.disposed = true;
72 }
73 }
74 }
75}
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index 4b1ef033..406bc46a 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -5803,7 +5803,7 @@ namespace WixToolset.Core
5803 wixFileRow.File_AssemblyApplication = assemblyApplication; 5803 wixFileRow.File_AssemblyApplication = assemblyApplication;
5804 wixFileRow.Directory_ = directoryId; 5804 wixFileRow.Directory_ = directoryId;
5805 wixFileRow.DiskId = (CompilerConstants.IntegerNotSet == diskId) ? 0 : diskId; 5805 wixFileRow.DiskId = (CompilerConstants.IntegerNotSet == diskId) ? 0 : diskId;
5806 wixFileRow.Source = source; 5806 wixFileRow.Source = new IntermediateFieldPathValue { Path = source };
5807 wixFileRow.ProcessorArchitecture = procArch; 5807 wixFileRow.ProcessorArchitecture = procArch;
5808 wixFileRow.PatchGroup = (CompilerConstants.IntegerNotSet != patchGroup ? patchGroup : -1); 5808 wixFileRow.PatchGroup = (CompilerConstants.IntegerNotSet != patchGroup ? patchGroup : -1);
5809 wixFileRow.Attributes = (generatedShortFileName ? 0x1 : 0x0); 5809 wixFileRow.Attributes = (generatedShortFileName ? 0x1 : 0x0);
diff --git a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
index 9c3b2765..266871bd 100644
--- a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
+++ b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs
@@ -62,7 +62,7 @@ namespace WixToolset.Link
62 { 62 {
63 // If we're building a Merge Module, ignore all references to the Media table 63 // If we're building a Merge Module, ignore all references to the Media table
64 // because Merge Modules don't have Media tables. 64 // because Merge Modules don't have Media tables.
65 if (this.BuildingMergeModule && wixSimpleReferenceRow.Definition.Type == TupleDefinitionType.Media) 65 if (this.BuildingMergeModule && wixSimpleReferenceRow.Table== "Media")
66 { 66 {
67 continue; 67 continue;
68 } 68 }
diff --git a/src/WixToolset.Core/Preprocess/IfContext.cs b/src/WixToolset.Core/Preprocess/IfContext.cs
index 64b5bd91..e7c6e6f5 100644
--- a/src/WixToolset.Core/Preprocess/IfContext.cs
+++ b/src/WixToolset.Core/Preprocess/IfContext.cs
@@ -1,46 +1,21 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. 1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 2
3namespace WixToolset.Preprocess 3namespace WixToolset.Core.Preprocess
4{ 4{
5 using System;
6
7 /// <summary>
8 /// Current state of the if context.
9 /// </summary>
10 internal enum IfState
11 {
12 /// <summary>Context currently in unknown state.</summary>
13 Unknown,
14
15 /// <summary>Context currently inside if statement.</summary>
16 If,
17
18 /// <summary>Context currently inside elseif statement..</summary>
19 ElseIf,
20
21 /// <summary>Conext currently inside else statement.</summary>
22 Else,
23 }
24
25 /// <summary> 5 /// <summary>
26 /// Context for an if statement in the preprocessor. 6 /// Context for an if statement in the preprocessor.
27 /// </summary> 7 /// </summary>
28 internal sealed class IfContext 8 internal sealed class IfContext
29 { 9 {
30 private bool active;
31 private bool keep; 10 private bool keep;
32 private bool everKept;
33 private IfState state;
34 11
35 /// <summary> 12 /// <summary>
36 /// Creates a default if context object, which are used for if's within an inactive preprocessor block 13 /// Creates a default if context object, which are used for if's within an inactive preprocessor block
37 /// </summary> 14 /// </summary>
38 public IfContext() 15 public IfContext()
39 { 16 {
40 this.active = false; 17 this.WasEverTrue = true;
41 this.keep = false; 18 this.IfState = IfState.If;
42 this.everKept = true;
43 this.state = IfState.If;
44 } 19 }
45 20
46 /// <summary> 21 /// <summary>
@@ -51,21 +26,17 @@ namespace WixToolset.Preprocess
51 /// <param name="state">State of context to start in.</param> 26 /// <param name="state">State of context to start in.</param>
52 public IfContext(bool active, bool keep, IfState state) 27 public IfContext(bool active, bool keep, IfState state)
53 { 28 {
54 this.active = active; 29 this.Active = active;
55 this.keep = keep; 30 this.keep = keep;
56 this.everKept = keep; 31 this.WasEverTrue = keep;
57 this.state = state; 32 this.IfState = IfState.If;
58 } 33 }
59 34
60 /// <summary> 35 /// <summary>
61 /// Gets and sets if this if context is currently active. 36 /// Gets and sets if this if context is currently active.
62 /// </summary> 37 /// </summary>
63 /// <value>true if context is active.</value> 38 /// <value>true if context is active.</value>
64 public bool Active 39 public bool Active { get; set; }
65 {
66 get { return this.active; }
67 set { this.active = value; }
68 }
69 40
70 /// <summary> 41 /// <summary>
71 /// Gets and sets if context is current true. 42 /// Gets and sets if context is current true.
@@ -83,7 +54,7 @@ namespace WixToolset.Preprocess
83 this.keep = value; 54 this.keep = value;
84 if (this.keep) 55 if (this.keep)
85 { 56 {
86 this.everKept = true; 57 this.WasEverTrue = true;
87 } 58 }
88 } 59 }
89 } 60 }
@@ -92,19 +63,12 @@ namespace WixToolset.Preprocess
92 /// Gets if the context was ever true. 63 /// Gets if the context was ever true.
93 /// </summary> 64 /// </summary>
94 /// <value>True if context was ever true.</value> 65 /// <value>True if context was ever true.</value>
95 public bool WasEverTrue 66 public bool WasEverTrue { get; private set; }
96 {
97 get { return this.everKept; }
98 }
99 67
100 /// <summary> 68 /// <summary>
101 /// Gets the current state of the if context. 69 /// Gets the current state of the if context.
102 /// </summary> 70 /// </summary>
103 /// <value>Current state of context.</value> 71 /// <value>Current state of context.</value>
104 public IfState IfState 72 public IfState IfState { get; set; }
105 {
106 get { return this.state; }
107 set { this.state = value; }
108 }
109 } 73 }
110} 74}
diff --git a/src/WixToolset.Core/Preprocess/IfState.cs b/src/WixToolset.Core/Preprocess/IfState.cs
new file mode 100644
index 00000000..f5bb3e87
--- /dev/null
+++ b/src/WixToolset.Core/Preprocess/IfState.cs
@@ -0,0 +1,22 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Preprocess
4{
5 /// <summary>
6 /// Current state of the if context.
7 /// </summary>
8 internal enum IfState
9 {
10 /// <summary>Context currently in unknown state.</summary>
11 Unknown,
12
13 /// <summary>Context currently inside if statement.</summary>
14 If,
15
16 /// <summary>Context currently inside elseif statement..</summary>
17 ElseIf,
18
19 /// <summary>Conext currently inside else statement.</summary>
20 Else,
21 }
22}
diff --git a/src/WixToolset.Core/Preprocessor.cs b/src/WixToolset.Core/Preprocessor.cs
index 23f568a8..3aed0735 100644
--- a/src/WixToolset.Core/Preprocessor.cs
+++ b/src/WixToolset.Core/Preprocessor.cs
@@ -13,7 +13,7 @@ namespace WixToolset.Core
13 using System.Xml.Linq; 13 using System.Xml.Linq;
14 using WixToolset.Data; 14 using WixToolset.Data;
15 using WixToolset.Extensibility; 15 using WixToolset.Extensibility;
16 using WixToolset.Preprocess; 16 using WixToolset.Core.Preprocess;
17 17
18 /// <summary> 18 /// <summary>
19 /// Preprocessor object 19 /// Preprocessor object
diff --git a/src/WixToolset.Data.WindowsInstaller/ColumnDefinition.cs b/src/WixToolset.Data.WindowsInstaller/ColumnDefinition.cs
index 7e5a07c5..056be1e9 100644
--- a/src/WixToolset.Data.WindowsInstaller/ColumnDefinition.cs
+++ b/src/WixToolset.Data.WindowsInstaller/ColumnDefinition.cs
@@ -975,7 +975,8 @@ namespace WixToolset.Data
975 { 975 {
976 if (!(value is string)) 976 if (!(value is string))
977 { 977 {
978 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot set string column '{0}' with a value of type '{1}'.", this.name, value.GetType().ToString())); 978 //throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot set string column '{0}' with a value of type '{1}'.", this.name, value.GetType().ToString()));
979 return value.ToString();
979 } 980 }
980 } 981 }
981 } 982 }
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs b/src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs
index 4b4daeda..da9f3a38 100644
--- a/src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs
@@ -39,5 +39,52 @@ namespace WixToolsetTest.CoreIntegrationFixture
39 Assert.Equal(@"test.txt", wixFile[WixFileTupleFields.Source].PreviousValue.AsPath().Path); 39 Assert.Equal(@"test.txt", wixFile[WixFileTupleFields.Source].PreviousValue.AsPath().Path);
40 } 40 }
41 } 41 }
42
43 [Fact]
44 public void CanBuildSimpleModule()
45 {
46 var folder = TestData.Get(@"TestData\SimpleModule");
47
48 using (var fs = new DisposableFileSystem())
49 using (var pushd = new Pushd(folder))
50 {
51 var intermediateFolder = fs.GetFolder();
52
53 var program = new Program();
54 var result = program.Run(new WixToolsetServiceProvider(), new[] { "build", "Module.wxs", "-loc", "Module.en-us.wxl", "-bindpath", "data", "-intermediateFolder", intermediateFolder, "-o", $@"{intermediateFolder}\bin\test.msm" });
55
56 Assert.Equal(0, result);
57
58 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msm")));
59 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb")));
60
61 var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wir"));
62 Assert.Single(intermediate.Sections);
63
64 var wixFile = intermediate.Sections.SelectMany(s => s.Tuples).OfType<WixFileTuple>().Single();
65 Assert.Equal(@"data\test.txt", wixFile[WixFileTupleFields.Source].AsPath().Path);
66 Assert.Equal(@"test.txt", wixFile[WixFileTupleFields.Source].PreviousValue.AsPath().Path);
67 }
68 }
69
70 [Fact(Skip = "Not implemented yet.")]
71 public void CanBuildInstanceTransform()
72 {
73 var folder = TestData.Get(@"TestData\InstanceTransform");
74
75 using (var fs = new DisposableFileSystem())
76 using (var pushd = new Pushd(folder))
77 {
78 var intermediateFolder = fs.GetFolder();
79
80 var program = new Program();
81 var result = program.Run(new WixToolsetServiceProvider(), new[] { "build", "Package.wxs", "PackageComponents.wxs", "-loc", "Package.en-us.wxl", "-bindpath", "data", "-intermediateFolder", intermediateFolder, "-o", $@"{intermediateFolder}\bin\test.msi" });
82
83 Assert.Equal(0, result);
84
85 var pdb = Pdb.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb"), false);
86 Assert.NotEmpty(pdb.Output.SubStorages);
87 }
88 }
42 } 89 }
43} 90}
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.en-us.wxl b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.en-us.wxl
new file mode 100644
index 00000000..38c12ac1
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.en-us.wxl
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<!--
4This file contains the declaration of all the localizable strings.
5-->
6<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
8 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9 <String Id="FeatureTitle">MsiPackage</String>
10
11</WixLocalization>
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.wxs b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.wxs
new file mode 100644
index 00000000..9c529668
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/Package.wxs
@@ -0,0 +1,27 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Product Id="*" Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4 <Package InstallerVersion="200" Compressed="no" InstallScope="perMachine" />
5
6 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
7 <MediaTemplate />
8
9 <Property Id="INSTANCEPROPERTY" Secure="yes" />
10
11 <InstanceTransforms Property="INSTANCEPROPERTY">
12 <Instance Id="I1" ProductCode="*" ProductName="MsiPackage (Instance 1)" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" />
13 </InstanceTransforms>
14
15 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
16 <ComponentGroupRef Id="ProductComponents" />
17 </Feature>
18 </Product>
19
20 <Fragment>
21 <Directory Id="TARGETDIR" Name="SourceDir">
22 <Directory Id="ProgramFilesFolder">
23 <Directory Id="INSTALLFOLDER" Name="MsiPackageInstance" />
24 </Directory>
25 </Directory>
26 </Fragment>
27</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/PackageComponents.wxs b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/PackageComponents.wxs
new file mode 100644
index 00000000..e26c4509
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/PackageComponents.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
5 <Component>
6 <File Source="test.txt" />
7 </Component>
8 </ComponentGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/data/test.txt b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/data/test.txt
new file mode 100644
index 00000000..cd0db0e1
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/InstanceTransform/data/test.txt
@@ -0,0 +1 @@
This is test.txt. \ No newline at end of file
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.en-us.wxl b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.en-us.wxl
new file mode 100644
index 00000000..c74e86a7
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.en-us.wxl
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<!--
4This file contains the declaration of all the localizable strings.
5-->
6<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
8 <String Id="Manufacturer">Example Company</String>
9
10</WixLocalization>
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wixproj b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wixproj
new file mode 100644
index 00000000..597d4318
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wixproj
@@ -0,0 +1,48 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
6 <ProductVersion>0.9</ProductVersion>
7 <ProjectGuid>27df04c6-3cef-4b9a-bac6-4e78d188384f</ProjectGuid>
8 <OutputName>MergeModule1</OutputName>
9 <OutputType>Module</OutputType>
10 <Name>MergeModule1</Name>
11 <RootNamespace>MergeModule1</RootNamespace>
12 </PropertyGroup>
13 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
14 <PlatformName>$(Platform)</PlatformName>
15 <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
16 <DefineConstants>Debug</DefineConstants>
17 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
19 <PlatformName>$(Platform)</PlatformName>
20 <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
21 </PropertyGroup>
22 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
23 <PlatformName>$(Platform)</PlatformName>
24 <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
25 <DefineConstants>Debug</DefineConstants>
26 </PropertyGroup>
27 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
28 <PlatformName>$(Platform)</PlatformName>
29 <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
30 </PropertyGroup>
31 <ItemGroup>
32 <Compile Include="MergeModule.wxs" />
33 </ItemGroup>
34 <ItemGroup>
35 <EmbeddedResource Include="MergeModule.en-us.wxl" />
36 </ItemGroup>
37 <ItemGroup>
38 <WixExtension Include="FgwepExtension.wixext">
39 <Name>FgwepExtension.wixext</Name>
40 <HintPath>$(WixExtDir)\FgwepExtension.wixext.dll</HintPath>
41 </WixExtension>
42 </ItemGroup>
43 <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
44 <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\wix.targets') " />
45 <Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
46 <Error Text="FG-WiX or WiX Toolset build tools (v3.11 or later) must be installed to build this project. To download FG-WiX, go to https://www.firegiant.com/downloads/. To download the WiX Toolset, go to http://wixtoolset.org/releases/." />
47 </Target>
48</Project> \ No newline at end of file
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wxs b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wxs
new file mode 100644
index 00000000..260339ba
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/Module.wxs
@@ -0,0 +1,16 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Module Id="MergeModule1" Language="1033" Version="1.0.0.0">
4 <Package Id="243FB739-4D05-472F-9CFB-EF6B1017B6DE" Manufacturer="!(loc.Manufacturer)" InstallerVersion="200" />
5
6 <Directory Id="TARGETDIR" Name="SourceDir">
7 <Directory Id="MergeRedirectFolder">
8
9 <Component Id="ModuleComponent" Guid="A04E61B2-3ED4-4803-B2EB-4B773576FA45">
10 <File Source="test.txt" />
11 </Component>
12
13 </Directory>
14 </Directory>
15 </Module>
16</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/data/test.txt b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/data/test.txt
new file mode 100644
index 00000000..cd0db0e1
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/TestData/SimpleModule/data/test.txt
@@ -0,0 +1 @@
This is test.txt. \ No newline at end of file
diff --git a/src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj b/src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj
index bce6e6b2..f9042cda 100644
--- a/src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj
+++ b/src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj
@@ -7,11 +7,14 @@
7 <IsPackable>false</IsPackable> 7 <IsPackable>false</IsPackable>
8 </PropertyGroup> 8 </PropertyGroup>
9 9
10 <PropertyGroup>
11 <NoWarn>NU1701</NoWarn>
12 </PropertyGroup>
13
14 <ItemGroup> 10 <ItemGroup>
11 <Content Include="TestData\SimpleModule\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
12 <Content Include="TestData\SimpleModule\Module.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
13 <Content Include="TestData\SimpleModule\Module.wxs" CopyToOutputDirectory="PreserveNewest" />
14 <Content Include="TestData\InstanceTransform\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
15 <Content Include="TestData\InstanceTransform\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
16 <Content Include="TestData\InstanceTransform\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
17 <Content Include="TestData\InstanceTransform\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
15 <Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" /> 18 <Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
16 <Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> 19 <Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
17 <Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" /> 20 <Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" />