aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.Native/LongPathUtil.cs78
-rw-r--r--src/wix/WixToolset.Core.Native/Msi/Database.cs119
-rw-r--r--src/wix/WixToolset.Core.Native/Msi/Installer.cs22
-rw-r--r--src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs2
-rw-r--r--src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs4
-rw-r--r--src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs4
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs4
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs9
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs3
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs2
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs2
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs89
-rw-r--r--src/wix/wixnative/wixnative.manifest9
-rw-r--r--src/wix/wixnative/wixnative.vcxproj3
21 files changed, 323 insertions, 41 deletions
diff --git a/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs
index 5231e0be..70b98222 100644
--- a/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs
@@ -69,7 +69,7 @@ namespace WixToolset.Core.Burn.Bind
69 { 69 {
70 var payload = payloadSymbolsById[msiPackage.PayloadRef]; 70 var payload = payloadSymbolsById[msiPackage.PayloadRef];
71 71
72 using (var db = new Database(payload.SourceFile.Path, OpenDatabase.ReadOnly)) 72 using (var db = Database.OpenAsReadOnly(payload.SourceFile.Path))
73 { 73 {
74 if (db.TableExists("SoftwareIdentificationTag")) 74 if (db.TableExists("SoftwareIdentificationTag"))
75 { 75 {
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
index d6cf1cfd..0b78c545 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
@@ -164,7 +164,7 @@ namespace WixToolset.Core.Burn.Bundles
164 164
165 this.CheckIfWindowsInstallerFileTooLarge(this.PackagePayload.SourceLineNumbers, sourcePath, "MSI"); 165 this.CheckIfWindowsInstallerFileTooLarge(this.PackagePayload.SourceLineNumbers, sourcePath, "MSI");
166 166
167 using (var db = new Database(sourcePath, OpenDatabase.ReadOnly)) 167 using (var db = Database.OpenAsReadOnly(sourcePath))
168 { 168 {
169 // Read data out of the msi database... 169 // Read data out of the msi database...
170 using (var sumInfo = new SummaryInformation(db)) 170 using (var sumInfo = new SummaryInformation(db))
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
index b889c2ce..8d1e9c39 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
@@ -98,7 +98,7 @@ namespace WixToolset.Core.Burn.Bundles
98 98
99 try 99 try
100 { 100 {
101 using (var db = new Database(sourcePath, OpenDatabase.ReadOnly | OpenDatabase.OpenPatchFile)) 101 using (var db = Database.OpenAsReadOnly(sourcePath, asPatch: true))
102 { 102 {
103 // Read data out of the msp database... 103 // Read data out of the msp database...
104 using (var sumInfo = new SummaryInformation(db)) 104 using (var sumInfo = new SummaryInformation(db))
diff --git a/src/wix/WixToolset.Core.Native/LongPathUtil.cs b/src/wix/WixToolset.Core.Native/LongPathUtil.cs
new file mode 100644
index 00000000..c24f1736
--- /dev/null
+++ b/src/wix/WixToolset.Core.Native/LongPathUtil.cs
@@ -0,0 +1,78 @@
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.Native
4{
5 using System.IO;
6 using System.Runtime.InteropServices;
7 using System.Text;
8
9 internal static class PathUtil
10 {
11 private const int MaxPath = 260;
12 private const string LongPathPrefix = @"\\?\";
13
14 public static bool CreateOrGetShortPath(string path, out string shortPath)
15 {
16 var fileCreated = false;
17
18 // The file must exist so we can get its short path.
19 if (!File.Exists(path))
20 {
21 using (File.Create(path))
22 {
23 }
24
25 fileCreated = true;
26 }
27
28 // Use the short path to avoid issues with long paths in the MSI API.
29 shortPath = GetShortPath(path);
30
31 return fileCreated;
32 }
33
34 public static string GetPrefixedLongPath(string path)
35 {
36 if (path.Length > MaxPath && !path.StartsWith(LongPathPrefix))
37 {
38 path = LongPathPrefix + path;
39 }
40
41 return path;
42 }
43
44 public static string GetShortPath(string longPath)
45 {
46 var path = GetPrefixedLongPath(longPath);
47
48 var buffer = new StringBuilder(MaxPath); // start with MAX_PATH.
49
50 var result = GetShortPathName(path, buffer, (uint)buffer.Capacity);
51
52 // If result > buffer.Capacity, reallocate and call again (even though we're usually using short names to avoid long path)
53 // so the short path result is still going to end up too long for APIs requiring a short path.
54 if (result > buffer.Capacity)
55 {
56 buffer = new StringBuilder((int)result);
57
58 result = GetShortPathName(path, buffer, (uint)buffer.Capacity);
59 }
60
61 // If we succeeded, return the short path without the prefix.
62 if (result > 0)
63 {
64 path = buffer.ToString();
65
66 if (path.StartsWith(LongPathPrefix))
67 {
68 path = path.Substring(LongPathPrefix.Length);
69 }
70 }
71
72 return path;
73 }
74
75 [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
76 private static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer);
77 }
78}
diff --git a/src/wix/WixToolset.Core.Native/Msi/Database.cs b/src/wix/WixToolset.Core.Native/Msi/Database.cs
index ff966302..33eb8de6 100644
--- a/src/wix/WixToolset.Core.Native/Msi/Database.cs
+++ b/src/wix/WixToolset.Core.Native/Msi/Database.cs
@@ -18,7 +18,7 @@ namespace WixToolset.Core.Native.Msi
18 /// </summary> 18 /// </summary>
19 /// <param name="path">Path to the database to be opened.</param> 19 /// <param name="path">Path to the database to be opened.</param>
20 /// <param name="type">Persist mode to use when opening the database.</param> 20 /// <param name="type">Persist mode to use when opening the database.</param>
21 public Database(string path, OpenDatabase type) 21 private Database(string path, OpenDatabase type)
22 { 22 {
23 var error = MsiInterop.MsiOpenDatabase(path, (IntPtr)type, out var handle); 23 var error = MsiInterop.MsiOpenDatabase(path, (IntPtr)type, out var handle);
24 if (0 != error) 24 if (0 != error)
@@ -35,14 +35,89 @@ namespace WixToolset.Core.Native.Msi
35 public static int MsiMaxStreamNameLength => MsiInterop.MsiMaxStreamNameLength; 35 public static int MsiMaxStreamNameLength => MsiInterop.MsiMaxStreamNameLength;
36 36
37 /// <summary> 37 /// <summary>
38 /// Creates a new <see cref="Database"/> with the specified path.
39 /// </summary>
40 /// <param name="path">Path of database to be created.</param>
41 /// <param name="asPatch">Indicates whether the database should be opened as a patch file.</param>
42 public static Database Create(string path, bool asPatch = false)
43 {
44 var fileCreated = false;
45 var mode = OpenDatabase.CreateDirect;
46
47 if (asPatch)
48 {
49 mode |= OpenDatabase.OpenPatchFile;
50 }
51
52 try
53 {
54 fileCreated = PathUtil.CreateOrGetShortPath(path, out var shortPath);
55
56 return new Database(shortPath, mode);
57 }
58 catch // cleanup on error if we created the short path file.
59 {
60 if (fileCreated)
61 {
62 File.Delete(path);
63 }
64
65 throw;
66 }
67 }
68
69 /// <summary>
70 /// Opens an existing <see cref="Database"/> with the specified path.
71 /// </summary>
72 /// <param name="path">Path of database to open.</param>
73 /// <param name="transact">Indicates whether to open the database in transaction mode.</param>
74 /// <param name="asPatch">Indicates whether the database should be opened as a patch file.</param>
75 public static Database Open(string path, bool transact = false, bool asPatch = false)
76 {
77 var mode = transact ? OpenDatabase.Transact : OpenDatabase.Direct;
78
79 if (asPatch)
80 {
81 mode |= OpenDatabase.OpenPatchFile;
82 }
83
84 // Use the short path to avoid issues with long paths in the MSI API.
85 var shortPath = PathUtil.GetShortPath(path);
86
87 return new Database(shortPath, mode);
88 }
89
90 /// <summary>
91 /// Opens an existing <see cref="Database"/> with the specified path.
92 /// </summary>
93 /// <param name="path">Path of database to open.</param>
94 /// <param name="asPatch">Indicates whether the database should be opened as a patch file.</param>
95 public static Database OpenAsReadOnly(string path, bool asPatch = false)
96 {
97 var mode = OpenDatabase.ReadOnly;
98
99 if (asPatch)
100 {
101 mode |= OpenDatabase.OpenPatchFile;
102 }
103
104 // Use the short path to avoid issues with long paths in the MSI API.
105 var shortPath = PathUtil.GetShortPath(path);
106
107 return new Database(shortPath, mode);
108 }
109
110 /// <summary>
38 /// Apply a transform to the MSI. 111 /// Apply a transform to the MSI.
39 /// </summary> 112 /// </summary>
40 /// <param name="transformFile">Path to transform to apply.</param> 113 /// <param name="transformFile">Path to transform to apply.</param>
41 public void ApplyTransform(string transformFile) 114 public void ApplyTransform(string transformFile)
42 { 115 {
116 var shortTransformFile = PathUtil.GetShortPath(transformFile);
117
43 // get the curret validation bits 118 // get the curret validation bits
44 var conditions = TransformErrorConditions.None; 119 var conditions = TransformErrorConditions.None;
45 using (var summaryInfo = new SummaryInformation(transformFile)) 120 using (var summaryInfo = new SummaryInformation(shortTransformFile))
46 { 121 {
47 try 122 try
48 { 123 {
@@ -65,7 +140,9 @@ namespace WixToolset.Core.Native.Msi
65 /// <param name="errorConditions">Specifies the error conditions that are to be suppressed.</param> 140 /// <param name="errorConditions">Specifies the error conditions that are to be suppressed.</param>
66 public void ApplyTransform(string transformFile, TransformErrorConditions errorConditions) 141 public void ApplyTransform(string transformFile, TransformErrorConditions errorConditions)
67 { 142 {
68 var error = MsiInterop.MsiDatabaseApplyTransform(this.Handle, transformFile, errorConditions); 143 var shortTransformFile = PathUtil.GetShortPath(transformFile);
144
145 var error = MsiInterop.MsiDatabaseApplyTransform(this.Handle, shortTransformFile, errorConditions);
69 if (0 != error) 146 if (0 != error)
70 { 147 {
71 throw new MsiException(error); 148 throw new MsiException(error);
@@ -119,7 +196,9 @@ namespace WixToolset.Core.Native.Msi
119 /// shows which properties should be validated to verify that this transform can be applied to the database.</param> 196 /// shows which properties should be validated to verify that this transform can be applied to the database.</param>
120 public void CreateTransformSummaryInfo(Database referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations) 197 public void CreateTransformSummaryInfo(Database referenceDatabase, string transformFile, TransformErrorConditions errorConditions, TransformValidations validations)
121 { 198 {
122 var error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, transformFile, errorConditions, validations); 199 var shortTransformFile = PathUtil.GetShortPath(transformFile);
200
201 var error = MsiInterop.MsiCreateTransformSummaryInfo(this.Handle, referenceDatabase.Handle, shortTransformFile, errorConditions, validations);
123 if (0 != error) 202 if (0 != error)
124 { 203 {
125 throw new MsiException(error); 204 throw new MsiException(error);
@@ -137,7 +216,9 @@ namespace WixToolset.Core.Native.Msi
137 var folderPath = Path.GetFullPath(Path.GetDirectoryName(idtPath)); 216 var folderPath = Path.GetFullPath(Path.GetDirectoryName(idtPath));
138 var fileName = Path.GetFileName(idtPath); 217 var fileName = Path.GetFileName(idtPath);
139 218
140 var error = MsiInterop.MsiDatabaseImport(this.Handle, folderPath, fileName); 219 var shortFolderPath = PathUtil.GetShortPath(folderPath);
220
221 var error = MsiInterop.MsiDatabaseImport(this.Handle, shortFolderPath, fileName);
141 if (1627 == error) // ERROR_FUNCTION_FAILED 222 if (1627 == error) // ERROR_FUNCTION_FAILED
142 { 223 {
143 throw new WixInvalidIdtException(idtPath); 224 throw new WixInvalidIdtException(idtPath);
@@ -161,7 +242,9 @@ namespace WixToolset.Core.Native.Msi
161 folderPath = Environment.CurrentDirectory; 242 folderPath = Environment.CurrentDirectory;
162 } 243 }
163 244
164 var error = MsiInterop.MsiDatabaseExport(this.Handle, tableName, folderPath, fileName); 245 var shortFolderPath = PathUtil.GetShortPath(folderPath);
246
247 var error = MsiInterop.MsiDatabaseExport(this.Handle, tableName, shortFolderPath, fileName);
165 if (0 != error) 248 if (0 != error)
166 { 249 {
167 throw new MsiException(error); 250 throw new MsiException(error);
@@ -177,13 +260,29 @@ namespace WixToolset.Core.Native.Msi
177 /// there are no differences between the two databases.</returns> 260 /// there are no differences between the two databases.</returns>
178 public bool GenerateTransform(Database referenceDatabase, string transformFile) 261 public bool GenerateTransform(Database referenceDatabase, string transformFile)
179 { 262 {
180 var error = MsiInterop.MsiDatabaseGenerateTransform(this.Handle, referenceDatabase.Handle, transformFile, 0, 0); 263 var fileCreated = false;
181 if (0 != error && 0xE8 != error) // ERROR_NO_DATA(0xE8) means no differences were found 264
265 try
182 { 266 {
183 throw new MsiException(error); 267 fileCreated = PathUtil.CreateOrGetShortPath(transformFile, out var shortTransformFile);
268
269 var error = MsiInterop.MsiDatabaseGenerateTransform(this.Handle, referenceDatabase.Handle, shortTransformFile, 0, 0);
270 if (0 != error && 0xE8 != error) // ERROR_NO_DATA(0xE8) means no differences were found
271 {
272 throw new MsiException(error);
273 }
274
275 return (0xE8 != error);
184 } 276 }
277 catch // Cleanup on error
278 {
279 if (fileCreated)
280 {
281 File.Delete(transformFile);
282 }
185 283
186 return (0xE8 != error); 284 throw;
285 }
187 } 286 }
188 287
189 /// <summary> 288 /// <summary>
diff --git a/src/wix/WixToolset.Core.Native/Msi/Installer.cs b/src/wix/WixToolset.Core.Native/Msi/Installer.cs
index b2c2c630..14745469 100644
--- a/src/wix/WixToolset.Core.Native/Msi/Installer.cs
+++ b/src/wix/WixToolset.Core.Native/Msi/Installer.cs
@@ -34,11 +34,13 @@ namespace WixToolset.Core.Native.Msi
34 var buffer = new StringBuilder(65535); 34 var buffer = new StringBuilder(65535);
35 var size = buffer.Capacity; 35 var size = buffer.Capacity;
36 36
37 var error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); 37 var shortPath = PathUtil.GetShortPath(path);
38
39 var error = MsiInterop.MsiExtractPatchXMLData(shortPath, 0, buffer, ref size);
38 if (234 == error) 40 if (234 == error)
39 { 41 {
40 buffer.EnsureCapacity(++size); 42 buffer.EnsureCapacity(++size);
41 error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); 43 error = MsiInterop.MsiExtractPatchXMLData(shortPath, 0, buffer, ref size);
42 } 44 }
43 45
44 if (error != 0) 46 if (error != 0)
@@ -57,8 +59,12 @@ namespace WixToolset.Core.Native.Msi
57 /// <param name="hash">Int array that receives the returned file hash information.</param> 59 /// <param name="hash">Int array that receives the returned file hash information.</param>
58 public static void GetFileHash(string filePath, int options, out int[] hash) 60 public static void GetFileHash(string filePath, int options, out int[] hash)
59 { 61 {
60 var hashInterop = new MSIFILEHASHINFO(); 62 var hashInterop = new MSIFILEHASHINFO
61 hashInterop.FileHashInfoSize = 20; 63 {
64 FileHashInfoSize = 20
65 };
66
67 filePath = PathUtil.GetPrefixedLongPath(filePath);
62 68
63 var error = MsiInterop.MsiGetFileHash(filePath, Convert.ToUInt32(options), hashInterop); 69 var error = MsiInterop.MsiGetFileHash(filePath, Convert.ToUInt32(options), hashInterop);
64 if (0 != error) 70 if (0 != error)
@@ -76,9 +82,9 @@ namespace WixToolset.Core.Native.Msi
76 } 82 }
77 83
78 /// <summary> 84 /// <summary>
79 /// Returns the version string and language string in the format that the installer 85 /// Returns the version string and language string in the format that the installer
80 /// expects to find them in the database. If you just want version information, set 86 /// expects to find them in the database. If you just want version information, set
81 /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set 87 /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set
82 /// lpVersionBuf and pcchVersionBuf to zero. 88 /// lpVersionBuf and pcchVersionBuf to zero.
83 /// </summary> 89 /// </summary>
84 /// <param name="filePath">Specifies the path to the file.</param> 90 /// <param name="filePath">Specifies the path to the file.</param>
@@ -91,6 +97,8 @@ namespace WixToolset.Core.Native.Msi
91 var versionBuffer = new StringBuilder(versionLength); 97 var versionBuffer = new StringBuilder(versionLength);
92 var languageBuffer = new StringBuilder(languageLength); 98 var languageBuffer = new StringBuilder(languageLength);
93 99
100 filePath = PathUtil.GetPrefixedLongPath(filePath);
101
94 var error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength); 102 var error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength);
95 if (234 == error) 103 if (234 == error)
96 { 104 {
diff --git a/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs b/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs
index 18a78f77..6d0226d2 100644
--- a/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs
+++ b/src/wix/WixToolset.Core.Native/Msi/OpenDatabase.cs
@@ -1,4 +1,4 @@
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.Core.Native.Msi 3namespace WixToolset.Core.Native.Msi
4{ 4{
diff --git a/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs b/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs
index 3b3dea0f..3eed1274 100644
--- a/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs
+++ b/src/wix/WixToolset.Core.Native/Msi/SummaryInformation.cs
@@ -220,8 +220,10 @@ namespace WixToolset.Core.Native.Msi
220 throw new ArgumentNullException(nameof(databaseFile)); 220 throw new ArgumentNullException(nameof(databaseFile));
221 } 221 }
222 222
223 var shortDatabaseFile = PathUtil.GetShortPath(databaseFile);
224
223 var handle = IntPtr.Zero; 225 var handle = IntPtr.Zero;
224 var error = MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, databaseFile, 0, ref handle); 226 var error = MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, shortDatabaseFile, 0, ref handle);
225 if (0 != error) 227 if (0 != error)
226 { 228 {
227 throw new MsiException(error); 229 throw new MsiException(error);
diff --git a/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs b/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs
index 7978304a..434b0887 100644
--- a/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs
+++ b/src/wix/WixToolset.Core.Native/WindowsInstallerValidator.cs
@@ -93,7 +93,7 @@ namespace WixToolset.Core.Native
93 93
94 try 94 try
95 { 95 {
96 using (var database = new Database(this.DatabasePath, OpenDatabase.Direct)) 96 using (var database = Database.Open(this.DatabasePath))
97 { 97 {
98 var propertyTableExists = database.TableExists("Property"); 98 var propertyTableExists = database.TableExists("Property");
99 string productCode = null; 99 string productCode = null;
@@ -130,7 +130,7 @@ namespace WixToolset.Core.Native
130 130
131 try 131 try
132 { 132 {
133 using (var cubeDatabase = new Database(findCubeFile.Path, OpenDatabase.ReadOnly)) 133 using (var cubeDatabase = Database.OpenAsReadOnly(findCubeFile.Path))
134 { 134 {
135 try 135 try
136 { 136 {
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
index e96df21f..f327081a 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs
@@ -418,8 +418,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
418 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); 418 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
419 419
420 // create the transform file 420 // create the transform file
421 using (var targetDatabase = new Database(targetDatabaseFile, OpenDatabase.ReadOnly)) 421 using (var targetDatabase = Database.OpenAsReadOnly(targetDatabaseFile))
422 using (var updatedDatabase = new Database(updatedDatabaseFile, OpenDatabase.ReadOnly)) 422 using (var updatedDatabase = Database.OpenAsReadOnly(updatedDatabaseFile))
423 { 423 {
424 if (updatedDatabase.GenerateTransform(targetDatabase, this.OutputPath)) 424 if (updatedDatabase.GenerateTransform(targetDatabase, this.OutputPath))
425 { 425 {
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
index 94ed0afc..117923e5 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs
@@ -90,7 +90,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
90 try 90 try
91 { 91 {
92 // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module. 92 // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module.
93 using (var db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly)) 93 using (var db = Database.OpenAsReadOnly(wixMergeRow.SourceFile))
94 { 94 {
95 if (db.TableExists("File") && db.TableExists("Component")) 95 if (db.TableExists("File") && db.TableExists("Component"))
96 { 96 {
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
index 3d831577..7414cb54 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
@@ -81,20 +81,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
81 81
82 var idtFolder = Path.Combine(baseDirectory, IdtsSubFolder); 82 var idtFolder = Path.Combine(baseDirectory, IdtsSubFolder);
83 83
84 var type = OpenDatabase.CreateDirect;
85
86 if (OutputType.Patch == this.Data.Type)
87 {
88 type |= OpenDatabase.OpenPatchFile;
89 }
90
91 try 84 try
92 { 85 {
93 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath)); 86 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
94 87
95 Directory.CreateDirectory(idtFolder); 88 Directory.CreateDirectory(idtFolder);
96 89
97 using (var db = new Database(this.OutputPath, type)) 90 using (var db = Database.Create(this.OutputPath, asPatch: OutputType.Patch == this.Data.Type))
98 { 91 {
99 // If we're not using the default codepage, import a new one into our 92 // If we're not using the default codepage, import a new one into our
100 // database before we add any tables (or the tables would be added 93 // database before we add any tables (or the tables would be added
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
index 5f21f496..71a2e367 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
@@ -223,7 +223,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
223 return; 223 return;
224 } 224 }
225 225
226 using (var db = new Database(this.OutputPath, OpenDatabase.Direct)) 226 using (var db = Database.Open(this.OutputPath))
227 { 227 {
228 // Suppress individual actions. 228 // Suppress individual actions.
229 foreach (var suppressAction in this.Section.Symbols.OfType<WixSuppressActionSymbol>()) 229 foreach (var suppressAction in this.Section.Symbols.OfType<WixSuppressActionSymbol>())
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
index c5f198f8..ff7c6579 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
@@ -64,7 +64,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
64 64
65 var mediaRows = this.Section.Symbols.OfType<MediaSymbol>().ToDictionary(t => t.DiskId); 65 var mediaRows = this.Section.Symbols.OfType<MediaSymbol>().ToDictionary(t => t.DiskId);
66 66
67 using (var db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) 67 using (var db = Database.OpenAsReadOnly(this.DatabasePath))
68 { 68 {
69 using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) 69 using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
70 { 70 {
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
index 52d2146c..75e536c2 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
@@ -76,7 +76,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
76 var assemblySymbols = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id); 76 var assemblySymbols = this.Section.Symbols.OfType<AssemblySymbol>().ToDictionary(t => t.Id.Id);
77 77
78 Parallel.ForEach(facades, 78 Parallel.ForEach(facades,
79 new ParallelOptions{ 79 new ParallelOptions
80 {
80 CancellationToken = this.CancellationToken, 81 CancellationToken = this.CancellationToken,
81 MaxDegreeOfParallelism = this.ThreadCount 82 MaxDegreeOfParallelism = this.ThreadCount
82 }, 83 },
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
index 455057f6..344cccb8 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
@@ -61,7 +61,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
61 return shouldCommit; 61 return shouldCommit;
62 } 62 }
63 63
64 using (var database = new Database(databasePath, OpenDatabase.Transact)) 64 using (var database = Database.Open(databasePath, transact: true))
65 { 65 {
66 // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content 66 // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
67 var codepage = 1252; 67 var codepage = 1252;
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
index ef02f5d1..ac6a6ab3 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs
@@ -86,7 +86,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
86 { 86 {
87 if (this.Database == null) 87 if (this.Database == null)
88 { 88 {
89 database = new Database(this.DatabasePath, OpenDatabase.ReadOnly); 89 database = Database.OpenAsReadOnly(this.DatabasePath);
90 this.Database = database; 90 this.Database = database;
91 } 91 }
92 92
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs
index aad3d34d..5df38db3 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Unbind/UnbindTransformCommand.cs
@@ -273,7 +273,7 @@ namespace WixToolset.Core.WindowsInstaller.Unbind
273 273
274 private Database ApplyTransformToSchemaDatabase(string schemaDatabasePath, TransformErrorConditions transformConditions) 274 private Database ApplyTransformToSchemaDatabase(string schemaDatabasePath, TransformErrorConditions transformConditions)
275 { 275 {
276 var msiDatabase = new Database(schemaDatabasePath, OpenDatabase.Transact); 276 var msiDatabase = Database.Open(schemaDatabasePath, transact: true);
277 277
278 try 278 try
279 { 279 {
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs
new file mode 100644
index 00000000..2cada64d
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/LongPathFixture.cs
@@ -0,0 +1,89 @@
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 WixToolsetTest.CoreIntegration
4{
5 using System.IO;
6 using System.Linq;
7 using WixInternal.Core.TestPackage;
8 using WixInternal.TestSupport;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using Xunit;
12
13 public class LongPathFixture
14 {
15 [Fact]
16 public void TestLongPathSupport()
17 {
18 var testDataFolder = TestData.Get(@"TestData", "SingleFile");
19
20 using (var fs = new DisposableFileSystem())
21 {
22 var folder = fs.GetFolder();
23
24 while (folder.Length < 500)
25 {
26 folder = Path.Combine(folder, new string('z', 100));
27 }
28
29 CopyDirectory(testDataFolder, folder);
30
31 var baseFolder = fs.GetFolder();
32
33 while (baseFolder.Length < 500)
34 {
35 baseFolder = Path.Combine(baseFolder, new string('a', 100));
36 }
37
38 var intermediateFolder = Path.Combine(baseFolder, "obj");
39
40 var result = WixRunner.Execute(
41 [
42 "build",
43 Path.Combine(folder, "Package.wxs"),
44 Path.Combine(folder, "PackageComponents.wxs"),
45 "-loc", Path.Combine(folder, "Package.en-us.wxl"),
46 "-bindpath", Path.Combine(folder, "data"),
47 "-intermediateFolder", intermediateFolder,
48 "-o", Path.Combine(baseFolder, "bin", "test.msi")
49 ]);
50
51 result.AssertSuccess();
52
53 Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.msi")));
54 Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "test.wixpdb")));
55 Assert.True(File.Exists(Path.Combine(baseFolder, "bin", "PFiles", "Example Corporation MsiPackage", "test.txt")));
56
57 var intermediate = Intermediate.Load(Path.Combine(baseFolder, "bin", "test.wixpdb"));
58
59 var section = intermediate.Sections.Single();
60
61 var fileSymbol = section.Symbols.OfType<FileSymbol>().First();
62 WixAssert.StringEqual(Path.Combine(folder, @"data\test.txt"), fileSymbol[FileSymbolFields.Source].AsPath().Path);
63 WixAssert.StringEqual(@"test.txt", fileSymbol[FileSymbolFields.Source].PreviousValue.AsPath().Path);
64 }
65 }
66
67 private static void CopyDirectory(string sourceFolder, string targetFolder)
68 {
69 // Ensure the target directory exists
70 Directory.CreateDirectory(targetFolder);
71
72 // Copy all files
73 foreach (var file in Directory.GetFiles(sourceFolder))
74 {
75 var targetFile = Path.Combine(targetFolder, Path.GetFileName(file));
76
77 File.Copy(file, targetFile);
78 }
79
80 // Recursively copy subdirectories
81 foreach (var subFolder in Directory.GetDirectories(sourceFolder))
82 {
83 var targetSubFolder = Path.Combine(targetFolder, Path.GetFileName(subFolder));
84
85 CopyDirectory(subFolder, targetSubFolder);
86 }
87 }
88 }
89}
diff --git a/src/wix/wixnative/wixnative.manifest b/src/wix/wixnative/wixnative.manifest
new file mode 100644
index 00000000..ce288e89
--- /dev/null
+++ b/src/wix/wixnative/wixnative.manifest
@@ -0,0 +1,9 @@
1<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 <assemblyIdentity name="WixToolset.Tools.WixNative" version="4.0.0.0" processorArchitecture="x86" type="win32"/>
4 <description>WiX Toolset Native</description>
5 <application xmlns="urn:schemas-microsoft-com:asm.v3"><windowsSettings>
6 <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
7 </windowsSettings></application>
8 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false"/></requestedPrivileges></security></trustInfo>
9</assembly>
diff --git a/src/wix/wixnative/wixnative.vcxproj b/src/wix/wixnative/wixnative.vcxproj
index e4474bb1..c4e05a62 100644
--- a/src/wix/wixnative/wixnative.vcxproj
+++ b/src/wix/wixnative/wixnative.vcxproj
@@ -55,6 +55,9 @@
55 <ClCompile Include="extractcab.cpp" /> 55 <ClCompile Include="extractcab.cpp" />
56 <ClCompile Include="smartcab.cpp" /> 56 <ClCompile Include="smartcab.cpp" />
57 </ItemGroup> 57 </ItemGroup>
58 <ItemGroup>
59 <Manifest Include="wixnative.manifest" />
60 </ItemGroup>
58 61
59 <ItemGroup> 62 <ItemGroup>
60 <ClInclude Include="precomp.h" /> 63 <ClInclude Include="precomp.h" />