From 477b227fca1246e37bae678a9af3154ffba84c0d Mon Sep 17 00:00:00 2001 From: Martin Broholm Andersen <090578@gmail.com> Date: Tue, 21 May 2024 22:35:14 +0200 Subject: [PATCH] Replace UpdateFileFacade loop with Parallel.ForEach --- .../Bind/BindDatabaseCommand.cs | 9 +- .../Bind/UpdateFileFacadesCommand.cs | 541 +++++++++++------- 2 files changed, 331 insertions(+), 219 deletions(-) diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 4db1bfbed..f1c5f8514 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -6,6 +6,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind using System.Collections.Generic; using System.IO; using System.Linq; + using System.Threading; using WixToolset.Data; using WixToolset.Data.Symbols; using WixToolset.Data.WindowsInstaller; @@ -50,6 +51,8 @@ public BindDatabaseCommand(IBindContext context, IEnumerable allFileFacades.First(ff => ff.Id == f.Id?.Id)); - var command = new UpdateFileFacadesCommand(this.Messaging, this.FileSystem, section, allFileFacades, updatedFacades, variableCache, overwriteHash: false); + var command = new UpdateFileFacadesCommand(this.Messaging, this.FileSystem, section, allFileFacades, updatedFacades, variableCache, overwriteHash: false, this.CancellationToken); command.Execute(); } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index b51e3a0f7..5792fdcb2 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs @@ -3,11 +3,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; + using System.Threading; + using System.Threading.Tasks; using WixToolset.Core.Native.Msi; using WixToolset.Data; using WixToolset.Data.Symbols; @@ -19,7 +22,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind /// internal class UpdateFileFacadesCommand { - public UpdateFileFacadesCommand(IMessaging messaging, IFileSystem fileSystem, IntermediateSection section, IEnumerable allFileFacades, IEnumerable updateFileFacades, IDictionary variableCache, bool overwriteHash) + public UpdateFileFacadesCommand(IMessaging messaging, IFileSystem fileSystem, IntermediateSection section, IEnumerable allFileFacades, IEnumerable updateFileFacades, IDictionary variableCache, bool overwriteHash, CancellationToken cancellationToken) { this.Messaging = messaging; this.FileSystem = fileSystem; @@ -28,6 +31,7 @@ public UpdateFileFacadesCommand(IMessaging messaging, IFileSystem fileSystem, In this.UpdateFileFacades = updateFileFacades; this.VariableCache = variableCache; this.OverwriteHash = overwriteHash; + this.CancellationToken = cancellationToken; } private IMessaging Messaging { get; } @@ -44,306 +48,409 @@ public UpdateFileFacadesCommand(IMessaging messaging, IFileSystem fileSystem, In private IDictionary VariableCache { get; } - public void Execute() - { - var assemblySymbols = this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id); - var assemblyNameSymbols = this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id); + private CancellationToken CancellationToken { get; } - foreach (var file in this.UpdateFileFacades.Where(f => f.SourcePath != null)) - { - this.UpdateFileFacade(file, assemblySymbols, assemblyNameSymbols); - } - } - - private void UpdateFileFacade(IFileFacade facade, Dictionary assemblySymbols, Dictionary assemblyNameSymbols) + public void Execute() { - FileInfo fileInfo = null; try { - fileInfo = new FileInfo(facade.SourcePath); + this.UpdateFileFacadesInParallel(this.UpdateFileFacades.Where(f => f.SourcePath != null)); } - catch (ArgumentException) + catch (AggregateException ae) { - this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); - return; - } - catch (PathTooLongException) - { - this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); - return; - } - catch (NotSupportedException) - { - this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); - return; - } - - if (!fileInfo.Exists) - { - this.Messaging.Write(ErrorMessages.CannotFindFile(facade.SourceLineNumber, facade.Id, facade.FileName, facade.SourcePath)); - return; - } - - using (var fileStream = this.FileSystem.OpenFile(facade.SourceLineNumber, fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - if (Int32.MaxValue < fileStream.Length) + foreach (var ex in ae.Flatten().InnerExceptions) { - throw new WixException(ErrorMessages.FileTooLarge(facade.SourceLineNumber, facade.SourcePath)); + throw ex; } - - facade.FileSize = Convert.ToInt32(fileStream.Length, CultureInfo.InvariantCulture); } + } - string version = null; - string language = null; - try - { - Installer.GetFileVersion(fileInfo.FullName, out version, out language); - } - catch (Win32Exception e) - { - if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND - { - throw new WixException(ErrorMessages.FileNotFound(facade.SourceLineNumber, fileInfo.FullName)); - } - else - { - throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, e.Message)); - } - } + private void UpdateFileFacadesInParallel(IEnumerable facades) + { + var mut = new Mutex(); + var exceptions = new ConcurrentQueue(); - // If there is no version, it is assumed there is no language because it won't matter in the versioning of the install. - if (String.IsNullOrEmpty(version)) // unversioned files have their hashes added to the MsiFileHash table - { - if (!this.OverwriteHash) + var assemblySymbols = this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id); + + Parallel.ForEach(facades, + new ParallelOptions{ + CancellationToken = this.CancellationToken + }, + () => { - // not overwriting hash, so don't do the rest of these options. - } - else if (null != facade.Version) + return new LocalData( + this.Messaging, + this.FileSystem, + this.AllFileFacades, + this.OverwriteHash, + this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id), + useVariableCache: null != this.VariableCache + ); + }, + (file, loopstate, local) => { - // Search all of the file rows available to see if the specified version is actually a companion file. Yes, this looks - // very expensive and you're probably thinking it would be better to create an index of some sort to do an O(1) look up. - // That's a reasonable thought but companion file usage is usually pretty rare so we'd be doing something expensive (indexing - // all the file rows) for a relatively uncommon situation. Let's not do that. - // - // Also, if we do not find a matching file identifier then the user provided a default version and is providing a version - // for unversioned file. That's allowed but generally a dangerous thing to do so let's point that out to the user. - if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) + try { - this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(facade.SourceLineNumber, facade.Version, facade.Id)); + local.UpdateFileFacade(file, assemblySymbols); } - } - else - { - if (null != facade.Language) + catch (Exception ex) { - this.Messaging.Write(WarningMessages.DefaultLanguageUsedForUnversionedFile(facade.SourceLineNumber, facade.Language, facade.Id)); + exceptions.Enqueue(ex); + loopstate.Stop(); } - int[] hash; - try - { - Installer.GetFileHash(fileInfo.FullName, 0, out hash); - } - catch (Win32Exception e) + return local; + }, + (local) => + { + // Merge local variable cache back into common variable cache + if (null != this.VariableCache) { - if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND + mut.WaitOne(); + try { - throw new WixException(ErrorMessages.FileNotFound(facade.SourceLineNumber, fileInfo.FullName)); + local.MergeVariableCacheWith(this.VariableCache); } - else + finally { - throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, fileInfo.FullName, e.Message)); + mut.ReleaseMutex(); } } + } + ); + + if (!exceptions.IsEmpty) + { + throw new AggregateException(exceptions); + } + } - // Remember the hash symbol for use later. - facade.MsiFileHashSymbol = new MsiFileHashSymbol(facade.SourceLineNumber, facade.Identifier) + + internal class LocalData + { + public LocalData(IMessaging messaging, IFileSystem fileSystem, IEnumerable allFileFacades, bool overwriteHash, Dictionary assemblyNameSymbols, bool useVariableCache) + { + this.Messaging = messaging; + this.FileSystem = fileSystem; + this.AllFileFacades = allFileFacades; + this.OverwriteHash = overwriteHash; + this.AssemblyNameSymbols = assemblyNameSymbols; + this.VariableCache = useVariableCache ? new Dictionary() : null; + } + + private IMessaging Messaging { get; } + + private IFileSystem FileSystem { get; } + + private IEnumerable AllFileFacades { get; } + + private bool OverwriteHash { get; } + + private Dictionary AssemblyNameSymbols { get; } + + private Dictionary VariableCache { get; } + + public void MergeVariableCacheWith(IDictionary variableCache) + { + if (null != variableCache && null != this.VariableCache) + { + foreach (var v in this.VariableCache) { - Options = 0, - HashPart1 = hash[0], - HashPart2 = hash[1], - HashPart3 = hash[2], - HashPart4 = hash[3], - }; + variableCache[v.Key] = v.Value; + } } } - else // update the file row with the version and language information. + + public void UpdateFileFacade(IFileFacade facade, Dictionary assemblySymbols) { - // If no version was provided by the user, use the version from the file itself. - // This is the most common case. - if (String.IsNullOrEmpty(facade.Version)) + FileInfo fileInfo = null; + try { - facade.Version = version; + fileInfo = new FileInfo(facade.SourcePath); } - else if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) // this looks expensive, but see explanation below. + catch (ArgumentException) { - // The user provided a default version for the file row so we looked for a companion file (a file row with Id matching - // the version value). We didn't find it so, we will override the default version they provided with the actual - // version from the file itself. Now, I know it looks expensive to search through all the file rows trying to match - // on the Id. However, the alternative is to build a big index of all file rows to do look ups. Since this case - // where the file version is already present is rare (companion files are pretty uncommon), we'll do the more - // CPU intensive search to save on the memory intensive index that wouldn't be used much. - // - // Also note this case can occur when the file is being updated using the WixBindUpdatedFiles extension mechanism. - // That's typically even more rare than companion files so again, no index, just search. - facade.Version = version; + this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); + return; } - - if (!String.IsNullOrEmpty(facade.Language) && String.IsNullOrEmpty(language)) + catch (PathTooLongException) { - this.Messaging.Write(WarningMessages.DefaultLanguageUsedForVersionedFile(facade.SourceLineNumber, facade.Language, facade.Id)); + this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); + return; } - else // override the default provided by the user (usually nothing) with the actual language from the file itself. + catch (NotSupportedException) { - facade.Language = language; + this.Messaging.Write(ErrorMessages.InvalidFileName(facade.SourceLineNumber, facade.SourcePath)); + return; } - } - // Populate the binder variables for this file information if requested. - if (null != this.VariableCache) - { - this.VariableCache[$"fileversion.{facade.Id}"] = facade.Version ?? String.Empty; - this.VariableCache[$"filelanguage.{facade.Id}"] = facade.Language ?? String.Empty; - } + if (!fileInfo.Exists) + { + this.Messaging.Write(ErrorMessages.CannotFindFile(facade.SourceLineNumber, facade.Id, facade.FileName, facade.SourcePath)); + return; + } - // If there is an assembly for this file. - if (assemblySymbols.TryGetValue(facade.Id, out var assemblySymbol)) - { - // If this is a CLR assembly, load the assembly and get the assembly name information - if (AssemblyType.DotNetAssembly == assemblySymbol.Type) + using (var fileStream = this.FileSystem.OpenFile(facade.SourceLineNumber, fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) { - try + if (Int32.MaxValue < fileStream.Length) { - var assemblyName = AssemblyNameReader.ReadAssembly(this.FileSystem, facade.SourceLineNumber, fileInfo.FullName, version); + throw new WixException(ErrorMessages.FileTooLarge(facade.SourceLineNumber, facade.SourcePath)); + } - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "name", assemblyName.Name); - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "culture", assemblyName.Culture); - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "version", assemblyName.Version); + facade.FileSize = Convert.ToInt32(fileStream.Length, CultureInfo.InvariantCulture); + } - if (!String.IsNullOrEmpty(assemblyName.Architecture)) - { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); - } - // TODO: WiX v3 seemed to do this but not clear it should actually be done. - //else if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) - //{ - // this.SetMsiAssemblyName(assemblyNameSymbols, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); - //} + string version = null; + string language = null; + try + { + Installer.GetFileVersion(fileInfo.FullName, out version, out language); + } + catch (Win32Exception e) + { + if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND + { + throw new WixException(ErrorMessages.FileNotFound(facade.SourceLineNumber, fileInfo.FullName)); + } + else + { + throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, e.Message)); + } + } - if (assemblyName.StrongNamedSigned) + // If there is no version, it is assumed there is no language because it won't matter in the versioning of the install. + if (String.IsNullOrEmpty(version)) // unversioned files have their hashes added to the MsiFileHash table + { + if (!this.OverwriteHash) + { + // not overwriting hash, so don't do the rest of these options. + } + else if (null != facade.Version) + { + // Search all of the file rows available to see if the specified version is actually a companion file. Yes, this looks + // very expensive and you're probably thinking it would be better to create an index of some sort to do an O(1) look up. + // That's a reasonable thought but companion file usage is usually pretty rare so we'd be doing something expensive (indexing + // all the file rows) for a relatively uncommon situation. Let's not do that. + // + // Also, if we do not find a matching file identifier then the user provided a default version and is providing a version + // for unversioned file. That's allowed but generally a dangerous thing to do so let's point that out to the user. + if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); + this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(facade.SourceLineNumber, facade.Version, facade.Id)); } - else if (assemblySymbol.ApplicationFileRef == null) + } + else + { + if (null != facade.Language) { - throw new WixException(ErrorMessages.GacAssemblyNoStrongName(facade.SourceLineNumber, fileInfo.FullName, facade.ComponentRef)); + this.Messaging.Write(WarningMessages.DefaultLanguageUsedForUnversionedFile(facade.SourceLineNumber, facade.Language, facade.Id)); } - if (!String.IsNullOrEmpty(assemblyName.FileVersion)) + int[] hash; + try { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "fileVersion", assemblyName.FileVersion); + Installer.GetFileHash(fileInfo.FullName, 0, out hash); } - - // add the assembly name to the information cache - if (null != this.VariableCache) + catch (Win32Exception e) { - this.VariableCache[$"assemblyfullname.{facade.Id}"] = assemblyName.GetFullName(); + if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND + { + throw new WixException(ErrorMessages.FileNotFound(facade.SourceLineNumber, fileInfo.FullName)); + } + else + { + throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, fileInfo.FullName, e.Message)); + } } - } - catch (WixException e) - { - this.Messaging.Write(e.Error); + + // Remember the hash symbol for use later. + facade.MsiFileHashSymbol = new MsiFileHashSymbol(facade.SourceLineNumber, facade.Identifier) + { + Options = 0, + HashPart1 = hash[0], + HashPart2 = hash[1], + HashPart3 = hash[2], + HashPart4 = hash[3], + }; } } - else if (AssemblyType.Win32Assembly == assemblySymbol.Type) + else // update the file row with the version and language information. { - // TODO: Consider passing in the this.AllFileFacades as an indexed collection instead of searching through - // all files like this. Even though this is a rare case it looks like we might be able to index the - // file earlier. - var fileManifest = this.AllFileFacades.FirstOrDefault(r => r.Id.Equals(assemblySymbol.ManifestFileRef, StringComparison.Ordinal)); - if (null == fileManifest) + // If no version was provided by the user, use the version from the file itself. + // This is the most common case. + if (String.IsNullOrEmpty(facade.Version)) + { + facade.Version = version; + } + else if (!this.AllFileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) // this looks expensive, but see explanation below. { - this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(facade.SourceLineNumber, facade.Id, assemblySymbol.ManifestFileRef)); + // The user provided a default version for the file row so we looked for a companion file (a file row with Id matching + // the version value). We didn't find it so, we will override the default version they provided with the actual + // version from the file itself. Now, I know it looks expensive to search through all the file rows trying to match + // on the Id. However, the alternative is to build a big index of all file rows to do look ups. Since this case + // where the file version is already present is rare (companion files are pretty uncommon), we'll do the more + // CPU intensive search to save on the memory intensive index that wouldn't be used much. + // + // Also note this case can occur when the file is being updated using the WixBindUpdatedFiles extension mechanism. + // That's typically even more rare than companion files so again, no index, just search. + facade.Version = version; } - try + if (!String.IsNullOrEmpty(facade.Language) && String.IsNullOrEmpty(language)) + { + this.Messaging.Write(WarningMessages.DefaultLanguageUsedForVersionedFile(facade.SourceLineNumber, facade.Language, facade.Id)); + } + else // override the default provided by the user (usually nothing) with the actual language from the file itself. { - var assemblyName = AssemblyNameReader.ReadAssemblyManifest(facade.SourceLineNumber, fileManifest.SourcePath); + facade.Language = language; + } + } + + // Populate the binder variables for this file information if requested. + if (null != this.VariableCache) + { + this.VariableCache[$"fileversion.{facade.Id}"] = facade.Version ?? String.Empty; + this.VariableCache[$"filelanguage.{facade.Id}"] = facade.Language ?? String.Empty; + } - if (!String.IsNullOrEmpty(assemblyName.Name)) + // If there is an assembly for this file. + if (assemblySymbols.TryGetValue(facade.Id, out var assemblySymbol)) + { + // If this is a CLR assembly, load the assembly and get the assembly name information + if (AssemblyType.DotNetAssembly == assemblySymbol.Type) + { + try { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "name", assemblyName.Name); + var assemblyName = AssemblyNameReader.ReadAssembly(this.FileSystem, facade.SourceLineNumber, fileInfo.FullName, version); + + this.SetMsiAssemblyName(facade, assemblySymbol, "name", assemblyName.Name); + this.SetMsiAssemblyName(facade, assemblySymbol, "culture", assemblyName.Culture); + this.SetMsiAssemblyName(facade, assemblySymbol, "version", assemblyName.Version); + + if (!String.IsNullOrEmpty(assemblyName.Architecture)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); + } + // TODO: WiX v3 seemed to do this but not clear it should actually be done. + //else if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture)) + //{ + // this.SetMsiAssemblyName(assemblyNameSymbols, file, "processorArchitecture", file.WixFile.ProcessorArchitecture); + //} + + if (assemblyName.StrongNamedSigned) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); + } + else if (assemblySymbol.ApplicationFileRef == null) + { + throw new WixException(ErrorMessages.GacAssemblyNoStrongName(facade.SourceLineNumber, fileInfo.FullName, facade.ComponentRef)); + } + + if (!String.IsNullOrEmpty(assemblyName.FileVersion)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "fileVersion", assemblyName.FileVersion); + } + + // add the assembly name to the information cache + if (null != this.VariableCache) + { + this.VariableCache[$"assemblyfullname.{facade.Id}"] = assemblyName.GetFullName(); + } } - - if (!String.IsNullOrEmpty(assemblyName.Version)) + catch (WixException e) { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "version", assemblyName.Version); + this.Messaging.Write(e.Error); } - - if (!String.IsNullOrEmpty(assemblyName.Type)) + } + else if (AssemblyType.Win32Assembly == assemblySymbol.Type) + { + // TODO: Consider passing in the this.AllFileFacades as an indexed collection instead of searching through + // all files like this. Even though this is a rare case it looks like we might be able to index the + // file earlier. + var fileManifest = this.AllFileFacades.FirstOrDefault(r => r.Id.Equals(assemblySymbol.ManifestFileRef, StringComparison.Ordinal)); + if (null == fileManifest) { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "type", assemblyName.Type); + this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(facade.SourceLineNumber, facade.Id, assemblySymbol.ManifestFileRef)); } - if (!String.IsNullOrEmpty(assemblyName.Architecture)) + try { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); + var assemblyName = AssemblyNameReader.ReadAssemblyManifest(facade.SourceLineNumber, fileManifest.SourcePath); + + if (!String.IsNullOrEmpty(assemblyName.Name)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "name", assemblyName.Name); + } + + if (!String.IsNullOrEmpty(assemblyName.Version)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "version", assemblyName.Version); + } + + if (!String.IsNullOrEmpty(assemblyName.Type)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "type", assemblyName.Type); + } + + if (!String.IsNullOrEmpty(assemblyName.Architecture)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "processorArchitecture", assemblyName.Architecture); + } + + if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken)) + { + this.SetMsiAssemblyName(facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); + } } - - if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken)) + catch (WixException e) { - this.SetMsiAssemblyName(assemblyNameSymbols, facade, assemblySymbol, "publicKeyToken", assemblyName.PublicKeyToken); + this.Messaging.Write(e.Error); } } - catch (WixException e) - { - this.Messaging.Write(e.Error); - } } } - } - private void SetMsiAssemblyName(Dictionary assemblyNameSymbols, IFileFacade facade, AssemblySymbol assemblySymbol, string name, string value) - { - // check for null value (this can occur when grabbing the file version from an assembly without one) - if (String.IsNullOrEmpty(value)) + private void SetMsiAssemblyName(IFileFacade facade, AssemblySymbol assemblySymbol, string name, string value) { - this.Messaging.Write(WarningMessages.NullMsiAssemblyNameValue(facade.SourceLineNumber, facade.ComponentRef, name)); - } - else - { - // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. - if ("name" == name && AssemblyType.DotNetAssembly == assemblySymbol.Type && - String.IsNullOrEmpty(assemblySymbol.ApplicationFileRef) && - !String.Equals(Path.GetFileNameWithoutExtension(facade.FileName), value, StringComparison.OrdinalIgnoreCase)) - { - this.Messaging.Write(ErrorMessages.GACAssemblyIdentityWarning(facade.SourceLineNumber, Path.GetFileNameWithoutExtension(facade.FileName), value)); - } - - // Override directly authored value, otherwise remember the gathered information on the facade for use later. - var lookup = String.Concat(facade.ComponentRef, "/", name); - if (assemblyNameSymbols.TryGetValue(lookup, out var assemblyNameSymbol)) + // check for null value (this can occur when grabbing the file version from an assembly without one) + if (String.IsNullOrEmpty(value)) { - assemblyNameSymbol.Value = value; + this.Messaging.Write(WarningMessages.NullMsiAssemblyNameValue(facade.SourceLineNumber, facade.ComponentRef, name)); } else { - assemblyNameSymbol = new MsiAssemblyNameSymbol(assemblySymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, facade.ComponentRef, name)) + // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. + if ("name" == name && AssemblyType.DotNetAssembly == assemblySymbol.Type && + String.IsNullOrEmpty(assemblySymbol.ApplicationFileRef) && + !String.Equals(Path.GetFileNameWithoutExtension(facade.FileName), value, StringComparison.OrdinalIgnoreCase)) { - ComponentRef = facade.ComponentRef, - Name = name, - Value = value, - }; + this.Messaging.Write(ErrorMessages.GACAssemblyIdentityWarning(facade.SourceLineNumber, Path.GetFileNameWithoutExtension(facade.FileName), value)); + } - facade.AssemblyNameSymbols.Add(assemblyNameSymbol); - assemblyNameSymbols.Add(assemblyNameSymbol.Id.Id, assemblyNameSymbol); - } + // Override directly authored value, otherwise remember the gathered information on the facade for use later. + var lookup = String.Concat(facade.ComponentRef, "/", name); + if (this.AssemblyNameSymbols.TryGetValue(lookup, out var assemblyNameSymbol)) + { + assemblyNameSymbol.Value = value; + } + else + { + assemblyNameSymbol = new MsiAssemblyNameSymbol(assemblySymbol.SourceLineNumbers, new Identifier(AccessModifier.Section, facade.ComponentRef, name)) + { + ComponentRef = facade.ComponentRef, + Name = name, + Value = value, + }; - if (this.VariableCache != null) - { - var key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, facade.Id).ToLowerInvariant(); - this.VariableCache[key] = value; + facade.AssemblyNameSymbols.Add(assemblyNameSymbol); + this.AssemblyNameSymbols.Add(assemblyNameSymbol.Id.Id, assemblyNameSymbol); + } + + if (this.VariableCache != null) + { + var key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, facade.Id).ToLowerInvariant(); + this.VariableCache[key] = value; + } } } }