Ejemplo n.º 1
0
        private int NgenRun(AssemblyDetails assembly, NgenAction action)
        {
            _outputMessages.Clear();
            var arguments = string.Empty;

            switch (action)
            {
            case NgenAction.Install:
                arguments = "install";
                break;

            case NgenAction.Uninstall:
                arguments = "uninstall";
                break;

            case NgenAction.Update:
                arguments = "update";
                break;

            case NgenAction.Display:
                arguments = "display";
                break;
            }
            if (action == NgenAction.Install || action == NgenAction.Uninstall || action == NgenAction.Display)
            {
                arguments += " \"" + assembly.AssemblyFile + "\" /nologo";
            }
            else
            {
                arguments += " /nologo";
            }
            //string frameworkPath;
            string frameworkDictKey = assembly.FrameworkVersion + (assembly.CPUVersion == CPUVersion.x64 ? "_64" : "_32");
            string frameworkPath;

            lock (locker)
            {
                if (!FrameworkDict.TryGetValue(frameworkDictKey, out frameworkPath))
                {
                    frameworkPath = GetFrameworkDirectory(assembly.CPUVersion == CPUVersion.x64);
                    FrameworkDict.Add(frameworkDictKey, frameworkPath);
                }
            }
            var nGenPath = frameworkPath + assembly.FrameworkVersion + "\\Ngen.exe";

            if (!File.Exists(nGenPath))
            {
                throw new FileNotFoundException(".NET Framework " + assembly.FrameworkVersion + (assembly.CPUVersion == CPUVersion.x64 ? " (x64)" : string.Empty) + " seems to be missing.");
            }
            return(RunWithRedirect(nGenPath, arguments));
        }
