Пример #1
0
        private void UpdateFileFacade(FileFacade facade, Dictionary <string, MsiAssemblyNameSymbol> assemblyNameSymbols)
        {
            FileInfo fileInfo = null;

            try
            {
                fileInfo = new FileInfo(facade.SourcePath);
            }
            catch (ArgumentException)
            {
                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 = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if (Int32.MaxValue < fileStream.Length)
                {
                    throw new WixException(ErrorMessages.FileTooLarge(facade.SourceLineNumber, facade.SourcePath));
                }

                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));
                }
            }

            // 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.FileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal)))
                    {
                        this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(facade.SourceLineNumber, facade.Version, facade.Id));
                    }
                }
                else
                {
                    if (null != facade.Language)
                    {
                        this.Messaging.Write(WarningMessages.DefaultLanguageUsedForUnversionedFile(facade.SourceLineNumber, facade.Language, facade.Id));
                    }

                    int[] hash;
                    try
                    {
                        Installer.GetFileHash(fileInfo.FullName, 0, out hash);
                    }
                    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, fileInfo.FullName, e.Message));
                        }
                    }

                    if (null == facade.Hash)
                    {
                        facade.Hash = this.Section.AddSymbol(new MsiFileHashSymbol(facade.SourceLineNumber, facade.Identifier));
                    }

                    facade.Hash.Options   = 0;
                    facade.Hash.HashPart1 = hash[0];
                    facade.Hash.HashPart2 = hash[1];
                    facade.Hash.HashPart3 = hash[2];
                    facade.Hash.HashPart4 = hash[3];
                }
            }
            else // update the file row with the version and language information.
            {
                // 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.FileFacades.Any(r => facade.Version.Equals(r.Id, StringComparison.Ordinal))) // this looks expensive, but see explanation below.
                {
                    // 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;
                }

                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.
                {
                    facade.Language = language;
                }

                // Populate the binder variables for this file information if requested.
                if (null != this.VariableCache)
                {
                    if (!String.IsNullOrEmpty(facade.Version))
                    {
                        var key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", facade.Id);
                        this.VariableCache[key] = facade.Version;
                    }

                    if (!String.IsNullOrEmpty(facade.Language))
                    {
                        var key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", facade.Id);
                        this.VariableCache[key] = facade.Language;
                    }
                }
            }

            // If this is a CLR assembly, load the assembly and get the assembly name information
            if (AssemblyType.DotNetAssembly == facade.AssemblyType)
            {
                try
                {
                    var assemblyName = AssemblyNameReader.ReadAssembly(facade.SourceLineNumber, fileInfo.FullName, version);

                    this.SetMsiAssemblyName(assemblyNameSymbols, facade, "name", assemblyName.Name);
                    this.SetMsiAssemblyName(assemblyNameSymbols, facade, "culture", assemblyName.Culture);
                    this.SetMsiAssemblyName(assemblyNameSymbols, facade, "version", assemblyName.Version);

                    if (!String.IsNullOrEmpty(assemblyName.Architecture))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "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(assemblyNameSymbols, facade, "publicKeyToken", assemblyName.PublicKeyToken);
                    }
                    else if (facade.AssemblyApplicationFileRef == null)
                    {
                        throw new WixException(ErrorMessages.GacAssemblyNoStrongName(facade.SourceLineNumber, fileInfo.FullName, facade.ComponentRef));
                    }

                    if (!String.IsNullOrEmpty(assemblyName.FileVersion))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "fileVersion", assemblyName.FileVersion);
                    }

                    // add the assembly name to the information cache
                    if (null != this.VariableCache)
                    {
                        this.VariableCache[$"assemblyfullname.{facade.Id}"] = assemblyName.GetFullName();
                    }
                }
                catch (WixException e)
                {
                    this.Messaging.Write(e.Error);
                }
            }
            else if (AssemblyType.Win32Assembly == facade.AssemblyType)
            {
                // TODO: Consider passing in the this.FileFacades 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.FileFacades.FirstOrDefault(r => r.Id.Equals(facade.AssemblyManifestFileRef, StringComparison.Ordinal));
                if (null == fileManifest)
                {
                    this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(facade.SourceLineNumber, facade.Id, facade.AssemblyManifestFileRef));
                }

                try
                {
                    var assemblyName = AssemblyNameReader.ReadAssemblyManifest(facade.SourceLineNumber, fileManifest.SourcePath);

                    if (!String.IsNullOrEmpty(assemblyName.Name))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "name", assemblyName.Name);
                    }

                    if (!String.IsNullOrEmpty(assemblyName.Version))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "version", assemblyName.Version);
                    }

                    if (!String.IsNullOrEmpty(assemblyName.Type))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "type", assemblyName.Type);
                    }

                    if (!String.IsNullOrEmpty(assemblyName.Architecture))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "processorArchitecture", assemblyName.Architecture);
                    }

                    if (!String.IsNullOrEmpty(assemblyName.PublicKeyToken))
                    {
                        this.SetMsiAssemblyName(assemblyNameSymbols, facade, "publicKeyToken", assemblyName.PublicKeyToken);
                    }
                }
                catch (WixException e)
                {
                    this.Messaging.Write(e.Error);
                }
            }
        }
