如何确定 .NET 程序集是为 x86 还是 x64 构建的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/270531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:31:57  来源:igfitidea点击:

How can I determine if a .NET assembly was built for x86 or x64?

.netassembliesx8664-bitx86-64

提问by Judah Gabriel Himango

I've got an arbitrary list of .NET assemblies.

我有一个任意的 .NET 程序集列表。

I need to programmatically check if each DLL was built for x86 (as opposed to x64 or Any CPU). Is this possible?

我需要以编程方式检查每个 DLL 是否是为 x86(而不是 x64 或任何 CPU)构建的。这可能吗?

采纳答案by x0n

Look at System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

看着 System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

You can examine assembly metadata from the returned AssemblyName instance:

您可以从返回的 AssemblyName 实例中检查程序集元数据:

Using PowerShell:

使用PowerShell

[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | fl

Name                  : Microsoft.GLEE
Version               : 1.0.0.0
CultureInfo           :
CodeBase              : file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase       : file:///C:/projects/powershell/BuildAnalyzer/...
ProcessorArchitecture : MSIL
Flags                 : PublicKey
HashAlgorithm         : SHA1
VersionCompatibility  : SameMachine
KeyPair               :
FullName              : Microsoft.GLEE, Version=1.0.0.0, Culture=neut... 

Here, ProcessorArchitectureidentifies target platform.

在这里,ProcessorArchitecture标识目标平台。

  • Amd64: A 64-bit processor based on the x64 architecture.
  • Arm: An ARM processor.
  • IA64: A 64-bit Intel Itanium processor only.
  • MSIL: Neutral with respect to processor and bits-per-word.
  • X86: A 32-bit Intel processor, either native or in the Windows on Windows environment on a 64-bit platform (WOW64).
  • None: An unknown or unspecified combination of processor and bits-per-word.
  • Amd64:基于 x64 架构的 64 位处理器。
  • Arm:ARM 处理器。
  • IA64:仅限 64 位 Intel Itanium 处理器。
  • MSIL:在处理器和每字位方面中立。
  • X86:32 位 Intel 处理器,本机或在 64 位平台 (WOW64) 上的 Windows on Windows 环境中。
  • :处理器和每字位的未知或未指定的组合。

I'm using PowerShell in this example to call the method.

我在本示例中使用 PowerShell 来调用该方法。

回答by cfeduke

You can use the CorFlagsCLItool (for instance, C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe) to determine the status of an assembly, based on its output and opening an assembly as a binary asset you should be able to determine where you need to seek to determine if the 32BIT flag is set to 1 (x86) or 0 (Any CPUor x64, depending on PE):

您可以使用CorFlags CLI工具(例如,C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe)根据程序集的输出确定程序集的状态并将程序集作为二进制资产您应该能够确定您需要寻找的位置来确定 32BIT 标志是设置为 1 ( x86) 还是 0 (任何 CPUx64,取决于PE):

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

The blog post x64 Development with .NEThas some information about corflags.

博客文章x64 Development with .NET有一些关于corflags.

Even better, you can use Module.GetPEKindto determine whether an assembly is PortableExecutableKindsvalue PE32Plus(64-bit), Required32Bit(32-bit and WOW), or ILOnly(any CPU) along with other attributes.

更好的是,您可以使用Module.GetPEKind其他属性来确定程序集是PortableExecutableKindsPE32Plus(64 位)、Required32Bit(32 位和 WOW)还是ILOnly(任何 CPU)。

回答by JoshL

Just for clarification, CorFlags.exe is part of the .NET Framework SDK. I have the development tools on my machine, and the simplest way for me determine whether a DLL is 32-bit only is to:

为了澄清起见,CorFlags.exe 是.NET Framework SDK 的一部分。我的机器上有开发工具,对我来说,确定 DLL 是否仅为 32 位的最简单方法是:

  1. Open the Visual Studio Command Prompt (In Windows: menu Start/Programs/Microsoft Visual Studio/Visual Studio Tools/Visual Studio 2008 Command Prompt)

  2. CD to the directory containing the DLL in question

  3. Run corflags like this: corflags MyAssembly.dll

  1. 打开 Visual Studio 命令提示符(在 Windows 中:菜单开始/程序/Microsoft Visual Studio/Visual Studio 工具/Visual Studio 2008 命令提示符)

  2. CD 到包含相关 DLL 的目录

  3. 像这样运行 corflags: corflags MyAssembly.dll

You will get output something like this:

你会得到这样的输出:

Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  3.5.21022.8
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

As per comments the flags above are to be read as following:

根据评论,上述标志应阅读如下:

  • Any CPU: PE = PE32 and 32BIT = 0
  • x86: PE = PE32 and 32BIT = 1
  • 64-bit: PE = PE32+ and 32BIT = 0
  • 任何 CPU:PE = PE32 和 32BIT = 0
  • x86:PE = PE32 和 32BIT = 1
  • 64 位:PE = PE32+ 和 32BIT = 0

回答by Jason

How about you just write you own? The core of the PE architecture hasn't been seriously changed since its implementation in Windows 95. Here's a C# example:

你只写你自己的怎么样?自在 Windows 95 中实现以来,PE 体系结构的核心并没有发生重大变化。这是一个 C# 示例:

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    if (bReader.ReadUInt16() == 23117) //check the MZ signature
                    {
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                        if (bReader.ReadUInt32() == 17744) //check the PE
0x10B - PE32  format.
0x20B - PE32+ format.
[TestMethod]
public void EnsureKWLLibrariesAreAll64Bit()
{
    var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(x => x.FullName.StartsWith("YourCommonProjectName")).ToArray();
    foreach (var assembly in assemblies)
    {
        var myAssemblyName = AssemblyName.GetAssemblyName(assembly.FullName.Split(',')[0] + ".dll");
        Assert.AreEqual(ProcessorArchitecture.MSIL, myAssemblyName.ProcessorArchitecture);
    }
}
signature. { fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header, architecture = bReader.ReadUInt16(); //read the magic number of the optional header. } } } } } catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */} //if architecture returns 0, there has been an error. return architecture; } }

Now the current constants are:

现在当前的常数是:

@echo off

echo.
echo Target architecture for all exes and dlls:
echo.

REM For each exe and dll in this directory and all subdirectories...
for %%a in (.exe, .dll) do forfiles /s /m *%%a /c "cmd /c echo @relpath" > testfiles.txt

for /f %%b in (testfiles.txt) do (
    REM Dump corflags results to a text file
    corflags /nologo %%b > corflagsdeets.txt

   REM Parse the corflags results to look for key markers   
   findstr /C:"PE32+">nul .\corflagsdeets.txt && (      
      REM `PE32+` indicates x64
        echo %%~b = x64
    ) || (
      REM pre-v8 Windows SDK listed only "32BIT" line item, 
      REM newer versions list "32BITREQ" and "32BITPREF" line items
        findstr /C:"32BITREQ  : 0">nul /C:"32BIT     : 0" .\corflagsdeets.txt && (
            REM `PE32` and NOT 32bit required indicates Any CPU
            echo %%~b = Any CPU
        ) || (
            REM `PE32` and 32bit required indicates x86
            echo %%~b = x86
        )
    )

    del corflagsdeets.txt
)

del testfiles.txt
echo.

But with this method it allows for the possibilities of new constants, just validate the return as you see fit.

但是使用这种方法,它允许使用新常量的可能性,只需按照您认为合适的方式验证返回值。

回答by Ludwo

Try to use CorFlagsReader from this project at CodePlex. It has no references to other assemblies and it can be used as is.

尝试在 CodePlex使用此项目中的CorFlagsReader 。它没有对其他程序集的引用,可以按原样使用。

回答by Prabhakaran Rajagopal

DotPeek from JetBrians provides quick and easy way to see msil(anycpu), x86, x64 dotPeek

JetBrians 的 DotPeek 提供了快速简便的方法来查看 msil(anycpu)、x86、x64 点窥

回答by Morgan Mellor

public static CompilationMode GetCompilationMode(this FileInfo info)
{
    if (!info.Exists) throw new ArgumentException($"{info.FullName} does not exist");

    var intPtr = IntPtr.Zero;
    try
    {
        uint unmanagedBufferSize = 4096;
        intPtr = Marshal.AllocHGlobal((int)unmanagedBufferSize);

        using (var stream = File.Open(info.FullName, FileMode.Open, FileAccess.Read))
        {
            var bytes = new byte[unmanagedBufferSize];
            stream.Read(bytes, 0, bytes.Length);
            Marshal.Copy(bytes, 0, intPtr, bytes.Length);
        }

        //Check DOS header magic number
        if (Marshal.ReadInt16(intPtr) != 0x5a4d) return CompilationMode.Invalid;

        // This will get the address for the WinNT header  
        var ntHeaderAddressOffset = Marshal.ReadInt32(intPtr + 60);

        // Check WinNT header signature
        var signature = Marshal.ReadInt32(intPtr + ntHeaderAddressOffset);
        if (signature != 0x4550) return CompilationMode.Invalid;

        //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER
        var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24);

        var result = CompilationMode.Invalid;
        uint clrHeaderSize;
        if (magic == 0x10b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4);
            result |= CompilationMode.Bit32;
        }
        else if (magic == 0x20b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4);
            result |= CompilationMode.Bit64;
        }
        else return CompilationMode.Invalid;

        result |= clrHeaderSize != 0
            ? CompilationMode.CLR
            : CompilationMode.Native;

        return result;
    }
    finally
    {
        if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr);
    }
}

