diff options
| author | Rob Mensching <rob@firegiant.com> | 2020-01-13 09:10:13 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2020-01-13 14:19:45 -0800 |
| commit | 94b941ee95a294228516097c269e27dfa41593ab (patch) | |
| tree | 208cb36a5a6a3e17f5d458cfaa679d6ca1a76e15 /src | |
| parent | a2b1235d9c0dfba48b1badac428d89d1137da698 (diff) | |
| download | wix-94b941ee95a294228516097c269e27dfa41593ab.tar.gz wix-94b941ee95a294228516097c269e27dfa41593ab.tar.bz2 wix-94b941ee95a294228516097c269e27dfa41593ab.zip | |
Provide Record enumerator on View that disposes fetched Records
Diffstat (limited to 'src')
9 files changed, 389 insertions, 390 deletions
diff --git a/src/WixToolset.Core.TestPackage/WixRunnerResult.cs b/src/WixToolset.Core.TestPackage/WixRunnerResult.cs index f4870ae3..88f20158 100644 --- a/src/WixToolset.Core.TestPackage/WixRunnerResult.cs +++ b/src/WixToolset.Core.TestPackage/WixRunnerResult.cs | |||
| @@ -26,7 +26,6 @@ namespace WixToolset.Core.TestPackage | |||
| 26 | var filename = message.SourceLineNumbers?.FileName ?? "TEST"; | 26 | var filename = message.SourceLineNumbers?.FileName ?? "TEST"; |
| 27 | var line = message.SourceLineNumbers?.LineNumber ?? -1; | 27 | var line = message.SourceLineNumbers?.LineNumber ?? -1; |
| 28 | var type = message.Level.ToString().ToLowerInvariant(); | 28 | var type = message.Level.ToString().ToLowerInvariant(); |
| 29 | var output = message.Level >= MessageLevel.Warning ? Console.Out : Console.Error; | ||
| 30 | 29 | ||
| 31 | if (line > 0) | 30 | if (line > 0) |
| 32 | { | 31 | { |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index 4105cb8f..5412c6f9 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs | |||
| @@ -89,46 +89,38 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 89 | using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) | 89 | using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`")) |
| 90 | { | 90 | { |
| 91 | // add each file row from the merge module into the file row collection (check for errors along the way) | 91 | // add each file row from the merge module into the file row collection (check for errors along the way) |
| 92 | while (true) | 92 | foreach (Record record in view.Records) |
| 93 | { | 93 | { |
| 94 | using (Record record = view.Fetch()) | 94 | // NOTE: this is very tricky - the merge module file rows are not added to the |
| 95 | // file table because they should not be created via idt import. Instead, these | ||
| 96 | // rows are created by merging in the actual modules. | ||
| 97 | var fileTuple = new FileTuple(wixMergeRow.SourceLineNumbers, new Identifier(AccessModifier.Private, record[1])); | ||
| 98 | fileTuple.Attributes = wixMergeRow.FileAttributes; | ||
| 99 | fileTuple.DirectoryRef = record[2]; | ||
| 100 | fileTuple.DiskId = wixMergeRow.DiskId; | ||
| 101 | fileTuple.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; | ||
| 102 | |||
| 103 | var mergeModuleFileFacade = new FileFacade(true, fileTuple); | ||
| 104 | |||
| 105 | // If case-sensitive collision with another merge module or a user-authored file identifier. | ||
| 106 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.Id.Id, out var collidingFacade)) | ||
| 95 | { | 107 | { |
| 96 | if (null == record) | 108 | this.Messaging.Write(ErrorMessages.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, collidingFacade.File.Id.Id)); |
| 97 | { | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | // NOTE: this is very tricky - the merge module file rows are not added to the | ||
| 102 | // file table because they should not be created via idt import. Instead, these | ||
| 103 | // rows are created by merging in the actual modules. | ||
| 104 | var fileTuple = new FileTuple(wixMergeRow.SourceLineNumbers, new Identifier(AccessModifier.Private, record[1])); | ||
| 105 | fileTuple.Attributes = wixMergeRow.FileAttributes; | ||
| 106 | fileTuple.DirectoryRef = record[2]; | ||
| 107 | fileTuple.DiskId = wixMergeRow.DiskId; | ||
| 108 | fileTuple.Source = new IntermediateFieldPathValue { Path = Path.Combine(this.IntermediateFolder, wixMergeRow.Id.Id, record[1]) }; | ||
| 109 | |||
| 110 | var mergeModuleFileFacade = new FileFacade(true, fileTuple); | ||
| 111 | |||
| 112 | // If case-sensitive collision with another merge module or a user-authored file identifier. | ||
| 113 | if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.Id.Id, out var collidingFacade)) | ||
| 114 | { | ||
| 115 | this.Messaging.Write(ErrorMessages.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, collidingFacade.File.Id.Id)); | ||
| 116 | } | ||
| 117 | else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.Id.Id, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module | ||
| 118 | { | ||
| 119 | this.Messaging.Write(ErrorMessages.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, mergeModuleFileFacade.File.Id.Id, collidingFacade.File.Id.Id)); | ||
| 120 | } | ||
| 121 | else // no collision | ||
| 122 | { | ||
| 123 | mergeModulesFileFacades.Add(mergeModuleFileFacade); | ||
| 124 | |||
| 125 | // Keep updating the indexes as new rows are added. | ||
| 126 | indexedFileFacades.Add(mergeModuleFileFacade.File.Id.Id, mergeModuleFileFacade); | ||
| 127 | uniqueModuleFileIdentifiers.Add(mergeModuleFileFacade.File.Id.Id, mergeModuleFileFacade); | ||
| 128 | } | ||
| 129 | |||
| 130 | containsFiles = true; | ||
| 131 | } | 109 | } |
| 110 | else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.Id.Id, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module | ||
| 111 | { | ||
| 112 | this.Messaging.Write(ErrorMessages.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, mergeModuleFileFacade.File.Id.Id, collidingFacade.File.Id.Id)); | ||
| 113 | } | ||
| 114 | else // no collision | ||
| 115 | { | ||
| 116 | mergeModulesFileFacades.Add(mergeModuleFileFacade); | ||
| 117 | |||
| 118 | // Keep updating the indexes as new rows are added. | ||
| 119 | indexedFileFacades.Add(mergeModuleFileFacade.File.Id.Id, mergeModuleFileFacade); | ||
| 120 | uniqueModuleFileIdentifiers.Add(mergeModuleFileFacade.File.Id.Id, mergeModuleFileFacade); | ||
| 121 | } | ||
| 122 | |||
| 123 | containsFiles = true; | ||
| 132 | } | 124 | } |
| 133 | } | 125 | } |
| 134 | } | 126 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index 7ee33997..8c11555e 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
| @@ -220,14 +220,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 220 | string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]); | 220 | string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]); |
| 221 | 221 | ||
| 222 | using (View view = db.OpenExecuteView(query)) | 222 | using (View view = db.OpenExecuteView(query)) |
| 223 | using (Record record = view.Fetch()) | ||
| 223 | { | 224 | { |
| 224 | using (Record record = view.Fetch()) | 225 | if (null != record) |
| 225 | { | 226 | { |
| 226 | if (null != record) | 227 | this.Messaging.Write(WarningMessages.SuppressMergedAction((string)row[1], row[0].ToString())); |
| 227 | { | 228 | view.Modify(ModifyView.Delete, record); |
| 228 | this.Messaging.Write(WarningMessages.SuppressMergedAction((string)row[1], row[0].ToString())); | ||
| 229 | view.Modify(ModifyView.Delete, record); | ||
| 230 | } | ||
| 231 | } | 229 | } |
| 232 | } | 230 | } |
| 233 | } | 231 | } |
| @@ -244,17 +242,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 244 | 242 | ||
| 245 | using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) | 243 | using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) |
| 246 | { | 244 | { |
| 247 | while (true) | 245 | foreach (Record resultRecord in view.Records) |
| 248 | { | 246 | { |
| 249 | using (Record resultRecord = view.Fetch()) | 247 | this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName)); |
| 250 | { | ||
| 251 | if (null == resultRecord) | ||
| 252 | { | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | |||
| 256 | this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName)); | ||
| 257 | } | ||
| 258 | } | 248 | } |
| 259 | } | 249 | } |
| 260 | 250 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs index 64fb3e4d..373ada38 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs | |||
| @@ -57,25 +57,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 57 | 57 | ||
| 58 | var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId); | 58 | var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId); |
| 59 | 59 | ||
| 60 | using (Database db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) | 60 | using (var db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) |
| 61 | { | 61 | { |
| 62 | using (View directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) | 62 | using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) |
| 63 | { | 63 | { |
| 64 | while (true) | 64 | foreach (var directoryRecord in directoryView.Records) |
| 65 | { | 65 | { |
| 66 | using (Record directoryRecord = directoryView.Fetch()) | 66 | var sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); |
| 67 | { | ||
| 68 | if (null == directoryRecord) | ||
| 69 | { | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | 67 | ||
| 73 | string sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage); | 68 | var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName); |
| 74 | 69 | ||
| 75 | var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName); | 70 | directories.Add(directoryRecord.GetString(1), resolvedDirectory); |
| 76 | |||
| 77 | directories.Add(directoryRecord.GetString(1), resolvedDirectory); | ||
| 78 | } | ||
| 79 | } | 71 | } |
| 80 | } | 72 | } |
| 81 | 73 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs index b91eeeef..ff7472ff 100644 --- a/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs | |||
| @@ -60,47 +60,39 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe | |||
| 60 | { | 60 | { |
| 61 | using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'")) | 61 | using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'")) |
| 62 | { | 62 | { |
| 63 | while (true) | 63 | foreach (Record digitalSignatureRecord in digitalSignatureView.Records) |
| 64 | { | 64 | { |
| 65 | using (Record digitalSignatureRecord = digitalSignatureView.Fetch()) | 65 | Row digitalSignatureRow = null; |
| 66 | { | 66 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); |
| 67 | if (null == digitalSignatureRecord) | ||
| 68 | { | ||
| 69 | break; | ||
| 70 | } | ||
| 71 | 67 | ||
| 72 | Row digitalSignatureRow = null; | 68 | string table = digitalSignatureRecord.GetString(0); |
| 73 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | 69 | string signObject = digitalSignatureRecord.GetString(1); |
| 74 | 70 | ||
| 75 | string table = digitalSignatureRecord.GetString(0); | 71 | digitalSignatureRow[0] = table; |
| 76 | string signObject = digitalSignatureRecord.GetString(1); | 72 | digitalSignatureRow[1] = signObject; |
| 73 | digitalSignatureRow[2] = digitalSignatureRecord.GetString(2); | ||
| 77 | 74 | ||
| 78 | digitalSignatureRow[0] = table; | 75 | if (false == digitalSignatureRecord.IsNull(3)) |
| 79 | digitalSignatureRow[1] = signObject; | 76 | { |
| 80 | digitalSignatureRow[2] = digitalSignatureRecord.GetString(2); | 77 | // Export to a file, because the MSI API's require us to provide a file path on disk |
| 78 | string hashPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalSignature"); | ||
| 79 | string hashFileName = string.Concat(table, ".", signObject, ".bin"); | ||
| 81 | 80 | ||
| 82 | if (false == digitalSignatureRecord.IsNull(3)) | 81 | Directory.CreateDirectory(hashPath); |
| 83 | { | 82 | hashPath = Path.Combine(hashPath, hashFileName); |
| 84 | // Export to a file, because the MSI API's require us to provide a file path on disk | ||
| 85 | string hashPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalSignature"); | ||
| 86 | string hashFileName = string.Concat(table, ".", signObject, ".bin"); | ||
| 87 | 83 | ||
| 88 | Directory.CreateDirectory(hashPath); | 84 | using (FileStream fs = File.Create(hashPath)) |
| 89 | hashPath = Path.Combine(hashPath, hashFileName); | 85 | { |
| 86 | int bytesRead; | ||
| 87 | byte[] buffer = new byte[1024 * 4]; | ||
| 90 | 88 | ||
| 91 | using (FileStream fs = File.Create(hashPath)) | 89 | while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length))) |
| 92 | { | 90 | { |
| 93 | int bytesRead; | 91 | fs.Write(buffer, 0, bytesRead); |
| 94 | byte[] buffer = new byte[1024 * 4]; | ||
| 95 | |||
| 96 | while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length))) | ||
| 97 | { | ||
| 98 | fs.Write(buffer, 0, bytesRead); | ||
| 99 | } | ||
| 100 | } | 92 | } |
| 101 | |||
| 102 | digitalSignatureRow[3] = hashFileName; | ||
| 103 | } | 93 | } |
| 94 | |||
| 95 | digitalSignatureRow[3] = hashFileName; | ||
| 104 | } | 96 | } |
| 105 | } | 97 | } |
| 106 | } | 98 | } |
| @@ -111,145 +103,129 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe | |||
| 111 | { | 103 | { |
| 112 | using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`")) | 104 | using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`")) |
| 113 | { | 105 | { |
| 114 | while (true) | 106 | foreach (Record digitalCertificateRecord in digitalCertificateView.Records) |
| 115 | { | 107 | { |
| 116 | using (Record digitalCertificateRecord = digitalCertificateView.Fetch()) | 108 | string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate |
| 117 | { | ||
| 118 | if (null == digitalCertificateRecord) | ||
| 119 | { | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | 109 | ||
| 123 | string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate | 110 | // Export to a file, because the MSI API's require us to provide a file path on disk |
| 111 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); | ||
| 112 | Directory.CreateDirectory(certPath); | ||
| 113 | certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer")); | ||
| 124 | 114 | ||
| 125 | // Export to a file, because the MSI API's require us to provide a file path on disk | 115 | using (FileStream fs = File.Create(certPath)) |
| 126 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); | 116 | { |
| 127 | Directory.CreateDirectory(certPath); | 117 | int bytesRead; |
| 128 | certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer")); | 118 | byte[] buffer = new byte[1024 * 4]; |
| 129 | 119 | ||
| 130 | using (FileStream fs = File.Create(certPath)) | 120 | while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length))) |
| 131 | { | 121 | { |
| 132 | int bytesRead; | 122 | fs.Write(buffer, 0, bytesRead); |
| 133 | byte[] buffer = new byte[1024 * 4]; | ||
| 134 | |||
| 135 | while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length))) | ||
| 136 | { | ||
| 137 | fs.Write(buffer, 0, bytesRead); | ||
| 138 | } | ||
| 139 | } | 123 | } |
| 124 | } | ||
| 140 | 125 | ||
| 141 | // Add it to our "add to MsiDigitalCertificate" table dictionary | 126 | // Add it to our "add to MsiDigitalCertificate" table dictionary |
| 142 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | 127 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); |
| 143 | digitalCertificateRow[0] = certificateId; | 128 | digitalCertificateRow[0] = certificateId; |
| 144 | 129 | ||
| 145 | // Now set the file path on disk where this binary stream will be picked up at import time | 130 | // Now set the file path on disk where this binary stream will be picked up at import time |
| 146 | digitalCertificateRow[1] = string.Concat(certificateId, ".cer"); | 131 | digitalCertificateRow[1] = string.Concat(certificateId, ".cer"); |
| 147 | 132 | ||
| 148 | // Load the cert to get it's thumbprint | 133 | // Load the cert to get it's thumbprint |
| 149 | X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); | 134 | X509Certificate cert = X509Certificate.CreateFromCertFile(certPath); |
| 150 | X509Certificate2 cert2 = new X509Certificate2(cert); | 135 | X509Certificate2 cert2 = new X509Certificate2(cert); |
| 151 | 136 | ||
| 152 | certificates.Add(cert2.Thumbprint, certificateId); | 137 | certificates.Add(cert2.Thumbprint, certificateId); |
| 153 | } | ||
| 154 | } | 138 | } |
| 155 | } | 139 | } |
| 156 | } | 140 | } |
| 157 | 141 | ||
| 158 | using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`")) | 142 | using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`")) |
| 159 | { | 143 | { |
| 160 | while (true) | 144 | foreach (Record mediaRecord in mediaView.Records) |
| 161 | { | 145 | { |
| 162 | using (Record mediaRecord = mediaView.Fetch()) | 146 | X509Certificate2 cert2 = null; |
| 147 | Row digitalSignatureRow = null; | ||
| 148 | |||
| 149 | string cabName = mediaRecord.GetString(4); // get the name of the cab | ||
| 150 | // If there is no cabinet or it's an internal cab, skip it. | ||
| 151 | if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal)) | ||
| 163 | { | 152 | { |
| 164 | if (null == mediaRecord) | 153 | continue; |
| 165 | { | 154 | } |
| 166 | break; | ||
| 167 | } | ||
| 168 | 155 | ||
| 169 | X509Certificate2 cert2 = null; | 156 | string cabId = mediaRecord.GetString(1); // get the ID of the cab |
| 170 | Row digitalSignatureRow = null; | 157 | string cabPath = Path.Combine(Path.GetDirectoryName(this.Context.InputFilePath), cabName); |
| 171 | 158 | ||
| 172 | string cabName = mediaRecord.GetString(4); // get the name of the cab | 159 | // If the cabs aren't there, throw an error but continue to catch the other errors |
| 173 | // If there is no cabinet or it's an internal cab, skip it. | 160 | if (!File.Exists(cabPath)) |
| 174 | if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal)) | 161 | { |
| 175 | { | 162 | this.Messaging.Write(ErrorMessages.WixFileNotFound(cabPath)); |
| 176 | continue; | 163 | continue; |
| 177 | } | 164 | } |
| 178 | 165 | ||
| 179 | string cabId = mediaRecord.GetString(1); // get the ID of the cab | 166 | try |
| 180 | string cabPath = Path.Combine(Path.GetDirectoryName(this.Context.InputFilePath), cabName); | 167 | { |
| 168 | // Get the certificate from the cab | ||
| 169 | X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath); | ||
| 170 | cert2 = new X509Certificate2(signedFileCert); | ||
| 171 | } | ||
| 172 | catch (System.Security.Cryptography.CryptographicException e) | ||
| 173 | { | ||
| 174 | uint HResult = unchecked((uint)Marshal.GetHRForException(e)); | ||
| 181 | 175 | ||
| 182 | // If the cabs aren't there, throw an error but continue to catch the other errors | 176 | // If the file has no cert, continue, but flag that we found at least one so we can later give a warning |
| 183 | if (!File.Exists(cabPath)) | 177 | if (0x80092009 == HResult) // CRYPT_E_NO_MATCH |
| 184 | { | 178 | { |
| 185 | this.Messaging.Write(ErrorMessages.WixFileNotFound(cabPath)); | 179 | foundUnsignedExternals = true; |
| 186 | continue; | 180 | continue; |
| 187 | } | 181 | } |
| 188 | 182 | ||
| 189 | try | 183 | // todo: exactly which HRESULT corresponds to this issue? |
| 184 | // If it's one of these exact platforms, warn the user that it may be due to their OS. | ||
| 185 | if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3 | ||
| 186 | (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP | ||
| 190 | { | 187 | { |
| 191 | // Get the certificate from the cab | 188 | this.Messaging.Write(ErrorMessages.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); |
| 192 | X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath); | ||
| 193 | cert2 = new X509Certificate2(signedFileCert); | ||
| 194 | } | 189 | } |
| 195 | catch (System.Security.Cryptography.CryptographicException e) | 190 | else // otherwise, generic error |
| 196 | { | 191 | { |
| 197 | uint HResult = unchecked((uint)Marshal.GetHRForException(e)); | 192 | this.Messaging.Write(ErrorMessages.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); |
| 198 | |||
| 199 | // If the file has no cert, continue, but flag that we found at least one so we can later give a warning | ||
| 200 | if (0x80092009 == HResult) // CRYPT_E_NO_MATCH | ||
| 201 | { | ||
| 202 | foundUnsignedExternals = true; | ||
| 203 | continue; | ||
| 204 | } | ||
| 205 | |||
| 206 | // todo: exactly which HRESULT corresponds to this issue? | ||
| 207 | // If it's one of these exact platforms, warn the user that it may be due to their OS. | ||
| 208 | if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3 | ||
| 209 | (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP | ||
| 210 | { | ||
| 211 | this.Messaging.Write(ErrorMessages.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | ||
| 212 | } | ||
| 213 | else // otherwise, generic error | ||
| 214 | { | ||
| 215 | this.Messaging.Write(ErrorMessages.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult))); | ||
| 216 | } | ||
| 217 | } | 193 | } |
| 194 | } | ||
| 218 | 195 | ||
| 219 | // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added | 196 | // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added |
| 220 | if (!certificates.ContainsKey(cert2.Thumbprint)) | 197 | if (!certificates.ContainsKey(cert2.Thumbprint)) |
| 221 | { | 198 | { |
| 222 | // generate a stable identifier | 199 | // generate a stable identifier |
| 223 | string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); | 200 | string certificateGeneratedId = Common.GenerateIdentifier("cer", cert2.Thumbprint); |
| 224 | |||
| 225 | // Add it to our "add to MsiDigitalCertificate" table dictionary | ||
| 226 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); | ||
| 227 | digitalCertificateRow[0] = certificateGeneratedId; | ||
| 228 | |||
| 229 | // Export to a file, because the MSI API's require us to provide a file path on disk | ||
| 230 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); | ||
| 231 | Directory.CreateDirectory(certPath); | ||
| 232 | certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer")); | ||
| 233 | File.Delete(certPath); | ||
| 234 | 201 | ||
| 235 | using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create))) | 202 | // Add it to our "add to MsiDigitalCertificate" table dictionary |
| 236 | { | 203 | Row digitalCertificateRow = digitalCertificateTable.CreateRow(null); |
| 237 | writer.Write(cert2.RawData); | 204 | digitalCertificateRow[0] = certificateGeneratedId; |
| 238 | writer.Close(); | ||
| 239 | } | ||
| 240 | 205 | ||
| 241 | // Now set the file path on disk where this binary stream will be picked up at import time | 206 | // Export to a file, because the MSI API's require us to provide a file path on disk |
| 242 | digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer"); | 207 | string certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate"); |
| 208 | Directory.CreateDirectory(certPath); | ||
| 209 | certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer")); | ||
| 210 | File.Delete(certPath); | ||
| 243 | 211 | ||
| 244 | certificates.Add(cert2.Thumbprint, certificateGeneratedId); | 212 | using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create))) |
| 213 | { | ||
| 214 | writer.Write(cert2.RawData); | ||
| 215 | writer.Close(); | ||
| 245 | } | 216 | } |
| 246 | 217 | ||
| 247 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | 218 | // Now set the file path on disk where this binary stream will be picked up at import time |
| 219 | digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer"); | ||
| 248 | 220 | ||
| 249 | digitalSignatureRow[0] = "Media"; | 221 | certificates.Add(cert2.Thumbprint, certificateGeneratedId); |
| 250 | digitalSignatureRow[1] = cabId; | ||
| 251 | digitalSignatureRow[2] = certificates[cert2.Thumbprint]; | ||
| 252 | } | 222 | } |
| 223 | |||
| 224 | digitalSignatureRow = digitalSignatureTable.CreateRow(null); | ||
| 225 | |||
| 226 | digitalSignatureRow[0] = "Media"; | ||
| 227 | digitalSignatureRow[1] = cabId; | ||
| 228 | digitalSignatureRow[2] = certificates[cert2.Thumbprint]; | ||
| 253 | } | 229 | } |
| 254 | } | 230 | } |
| 255 | 231 | ||
| @@ -275,7 +251,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe | |||
| 275 | 251 | ||
| 276 | certificates = null; | 252 | certificates = null; |
| 277 | 253 | ||
| 278 | // If we did find external cabs but none of them were signed, give a warning | 254 | // If we did find external cabs but not all of them were signed, give a warning |
| 279 | if (foundUnsignedExternals) | 255 | if (foundUnsignedExternals) |
| 280 | { | 256 | { |
| 281 | this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.Context.InputFilePath)); | 257 | this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.Context.InputFilePath)); |
diff --git a/src/WixToolset.Core.WindowsInstaller/Msi/View.cs b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs index 1beb72da..0fb7fc62 100644 --- a/src/WixToolset.Core.WindowsInstaller/Msi/View.cs +++ b/src/WixToolset.Core.WindowsInstaller/Msi/View.cs | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | namespace WixToolset.Core.WindowsInstaller.Msi | 3 | namespace WixToolset.Core.WindowsInstaller.Msi |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections; | ||
| 7 | using System.Collections.Generic; | ||
| 6 | using System.Globalization; | 8 | using System.Globalization; |
| 7 | 9 | ||
| 8 | /// <summary> | 10 | /// <summary> |
| @@ -110,6 +112,11 @@ namespace WixToolset.Core.WindowsInstaller.Msi | |||
| 110 | } | 112 | } |
| 111 | 113 | ||
| 112 | /// <summary> | 114 | /// <summary> |
| 115 | /// Enumerator that automatically disposes of the retrieved Records. | ||
| 116 | /// </summary> | ||
| 117 | public IEnumerable<Record> Records => new ViewEnumerable(this); | ||
| 118 | |||
| 119 | /// <summary> | ||
| 113 | /// Executes a view with no customizable parameters. | 120 | /// Executes a view with no customizable parameters. |
| 114 | /// </summary> | 121 | /// </summary> |
| 115 | public void Execute() | 122 | public void Execute() |
| @@ -124,7 +131,7 @@ namespace WixToolset.Core.WindowsInstaller.Msi | |||
| 124 | /// <param name="record">Record containing parameters to be substituded into the view.</param> | 131 | /// <param name="record">Record containing parameters to be substituded into the view.</param> |
| 125 | public void Execute(Record record) | 132 | public void Execute(Record record) |
| 126 | { | 133 | { |
| 127 | int error = MsiInterop.MsiViewExecute(this.Handle, null == record ? 0 : record.Handle); | 134 | var error = MsiInterop.MsiViewExecute(this.Handle, null == record ? 0 : record.Handle); |
| 128 | if (0 != error) | 135 | if (0 != error) |
| 129 | { | 136 | { |
| 130 | throw new MsiException(error); | 137 | throw new MsiException(error); |
| @@ -137,9 +144,7 @@ namespace WixToolset.Core.WindowsInstaller.Msi | |||
| 137 | /// <returns>Returns the fetched record; otherwise null.</returns> | 144 | /// <returns>Returns the fetched record; otherwise null.</returns> |
| 138 | public Record Fetch() | 145 | public Record Fetch() |
| 139 | { | 146 | { |
| 140 | uint recordHandle; | 147 | var error = MsiInterop.MsiViewFetch(this.Handle, out var recordHandle); |
| 141 | |||
| 142 | int error = MsiInterop.MsiViewFetch(this.Handle, out recordHandle); | ||
| 143 | if (259 == error) | 148 | if (259 == error) |
| 144 | { | 149 | { |
| 145 | return null; | 150 | return null; |
| @@ -183,5 +188,75 @@ namespace WixToolset.Core.WindowsInstaller.Msi | |||
| 183 | 188 | ||
| 184 | return new Record(recordHandle); | 189 | return new Record(recordHandle); |
| 185 | } | 190 | } |
| 191 | |||
| 192 | private class ViewEnumerable : IEnumerable<Record> | ||
| 193 | { | ||
| 194 | private readonly View view; | ||
| 195 | |||
| 196 | public ViewEnumerable(View view) => this.view = view; | ||
| 197 | |||
| 198 | public IEnumerator<Record> GetEnumerator() => new ViewEnumerator(this.view); | ||
| 199 | |||
| 200 | IEnumerator IEnumerable.GetEnumerator() => new ViewEnumerator(this.view); | ||
| 201 | } | ||
| 202 | |||
| 203 | private class ViewEnumerator : IEnumerator<Record> | ||
| 204 | { | ||
| 205 | private readonly View view; | ||
| 206 | private readonly List<Record> records = new List<Record>(); | ||
| 207 | private int position = -1; | ||
| 208 | private bool disposed; | ||
| 209 | |||
| 210 | public ViewEnumerator(View view) => this.view = view; | ||
| 211 | |||
| 212 | public Record Current => this.records[this.position]; | ||
| 213 | |||
| 214 | object IEnumerator.Current => this.records[this.position]; | ||
| 215 | |||
| 216 | public bool MoveNext() | ||
| 217 | { | ||
| 218 | if (this.position + 1 >= this.records.Count) | ||
| 219 | { | ||
| 220 | var record = this.view.Fetch(); | ||
| 221 | |||
| 222 | if (record == null) | ||
| 223 | { | ||
| 224 | return false; | ||
| 225 | } | ||
| 226 | |||
| 227 | this.records.Add(record); | ||
| 228 | this.position = this.records.Count - 1; | ||
| 229 | } | ||
| 230 | else | ||
| 231 | { | ||
| 232 | ++this.position; | ||
| 233 | } | ||
| 234 | |||
| 235 | return true; | ||
| 236 | } | ||
| 237 | |||
| 238 | public void Reset() => this.position = -1; | ||
| 239 | |||
| 240 | public void Dispose() | ||
| 241 | { | ||
| 242 | this.Dispose(true); | ||
| 243 | } | ||
| 244 | |||
| 245 | protected virtual void Dispose(bool disposing) | ||
| 246 | { | ||
| 247 | if (!this.disposed) | ||
| 248 | { | ||
| 249 | if (disposing) | ||
| 250 | { | ||
| 251 | foreach (var record in this.records) | ||
| 252 | { | ||
| 253 | record.Dispose(); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | this.disposed = true; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | } | ||
| 186 | } | 261 | } |
| 187 | } | 262 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs index 557500e8..fb4b4ee3 100644 --- a/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Unbind/UnbindDatabaseCommand.cs | |||
| @@ -121,142 +121,125 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
| 121 | // get the normal tables | 121 | // get the normal tables |
| 122 | using (var tablesView = this.Database.OpenExecuteView("SELECT * FROM _Tables")) | 122 | using (var tablesView = this.Database.OpenExecuteView("SELECT * FROM _Tables")) |
| 123 | { | 123 | { |
| 124 | while (true) | 124 | foreach (var tableRecord in tablesView.Records) |
| 125 | { | 125 | { |
| 126 | using (var tableRecord = tablesView.Fetch()) | 126 | var tableName = tableRecord.GetString(1); |
| 127 | { | ||
| 128 | if (null == tableRecord) | ||
| 129 | { | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | 127 | ||
| 133 | var tableName = tableRecord.GetString(1); | 128 | using (var tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) |
| 129 | { | ||
| 130 | var tableDefinition = this.GetTableDefinition(tableName, tableView, validationView); | ||
| 131 | var table = new Table(tableDefinition); | ||
| 134 | 132 | ||
| 135 | using (var tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName))) | 133 | foreach (var rowRecord in tableView.Records) |
| 136 | { | 134 | { |
| 137 | var tableDefinition = this.GetTableDefinition(tableName, tableView, validationView); | 135 | var recordCount = rowRecord.GetFieldCount(); |
| 138 | var table = new Table(tableDefinition); | 136 | var row = table.CreateRow(output.SourceLineNumbers); |
| 139 | 137 | ||
| 140 | while (true) | 138 | for (var i = 0; recordCount > i && row.Fields.Length > i; i++) |
| 141 | { | 139 | { |
| 142 | using (var rowRecord = tableView.Fetch()) | 140 | if (rowRecord.IsNull(i + 1)) |
| 143 | { | 141 | { |
| 144 | if (null == rowRecord) | 142 | if (!row.Fields[i].Column.Nullable) |
| 145 | { | 143 | { |
| 146 | break; | 144 | // TODO: display an error for a null value in a non-nullable field OR |
| 145 | // display a warning and put an empty string in the value to let the compiler handle it | ||
| 146 | // (the second option is risky because the later code may make certain assumptions about | ||
| 147 | // the contents of a row value) | ||
| 147 | } | 148 | } |
| 148 | 149 | } | |
| 149 | var recordCount = rowRecord.GetFieldCount(); | 150 | else |
| 150 | var row = table.CreateRow(output.SourceLineNumbers); | 151 | { |
| 151 | 152 | switch (row.Fields[i].Column.Type) | |
| 152 | for (var i = 0; recordCount > i && row.Fields.Length > i; i++) | ||
| 153 | { | 153 | { |
| 154 | if (rowRecord.IsNull(i + 1)) | 154 | case ColumnType.Number: |
| 155 | { | 155 | var success = false; |
| 156 | if (!row.Fields[i].Column.Nullable) | 156 | var intValue = rowRecord.GetInteger(i + 1); |
| 157 | if (row.Fields[i].Column.IsLocalizable) | ||
| 157 | { | 158 | { |
| 158 | // TODO: display an error for a null value in a non-nullable field OR | 159 | success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); |
| 159 | // display a warning and put an empty string in the value to let the compiler handle it | ||
| 160 | // (the second option is risky because the later code may make certain assumptions about | ||
| 161 | // the contents of a row value) | ||
| 162 | } | 160 | } |
| 163 | } | 161 | else |
| 164 | else | ||
| 165 | { | ||
| 166 | switch (row.Fields[i].Column.Type) | ||
| 167 | { | 162 | { |
| 168 | case ColumnType.Number: | 163 | success = row.BestEffortSetField(i, intValue); |
| 169 | var success = false; | 164 | } |
| 170 | var intValue = rowRecord.GetInteger(i + 1); | ||
| 171 | if (row.Fields[i].Column.IsLocalizable) | ||
| 172 | { | ||
| 173 | success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture)); | ||
| 174 | } | ||
| 175 | else | ||
| 176 | { | ||
| 177 | success = row.BestEffortSetField(i, intValue); | ||
| 178 | } | ||
| 179 | 165 | ||
| 180 | if (!success) | 166 | if (!success) |
| 181 | { | 167 | { |
| 182 | this.Messaging.Write(WarningMessages.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); | 168 | this.Messaging.Write(WarningMessages.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name)); |
| 183 | } | 169 | } |
| 184 | break; | 170 | break; |
| 185 | case ColumnType.Object: | 171 | case ColumnType.Object: |
| 186 | var sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; | 172 | var sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES"; |
| 187 | 173 | ||
| 188 | if (null != this.ExportBasePath) | 174 | if (null != this.ExportBasePath) |
| 189 | { | 175 | { |
| 190 | var relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); | 176 | var relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.')); |
| 191 | sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile); | 177 | sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile); |
| 192 | 178 | ||
| 193 | // ensure the parent directory exists | 179 | // ensure the parent directory exists |
| 194 | System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); | 180 | System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName)); |
| 195 | 181 | ||
| 196 | using (var fs = System.IO.File.Create(sourceFile)) | 182 | using (var fs = System.IO.File.Create(sourceFile)) |
| 197 | { | 183 | { |
| 198 | int bytesRead; | 184 | int bytesRead; |
| 199 | var buffer = new byte[512]; | 185 | var buffer = new byte[512]; |
| 200 | 186 | ||
| 201 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) | 187 | while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length))) |
| 202 | { | 188 | { |
| 203 | fs.Write(buffer, 0, bytesRead); | 189 | fs.Write(buffer, 0, bytesRead); |
| 204 | } | ||
| 205 | } | 190 | } |
| 206 | |||
| 207 | this.exportedFiles.Add(sourceFile); | ||
| 208 | } | 191 | } |
| 209 | 192 | ||
| 210 | row[i] = sourceFile; | 193 | this.exportedFiles.Add(sourceFile); |
| 211 | break; | 194 | } |
| 212 | default: | ||
| 213 | var value = rowRecord.GetString(i + 1); | ||
| 214 | 195 | ||
| 215 | switch (row.Fields[i].Column.Category) | 196 | row[i] = sourceFile; |
| 216 | { | 197 | break; |
| 198 | default: | ||
| 199 | var value = rowRecord.GetString(i + 1); | ||
| 200 | |||
| 201 | switch (row.Fields[i].Column.Category) | ||
| 202 | { | ||
| 217 | case ColumnCategory.Guid: | 203 | case ColumnCategory.Guid: |
| 218 | value = value.ToUpper(CultureInfo.InvariantCulture); | 204 | value = value.ToUpper(CultureInfo.InvariantCulture); |
| 219 | break; | 205 | break; |
| 220 | } | 206 | } |
| 221 | 207 | ||
| 222 | // de-modularize | 208 | // de-modularize |
| 223 | if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) | 209 | if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType) |
| 224 | { | 210 | { |
| 225 | var modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); | 211 | var modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}"); |
| 226 | 212 | ||
| 227 | if (null == modularizationGuid) | 213 | if (null == modularizationGuid) |
| 214 | { | ||
| 215 | var match = modularization.Match(value); | ||
| 216 | if (match.Success) | ||
| 228 | { | 217 | { |
| 229 | var match = modularization.Match(value); | 218 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); |
| 230 | if (match.Success) | ||
| 231 | { | ||
| 232 | modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}'); | ||
| 233 | } | ||
| 234 | } | 219 | } |
| 235 | |||
| 236 | value = modularization.Replace(value, String.Empty); | ||
| 237 | } | 220 | } |
| 238 | 221 | ||
| 239 | // escape "$(" for the preprocessor | 222 | value = modularization.Replace(value, String.Empty); |
| 240 | value = value.Replace("$(", "$$("); | 223 | } |
| 241 | 224 | ||
| 242 | // escape things that look like wix variables | 225 | // escape "$(" for the preprocessor |
| 243 | var matches = Common.WixVariableRegex.Matches(value); | 226 | value = value.Replace("$(", "$$("); |
| 244 | for (var j = matches.Count - 1; 0 <= j; j--) | ||
| 245 | { | ||
| 246 | value = value.Insert(matches[j].Index, "!"); | ||
| 247 | } | ||
| 248 | 227 | ||
| 249 | row[i] = value; | 228 | // escape things that look like wix variables |
| 250 | break; | 229 | var matches = Common.WixVariableRegex.Matches(value); |
| 230 | for (var j = matches.Count - 1; 0 <= j; j--) | ||
| 231 | { | ||
| 232 | value = value.Insert(matches[j].Index, "!"); | ||
| 251 | } | 233 | } |
| 252 | } | 234 | |
| 235 | row[i] = value; | ||
| 236 | break; | ||
| 253 | } | 237 | } |
| 254 | } | 238 | } |
| 255 | } | 239 | } |
| 256 | |||
| 257 | output.Tables.Add(table); | ||
| 258 | } | 240 | } |
| 259 | 241 | ||
| 242 | output.Tables.Add(table); | ||
| 260 | } | 243 | } |
| 261 | } | 244 | } |
| 262 | } | 245 | } |
| @@ -634,82 +617,82 @@ namespace WixToolset.Core.WindowsInstaller.Unbind | |||
| 634 | { | 617 | { |
| 635 | switch (table.Name) | 618 | switch (table.Name) |
| 636 | { | 619 | { |
| 637 | case "WixFile": | 620 | case "WixFile": |
| 638 | case "MsiFileHash": | 621 | case "MsiFileHash": |
| 639 | ConnectTableToSection(table, fileSectionIdIndex, 0); | 622 | ConnectTableToSection(table, fileSectionIdIndex, 0); |
| 640 | break; | 623 | break; |
| 641 | case "MsiAssembly": | 624 | case "MsiAssembly": |
| 642 | case "MsiAssemblyName": | 625 | case "MsiAssemblyName": |
| 643 | ConnectTableToSection(table, componentSectionIdIndex, 0); | 626 | ConnectTableToSection(table, componentSectionIdIndex, 0); |
| 644 | break; | 627 | break; |
| 645 | case "MsiPackageCertificate": | 628 | case "MsiPackageCertificate": |
| 646 | case "MsiPatchCertificate": | 629 | case "MsiPatchCertificate": |
| 647 | ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1); | 630 | ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1); |
| 648 | break; | 631 | break; |
| 649 | case "CreateFolder": | 632 | case "CreateFolder": |
| 650 | case "FeatureComponents": | 633 | case "FeatureComponents": |
| 651 | case "MoveFile": | 634 | case "MoveFile": |
| 652 | case "ReserveCost": | 635 | case "ReserveCost": |
| 653 | case "ODBCTranslator": | 636 | case "ODBCTranslator": |
| 654 | ConnectTableToSection(table, componentSectionIdIndex, 1); | 637 | ConnectTableToSection(table, componentSectionIdIndex, 1); |
| 655 | break; | 638 | break; |
| 656 | case "TypeLib": | 639 | case "TypeLib": |
| 657 | ConnectTableToSection(table, componentSectionIdIndex, 2); | 640 | ConnectTableToSection(table, componentSectionIdIndex, 2); |
| 658 | break; | 641 | break; |
| 659 | case "Shortcut": | 642 | case "Shortcut": |
| 660 | case "Environment": | 643 | case "Environment": |
| 661 | ConnectTableToSection(table, componentSectionIdIndex, 3); | 644 | ConnectTableToSection(table, componentSectionIdIndex, 3); |
| 662 | break; | 645 | break; |
| 663 | case "RemoveRegistry": | 646 | case "RemoveRegistry": |
| 664 | ConnectTableToSection(table, componentSectionIdIndex, 4); | 647 | ConnectTableToSection(table, componentSectionIdIndex, 4); |
| 665 | break; | 648 | break; |
| 666 | case "ServiceControl": | 649 | case "ServiceControl": |
| 667 | ConnectTableToSection(table, componentSectionIdIndex, 5); | 650 | ConnectTableToSection(table, componentSectionIdIndex, 5); |
| 668 | break; | 651 | break; |
| 669 | case "IniFile": | 652 | case "IniFile": |
| 670 | case "RemoveIniFile": | 653 | case "RemoveIniFile": |
| 671 | ConnectTableToSection(table, componentSectionIdIndex, 7); | 654 | ConnectTableToSection(table, componentSectionIdIndex, 7); |
| 672 | break; | 655 | break; |
| 673 | case "AppId": | 656 | case "AppId": |
| 674 | ConnectTableToSection(table, appIdSectionIdIndex, 0); | 657 | ConnectTableToSection(table, appIdSectionIdIndex, 0); |
| 675 | break; | 658 | break; |
| 676 | case "Condition": | 659 | case "Condition": |
| 677 | ConnectTableToSection(table, featureSectionIdIndex, 0); | 660 | ConnectTableToSection(table, featureSectionIdIndex, 0); |
| 678 | break; | 661 | break; |
| 679 | case "ODBCSourceAttribute": | 662 | case "ODBCSourceAttribute": |
| 680 | ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0); | 663 | ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0); |
| 681 | break; | 664 | break; |
| 682 | case "ODBCAttribute": | 665 | case "ODBCAttribute": |
| 683 | ConnectTableToSection(table, odbcDriverSectionIdIndex, 0); | 666 | ConnectTableToSection(table, odbcDriverSectionIdIndex, 0); |
| 684 | break; | 667 | break; |
| 685 | case "AdminExecuteSequence": | 668 | case "AdminExecuteSequence": |
| 686 | case "AdminUISequence": | 669 | case "AdminUISequence": |
| 687 | case "AdvtExecuteSequence": | 670 | case "AdvtExecuteSequence": |
| 688 | case "AdvtUISequence": | 671 | case "AdvtUISequence": |
| 689 | case "InstallExecuteSequence": | 672 | case "InstallExecuteSequence": |
| 690 | case "InstallUISequence": | 673 | case "InstallUISequence": |
| 691 | ConnectTableToSection(table, customActionSectionIdIndex, 0); | 674 | ConnectTableToSection(table, customActionSectionIdIndex, 0); |
| 692 | break; | 675 | break; |
| 693 | case "LockPermissions": | 676 | case "LockPermissions": |
| 694 | case "MsiLockPermissions": | 677 | case "MsiLockPermissions": |
| 695 | foreach (var row in table.Rows) | 678 | foreach (var row in table.Rows) |
| 696 | { | ||
| 697 | var lockObject = (string)row[0]; | ||
| 698 | var tableName = (string)row[1]; | ||
| 699 | switch (tableName) | ||
| 700 | { | 679 | { |
| 701 | case "File": | 680 | var lockObject = (string)row[0]; |
| 702 | row.SectionId = (string)fileSectionIdIndex[lockObject]; | 681 | var tableName = (string)row[1]; |
| 703 | break; | 682 | switch (tableName) |
| 704 | case "Registry": | 683 | { |
| 705 | row.SectionId = (string)registrySectionIdIndex[lockObject]; | 684 | case "File": |
| 706 | break; | 685 | row.SectionId = (string)fileSectionIdIndex[lockObject]; |
| 707 | case "ServiceInstall": | 686 | break; |
| 708 | row.SectionId = (string)serviceInstallSectionIdIndex[lockObject]; | 687 | case "Registry": |
| 709 | break; | 688 | row.SectionId = (string)registrySectionIdIndex[lockObject]; |
| 689 | break; | ||
| 690 | case "ServiceInstall": | ||
| 691 | row.SectionId = (string)serviceInstallSectionIdIndex[lockObject]; | ||
| 692 | break; | ||
| 693 | } | ||
| 710 | } | 694 | } |
| 711 | } | 695 | break; |
| 712 | break; | ||
| 713 | } | 696 | } |
| 714 | } | 697 | } |
| 715 | 698 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Validator.cs b/src/WixToolset.Core.WindowsInstaller/Validator.cs index 1c9cdc2f..72b09ebc 100644 --- a/src/WixToolset.Core.WindowsInstaller/Validator.cs +++ b/src/WixToolset.Core.WindowsInstaller/Validator.cs | |||
| @@ -201,21 +201,13 @@ namespace WixToolset.Core.WindowsInstaller | |||
| 201 | List<string> actions = new List<string>(); | 201 | List<string> actions = new List<string>(); |
| 202 | using (View view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`")) | 202 | using (View view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`")) |
| 203 | { | 203 | { |
| 204 | while (true) | 204 | foreach (Record record in view.Records) |
| 205 | { | 205 | { |
| 206 | using (Record record = view.Fetch()) | 206 | string action = record.GetString(1); |
| 207 | { | ||
| 208 | if (null == record) | ||
| 209 | { | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | 207 | ||
| 213 | string action = record.GetString(1); | 208 | if ((this.SuppressedICEs == null || !this.SuppressedICEs.Contains(action)) && (this.ICEs == null || this.ICEs.Contains(action))) |
| 214 | 209 | { | |
| 215 | if ((this.SuppressedICEs == null || !this.SuppressedICEs.Contains(action)) && (this.ICEs == null || this.ICEs.Contains(action))) | 210 | actions.Add(action); |
| 216 | { | ||
| 217 | actions.Add(action); | ||
| 218 | } | ||
| 219 | } | 211 | } |
| 220 | } | 212 | } |
| 221 | } | 213 | } |
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index 5ee60984..023a3c1e 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs | |||
| @@ -591,7 +591,7 @@ namespace WixToolset.Core.CommandLine | |||
| 591 | this.OutputType = Path.GetExtension(this.OutputFile); | 591 | this.OutputType = Path.GetExtension(this.OutputFile); |
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | switch (this.OutputType.ToLowerInvariant()) | 594 | switch (this.OutputType?.ToLowerInvariant()) |
| 595 | { | 595 | { |
| 596 | case "bundle": | 596 | case "bundle": |
| 597 | case ".exe": | 597 | case ".exe": |