Ejemplo n.º 2
0
        private void CheckFiles(IEnumerable <string> files)
        {
            var startIndex = FileList.Count;

            foreach (var file in files)
            {
                if (Status == AppStatus.Stopping)
                {
                    return;
                }
                if (FileList.Any(item => file.ToLower() == item.AssemblyDetails.AssemblyFile.ToLower()))
                {
                    continue;
                }
                var assembly = AssemblyDetails.FromFile(file);
                if (assembly == null)
                {
                    continue;
                }
                FileList.Add(new NgenFileItem(assembly, NgenFileStatus.Unknown));
            }

            var processedFiles = 0;

            Parallel.For(startIndex, FileList.Count, i =>
            {
                var file = FileList[i];
                if (Status == AppStatus.Stopping)
                {
                    return;
                }
                file.Status = NgenFileStatus.InProgress;
                var ngen    = new NgenProcess(file.AssemblyDetails);
                file.Status = ngen.Check() ? NgenFileStatus.Installed : NgenFileStatus.Deinstalled;

                lock (Locker)
                {
                    processedFiles++;
                    OnProgressChanged(processedFiles, FileList.Count);
                }
            });
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Get the AssemblyDetails of a .NET 2.0+ assembly.
        /// </summary>
        /// <param name="file">The file to get the AssemblyDetails of.</param>
        /// <returns>An AssemblyDetails object for .NET 2.0+ assemblies. Null otherwise.</returns>
        public static AssemblyDetails FromFile(string file)
        {
            var assembInfo = new AssemblyDetails {
                AssemblyFile = file
            };

            using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
            {
                using (var reader = new BinaryReader(fileStream))
                {
                    var bytes = reader.ReadBytes(2);

                    // Verify file starts with "MZ" signature.
                    if ((bytes[0] != 0x4d) || (bytes[1] != 0x5a))
                    {
                        // Not a PE file.
                        return(null);
                    }

                    // Partion II, 25.2.1

                    // OFFSET_TO_PE_HEADER_OFFSET = 0x3c
                    fileStream.Seek(0x3c, SeekOrigin.Begin);

                    // read the offset to the PE Header
                    var offset = reader.ReadUInt32();

                    // go to the beginning of the PE Header
                    fileStream.Seek(offset, SeekOrigin.Begin);

                    bytes = reader.ReadBytes(4);

                    // Verify PE header starts with 'PE\0\0'.
                    if ((bytes[0] != 0x50) || (bytes[1] != 0x45) || (bytes[2] != 0) || (bytes[3] != 0))
                    {
                        // Not a PE file.
                        return(null);
                    }

                    // It's a PE file, verify that it has the right "machine" code.
                    // Partion II, 25.2.2
                    //
                    var machineCode = reader.ReadUInt16();

                    // IMAGE_FILE_MACHINE_AMD64 (aka x64) = 0x8664
                    // IMAGE_FILE_MACHINE_I386 (aka x86) = 0x14c
                    if (!(machineCode == 0x014c || machineCode == 0x8664))
                    {
                        // Invalid or unrecognized PE file of some kind.
                        return(null);
                    }

                    // Locate the PE_OPTIONAL_HEADER

                    // The PE_FILE_HEADER is 20bytes long we already
                    // read the 2 byte machine code (hence 18byte seek)
                    fileStream.Seek(18, SeekOrigin.Current);

                    var magic = reader.ReadUInt16();

                    switch (magic)
                    {
                    case 0x10b:     // PE32

                        // set to AnyCPU for now - we'll check later if image is x86 specific
                        assembInfo.CPUVersion = CPUVersion.AnyCPU;

                        break;

                    case 0x20b:     // PE32+ (aka x64)
                        assembInfo.CPUVersion = CPUVersion.x64;
                        break;

                    default:     // unknown assembly type
                        return(null);
                    }

                    // Read the SectionAlignment & FileAlignment for
                    // conversion from RVA to file address
                    fileStream.Seek(30, SeekOrigin.Current);
                    var sectionAlignment = reader.ReadUInt32();
                    var fileAlignment    = reader.ReadUInt32();

                    // go to 'NumberOfRvaAndSizes' in the PE Header
                    // at 92/108 from start of PE Header for PE32/PE32+
                    fileStream.Seek(magic == 0x10b ? 52 : 68, SeekOrigin.Current);

                    // verify that the number of data directories is 0x10.

                    var numDataDirs = reader.ReadUInt32(); // Partition II, 25.2.3.2
                    if (numDataDirs != 0x10)               // Partition II, 25.2.3.2
                    {
                        // Invalid or unrecognized PE file of some kind.
                        return(null);
                    }

                    // Go to the CLR Runtime Header
                    // at 208/224 from start of PE Header for PE32/PE32+
                    fileStream.Seek(112, SeekOrigin.Current);
                    // Check for the existence of a non-null CLI header.
                    // If found, this is an assembly of some kind, otherwise
                    // it's a native PE file of one kind or another.
                    var rvaCliHeader = reader.ReadUInt32(); // Partition II, 25.2.3.3, CLI Header (rva)
                    // uint cliHeaderSize = UIntFromBytes(pPEOptionalHeader + 212); // Partition II, 25.2.3.3, CLI Header (size)

                    if (rvaCliHeader == 0)
                    {
                        // Not an assembly.
                        return(null);
                    }

                    // Partition II, 25.3.3 (CLI Header)

                    // Go to the beginning of the CLI header (RVA -> file address)

                    /*
                     * -> Converting from Relative Virtual Address to File Address:
                     *
                     * FA = RVA - sectionAlignment + fileAlignment
                     *
                     * The section alignment in memory is sectionAlignment (usually 0x2000),
                     * and since the RVA for the CLR header is 2008, on subtracting 2000 from
                     * 2008, the difference comes to 8. Thus, the CLR header is placed 8 bytes
                     * away from the start of the section.
                     *
                     * A file on disk has the alignment of fileAlignment (usually 512 bytes).
                     * Therefore, the first section would start at position 512 from the start
                     * of the file. As the CLR is 8 bytes away from the section start, 8 is added
                     * to 512, (section start for a file on disk), thereby arriving at a value of 520.
                     * The next 72 bytes (0x48) are picked up from this position, since they
                     * constitute the CLR header, and they are loaded at location 0x4002008.
                     *
                     */

                    // Also, skip the CLI header size = 4 bytes
                    fileStream.Seek((rvaCliHeader - sectionAlignment + fileAlignment) + 4, SeekOrigin.Begin);

                    var majorVersion = reader.ReadUInt16();
                    var minorVersion = reader.ReadUInt16();

                    // 2.5 means the file is a .NET Framework 2.0+ assembly
                    if (!(majorVersion == 2 && minorVersion == 5))
                    {
                        return(null);
                    }

                    // RVA for the MetaData (we'll read the metadata later)
                    var rvaMetaData = reader.ReadUInt32();
                    fileStream.Seek(4, SeekOrigin.Current); // skip the size

                    // Partition II, 25.3.3.1

                    // read the CLI flags
                    var cliFlags = reader.ReadUInt32();

                    // Detect if compiled with Platform Target of "x86"
                    // COMIMAGE_FLAGS_32BITREQUIRED = 0x2;
                    if (assembInfo.CPUVersion == CPUVersion.AnyCPU && (cliFlags & 0x2) == 0x2)
                    {
                        assembInfo.CPUVersion = CPUVersion.x86;
                    }

                    // Detect if the assembly is built with a strong name
                    // CLI_FLAG_STRONG_NAME_SIGNED = 0x8;
                    assembInfo.StrongName = ((cliFlags & 0x8) == 0x8);
                    fileStream.Seek((rvaMetaData - sectionAlignment + fileAlignment) + 12, SeekOrigin.Begin);

                    // Read the framework version required (meta data - Partition II, 24.2.1 - pg 200)

                    // read the version string length
                    var versionLen = reader.ReadInt32();
                    var versionStr = reader.ReadChars(versionLen);

                    assembInfo.FrameworkVersion = new string(versionStr).Trim('\0');
                }
            }
            return(assembInfo);
        }
Ejemplo n.º 4
0
 public NgenProcess(AssemblyDetails assembly)
 {
     Assembly        = assembly;
     _outputMessages = new List <string>();
 }
Ejemplo n.º 5
0
 public NgenFileItem(AssemblyDetails assemblyDetails, NgenFileStatus status)
 {
     AssemblyDetails = assemblyDetails;
     Status          = status;
     AssemblyFile    = Path.GetFileName(assemblyDetails.AssemblyFile);
 }