回答by Eric Lease

Below is a batch file that will run corflags.exeagainst all dllsand exesin the current working directory and all sub-directories, parse the results and display the target architecture of each.

下面是将运行一个批处理文件,corflags.exe对所有dllsexes当前工作目录及其所有子目录,解析结果,并显示每个目标架构。

Depending on the version of corflags.exethat is used, the line items in the output will either include 32BIT, or32BITREQ(and 32BITPREF). Whichever of these two is included in the output is the critical line item that must be checked to differentiate between Any CPUand x86. If you are using an older version of corflags.exe(pre Windows SDK v8.0A), then only the 32BITline item will be present in the output, as others have indicated in past answers. Otherwise 32BITREQand 32BITPREFreplace it.

根据所使用的版本,corflags.exe输出中的行项目将包括32BIT,32BITREQ(和32BITPREF)。输出中包含这两个中的任何一个是必须检查以区分Any CPU和的关键行项目x86。如果您使用的是旧版本corflags.exe(Windows SDK v8.0A 之前的版本),那么输出中只会出现32BIT行项目,正如其他人在过去的答案中所指出的那样。否则32BITREQ32BITPREF更换它。

This assumes corflags.exeis in the %PATH%. The simplest way to ensure this is to use a Developer Command Prompt. Alternatively you could copy it from it's default location.