Пример #2
0
        private void UpdateFileFacade(FileFacade file)
        {
            var assemblyNameTuples = new Dictionary <string, MsiAssemblyNameTuple>();

            foreach (var assemblyTuple in this.Section.Tuples.OfType <MsiAssemblyNameTuple>())
            {
                assemblyNameTuples.Add(assemblyTuple.Component_ + "/" + assemblyTuple.Name, assemblyTuple);
            }

            FileInfo fileInfo = null;

            try
            {
                fileInfo = new FileInfo(file.WixFile.Source.Path);
            }
            catch (ArgumentException)
            {
                this.Messaging.Write(ErrorMessages.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
                return;
            }
            catch (PathTooLongException)
            {
                this.Messaging.Write(ErrorMessages.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
                return;
            }
            catch (NotSupportedException)
            {
                this.Messaging.Write(ErrorMessages.InvalidFileName(file.File.SourceLineNumbers, file.WixFile.Source.Path));
                return;
            }

            if (!fileInfo.Exists)
            {
                this.Messaging.Write(ErrorMessages.CannotFindFile(file.File.SourceLineNumbers, file.File.File, file.File.LongFileName, file.WixFile.Source.Path));
                return;
            }

            using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if (Int32.MaxValue < fileStream.Length)
                {
                    throw new WixException(ErrorMessages.FileTooLarge(file.File.SourceLineNumbers, file.WixFile.Source.Path));
                }

                file.File.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(file.File.SourceLineNumbers, fileInfo.FullName));
                }
                else
                {
                    throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, e.Message));
                }
            }

            // 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 != file.File.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.FileFacades.Any(r => file.File.Version.Equals(r.File.File, StringComparison.Ordinal)))
                    {
                        this.Messaging.Write(WarningMessages.DefaultVersionUsedForUnversionedFile(file.File.SourceLineNumbers, file.File.Version, file.File.File));
                    }
                }
                else
                {
                    if (null != file.File.Language)
                    {
                        this.Messaging.Write(WarningMessages.DefaultLanguageUsedForUnversionedFile(file.File.SourceLineNumbers, file.File.Language, file.File.File));
                    }

                    int[] hash;
                    try
                    {
                        Installer.GetFileHash(fileInfo.FullName, 0, out hash);
                    }
                    catch (Win32Exception e)
                    {
                        if (0x2 == e.NativeErrorCode) // ERROR_FILE_NOT_FOUND
                        {
                            throw new WixException(ErrorMessages.FileNotFound(file.File.SourceLineNumbers, fileInfo.FullName));
                        }
                        else
                        {
                            throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, fileInfo.FullName, e.Message));
                        }
                    }

                    if (null == file.Hash)
                    {
                        file.Hash = new MsiFileHashTuple(file.File.SourceLineNumbers, file.File.Id);
                        this.Section.Tuples.Add(file.Hash);
                    }

                    file.Hash.File_     = file.File.File;
                    file.Hash.Options   = 0;
                    file.Hash.HashPart1 = hash[0];
                    file.Hash.HashPart2 = hash[1];
                    file.Hash.HashPart3 = hash[2];
                    file.Hash.HashPart4 = hash[3];
                }
            }
            else // update the file row with the version and language information.
            {
                // If no version was provided by the user, use the version from the file itself.
                // This is the most common case.
                if (String.IsNullOrEmpty(file.File.Version))
                {
                    file.File.Version = version;
                }
                else if (!this.FileFacades.Any(r => file.File.Version.Equals(r.File.File, StringComparison.Ordinal))) // this looks expensive, but see explanation below.
                {
                    // 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.
                    file.File.Version = version;
                }

                if (!String.IsNullOrEmpty(file.File.Language) && String.IsNullOrEmpty(language))
                {
                    this.Messaging.Write(WarningMessages.DefaultLanguageUsedForVersionedFile(file.File.SourceLineNumbers, file.File.Language, file.File.File));
                }
                else // override the default provided by the user (usually nothing) with the actual language from the file itself.
                {
                    file.File.Language = language;
                }

                // Populate the binder variables for this file information if requested.
                if (null != this.VariableCache)
                {
                    if (!String.IsNullOrEmpty(file.File.Version))
                    {
                        var key = String.Format(CultureInfo.InvariantCulture, "fileversion.{0}", file.File.File);
                        this.VariableCache[key] = file.File.Version;
                    }

                    if (!String.IsNullOrEmpty(file.File.Language))
                    {
                        var key = String.Format(CultureInfo.InvariantCulture, "filelanguage.{0}", file.File.File);
                        this.VariableCache[key] = file.File.Language;
                    }
                }
            }

            // If this is a CLR assembly, load the assembly and get the assembly name information
            if (FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType)
            {
                bool targetNetfx1       = false;
                var  assemblyNameValues = new Dictionary <string, string>();

                Guid referenceIdentityGuid = ClrInterop.ReferenceIdentityGuid;
                var  result = ClrInterop.GetAssemblyIdentityFromFile(fileInfo.FullName, ref referenceIdentityGuid, out var referenceIdentity);
                if (0 == result && null != referenceIdentity)
                {
                    var imageRuntimeVersion = referenceIdentity.GetAttribute(null, "ImageRuntimeVersion");
                    if (null != imageRuntimeVersion)
                    {
                        targetNetfx1 = imageRuntimeVersion.StartsWith("v1", StringComparison.OrdinalIgnoreCase);
                    }

                    string culture = referenceIdentity.GetAttribute(null, "Culture") ?? "neutral";
                    assemblyNameValues.Add("Culture", culture);

                    string name = referenceIdentity.GetAttribute(null, "Name");
                    if (null != name)
                    {
                        assemblyNameValues.Add("Name", name);
                    }

                    string processorArchitecture = referenceIdentity.GetAttribute(null, "ProcessorArchitecture");
                    if (null != processorArchitecture)
                    {
                        assemblyNameValues.Add("ProcessorArchitecture", processorArchitecture);
                    }

                    string publicKeyToken = referenceIdentity.GetAttribute(null, "PublicKeyToken");
                    if (null != publicKeyToken)
                    {
                        bool publicKeyIsNeutral = (String.Equals(publicKeyToken, "neutral", StringComparison.OrdinalIgnoreCase));

                        // Managed code expects "null" instead of "neutral", and
                        // this won't be installed to the GAC since it's not signed anyway.
                        assemblyNameValues.Add("publicKeyToken", publicKeyIsNeutral ? "null" : publicKeyToken.ToUpperInvariant());
                        assemblyNameValues.Add("publicKeyTokenPreservedCase", publicKeyIsNeutral ? "null" : publicKeyToken);
                    }
                    else if (file.WixFile.File_AssemblyApplication == null)
                    {
                        throw new WixException(ErrorMessages.GacAssemblyNoStrongName(file.File.SourceLineNumbers, fileInfo.FullName, file.File.Component_));
                    }

                    string assemblyVersion = referenceIdentity.GetAttribute(null, "Version");
                    if (null != version)
                    {
                        assemblyNameValues.Add("Version", assemblyVersion);
                    }
                }
                else
                {
                    this.Messaging.Write(ErrorMessages.InvalidAssemblyFile(file.File.SourceLineNumbers, fileInfo.FullName, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", result)));
                    return;
                }

                if (assemblyNameValues.TryGetValue("name", out var value))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "name", value);
                }

                if (!String.IsNullOrEmpty(version))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "fileVersion", version);
                }

                if (assemblyNameValues.ContainsKey("version"))
                {
                    string assemblyVersion = assemblyNameValues["version"];

                    if (!targetNetfx1)
                    {
                        // There is a bug in v1 fusion that requires the assembly's "version" attribute
                        // to be equal to or longer than the "fileVersion" in length when its present;
                        // the workaround is to prepend zeroes to the last version number in the assembly
                        // version.
                        if (null != version && version.Length > assemblyVersion.Length)
                        {
                            string   padding = new string('0', version.Length - assemblyVersion.Length);
                            string[] assemblyVersionNumbers = assemblyVersion.Split('.');

                            if (assemblyVersionNumbers.Length > 0)
                            {
                                assemblyVersionNumbers[assemblyVersionNumbers.Length - 1] = String.Concat(padding, assemblyVersionNumbers[assemblyVersionNumbers.Length - 1]);
                                assemblyVersion = String.Join(".", assemblyVersionNumbers);
                            }
                        }
                    }

                    this.SetMsiAssemblyName(assemblyNameTuples, file, "version", assemblyVersion);
                }

                if (assemblyNameValues.ContainsKey("culture"))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "culture", assemblyNameValues["culture"]);
                }

                if (assemblyNameValues.ContainsKey("publicKeyToken"))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", assemblyNameValues["publicKeyToken"]);
                }

                if (!String.IsNullOrEmpty(file.WixFile.ProcessorArchitecture))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", file.WixFile.ProcessorArchitecture);
                }

                if (assemblyNameValues.ContainsKey("processorArchitecture"))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", assemblyNameValues["processorArchitecture"]);
                }

                // add the assembly name to the information cache
                if (null != this.VariableCache)
                {
                    string fileId       = file.File.File;
                    string key          = String.Concat("assemblyfullname.", fileId);
                    string assemblyName = String.Concat(assemblyNameValues["name"], ", version=", assemblyNameValues["version"], ", culture=", assemblyNameValues["culture"], ", publicKeyToken=", String.IsNullOrEmpty(assemblyNameValues["publicKeyToken"]) ? "null" : assemblyNameValues["publicKeyToken"]);
                    if (assemblyNameValues.ContainsKey("processorArchitecture"))
                    {
                        assemblyName = String.Concat(assemblyName, ", processorArchitecture=", assemblyNameValues["processorArchitecture"]);
                    }

                    this.VariableCache[key] = assemblyName;

                    // Add entries with the preserved case publicKeyToken
                    string pcAssemblyNameKey = String.Concat("assemblyfullnamepreservedcase.", fileId);
                    this.VariableCache[pcAssemblyNameKey] = (assemblyNameValues["publicKeyToken"] == assemblyNameValues["publicKeyTokenPreservedCase"]) ? assemblyName : assemblyName.Replace(assemblyNameValues["publicKeyToken"], assemblyNameValues["publicKeyTokenPreservedCase"]);

                    string pcPublicKeyTokenKey = String.Concat("assemblypublickeytokenpreservedcase.", fileId);
                    this.VariableCache[pcPublicKeyTokenKey] = assemblyNameValues["publicKeyTokenPreservedCase"];
                }
            }
            else if (FileAssemblyType.Win32Assembly == file.WixFile.AssemblyType)
            {
                // TODO: Consider passing in the this.FileFacades 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.
                FileFacade fileManifest = this.FileFacades.SingleOrDefault(r => r.File.File.Equals(file.WixFile.File_AssemblyManifest, StringComparison.Ordinal));
                if (null == fileManifest)
                {
                    this.Messaging.Write(ErrorMessages.MissingManifestForWin32Assembly(file.File.SourceLineNumbers, file.File.File, file.WixFile.File_AssemblyManifest));
                }

                string win32Type    = null;
                string win32Name    = null;
                string win32Version = null;
                string win32ProcessorArchitecture = null;
                string win32PublicKeyToken        = null;

                // loading the dom is expensive we want more performant APIs than the DOM
                // Navigator is cheaper than dom.  Perhaps there is a cheaper API still.
                try
                {
                    XPathDocument  doc = new XPathDocument(fileManifest.WixFile.Source.Path);
                    XPathNavigator nav = doc.CreateNavigator();
                    nav.MoveToRoot();

                    // this assumes a particular schema for a win32 manifest and does not
                    // provide error checking if the file does not conform to schema.
                    // The fallback case here is that nothing is added to the MsiAssemblyName
                    // table for an out of tolerance Win32 manifest.  Perhaps warnings needed.
                    if (nav.MoveToFirstChild())
                    {
                        while (nav.NodeType != XPathNodeType.Element || nav.Name != "assembly")
                        {
                            nav.MoveToNext();
                        }

                        if (nav.MoveToFirstChild())
                        {
                            bool hasNextSibling = true;
                            while (nav.NodeType != XPathNodeType.Element || nav.Name != "assemblyIdentity" && hasNextSibling)
                            {
                                hasNextSibling = nav.MoveToNext();
                            }
                            if (!hasNextSibling)
                            {
                                this.Messaging.Write(ErrorMessages.InvalidManifestContent(file.File.SourceLineNumbers, fileManifest.WixFile.Source.Path));
                                return;
                            }

                            if (nav.MoveToAttribute("type", String.Empty))
                            {
                                win32Type = nav.Value;
                                nav.MoveToParent();
                            }

                            if (nav.MoveToAttribute("name", String.Empty))
                            {
                                win32Name = nav.Value;
                                nav.MoveToParent();
                            }

                            if (nav.MoveToAttribute("version", String.Empty))
                            {
                                win32Version = nav.Value;
                                nav.MoveToParent();
                            }

                            if (nav.MoveToAttribute("processorArchitecture", String.Empty))
                            {
                                win32ProcessorArchitecture = nav.Value;
                                nav.MoveToParent();
                            }

                            if (nav.MoveToAttribute("publicKeyToken", String.Empty))
                            {
                                win32PublicKeyToken = nav.Value;
                                nav.MoveToParent();
                            }
                        }
                    }
                }
                catch (FileNotFoundException fe)
                {
                    this.Messaging.Write(ErrorMessages.FileNotFound(new SourceLineNumber(fileManifest.WixFile.Source.Path), fe.FileName, "AssemblyManifest"));
                }
                catch (XmlException xe)
                {
                    this.Messaging.Write(ErrorMessages.InvalidXml(new SourceLineNumber(fileManifest.WixFile.Source.Path), "manifest", xe.Message));
                }

                if (!String.IsNullOrEmpty(win32Name))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "name", win32Name);
                }

                if (!String.IsNullOrEmpty(win32Version))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "version", win32Version);
                }

                if (!String.IsNullOrEmpty(win32Type))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "type", win32Type);
                }

                if (!String.IsNullOrEmpty(win32ProcessorArchitecture))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "processorArchitecture", win32ProcessorArchitecture);
                }

                if (!String.IsNullOrEmpty(win32PublicKeyToken))
                {
                    this.SetMsiAssemblyName(assemblyNameTuples, file, "publicKeyToken", win32PublicKeyToken);
                }
            }
        }