这假设corflags.exe%PATH%. 确保这一点的最简单方法是使用Developer Command Prompt. 或者,您可以从它的默认位置复制它。

If the batch file below is run against an unmanaged dllor exe, it will incorrectly display it as x86, since the actual output from Corflags.exewill be an error message similar to:

如果下面的批处理文件是针对非托管的dll或运行的exe,它将错误地显示为x86,因为来自的实际输出Corflags.exe将是类似于以下内容的错误消息:

corflags : error CF008 : The specified file does not have a valid managed header

corflags:错误 CF008:指定的文件没有有效的托管头

[Flags]
public enum CompilationMode
{
    Invalid = 0,
    Native = 0x1,
    CLR = Native << 1,
    Bit32 = CLR << 1,
    Bit64 = Bit32 << 1
}

回答by BlackGad

More generic way - use file structure to determine bitness and image type:

更通用的方法 - 使用文件结构来确定位数和图像类型:

##代码##

Compilation mode enumeration

编译方式枚举

##代码##

Source code with explanation at GitHub

GitHub 上的源代码和解释

回答by thalm

I've cloned a super handy tool that adds a context menu entry for assemblies in the windows explorer to show all available info:

我已经克隆了一个超级方便的工具,它为 Windows 资源管理器中的程序集添加了一个上下文菜单条目,以显示所有可用信息:

Download here: https://github.com/tebjan/AssemblyInformation/releases

在这里下载:https: //github.com/tebjan/AssemblyInformation/releases

enter image description here

在此处输入图片说明