我需要以编程方式检查每个DLL是否针对x86(而不是x64或Any CPU)构建的。这可能吗?
#1 楼
查看System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
您可以从返回的AssemblyName实例中检查程序集元数据:
使用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...
这里,ProcessorArchitecture标识目标平台。
Amd64:基于x64架构的64位处理器。臂:ARM处理器。
IA64:仅限64位Intel Itanium处理器。
MSIL:在处理器和每字位数方面是中立的。
X86 :32位Intel处理器,在64位平台(WOW64)上本机或Windows on Windows环境中。
无:处理器和每字位数的未知或未指定组合。
我在此示例中使用PowerShell来调用该方法。
评论
原谅这个愚蠢的问题-但是,这告诉你什么是x86?
–乔治·莫尔(George Mauer)
2012年12月13日下午16:31
ProcessorArchitecture字段是一个枚举;在上面的示例中,将其设置为MSIL,表示“对于处理器和每字位数是中性”。其他值包括X86,IA64,Amd64。有关更多详细信息,请参见msdn.microsoft.com/en-us/library/…。
–布赖恩·吉莱斯皮(Brian Gillespie)
2012年12月13日19:45在
我在尝试使用PowerShell时遇到以下错误:带有“ 1”参数的调用“ GetAssemblyName”的异常:“无法加载文件或程序集'[DLLName] .dll”或其依赖项之一。系统找不到该文件指定。” (是的,我拼写正确)。
– PeterX
13-10-29在9:14
尝试使用[reflection.assemblyname] :: GetAssemblyName(“ $ {pwd} \ name.dll”),因为有时该进程的当前目录与当前提供程序的目录不同(这是我认为DLL适合您的位置)
–x0n
13-10-29在14:36
需要注意的另一个警告是,如果您是从Internet下载的,则忘记“解除阻止”该DLL。使用取消阻止文件,或右键单击/属性/从资源管理器取消阻止。如果您在当前会话中已经失败一次,则需要重新启动外壳程序以使其识别未阻止状态(对此归咎于Internet Explorer)-是的,确实如此。
–x0n
2014年1月22日20:16
#2 楼
您可以使用CorFlags CLI工具(例如C:\ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe)根据程序集的输出确定程序集的状态,并以二进制资产,您应该能够确定需要将32BIT标志设置为1(x86)还是0(任何CPU或x64,具体取决于PE
):Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
博客x64通过.NET开发具有有关
corflags
的一些信息。更好的是,您可以使用
Module.GetPEKind
来确定程序集是否为PortableExecutableKinds
值PE32Plus
(64位), Required32Bit
(32位和WOW)或ILOnly
(任何CPU)以及其他属性。评论
看到您的更新后,使用GetPEKind似乎是执行此操作的正确方法。我已将您的答案标记为答案。
–犹大·加布里埃尔·Himango
08年7月7日在5:38
检查32位程序集时,GetPEKind在64位进程中失败
– jjxtra
2010-4-19在16:25
您必须从32位进程调用GetPEKind
–Ludwo
13年2月18日在12:21
我安装了VS 2008,VS 2010,VS 2012和VS2013。我在C:\ Program Files(x86)\ Microsoft SDKs \ Windows \的子文件夹中有8个文件CorFlags.exe。我应该使用哪个?
– Kiquenet
2014年3月25日15:06
正如此答案所指出的,.NET 4.5中有32BITREQ和32BITPREF而不是32BIT标志。 PE32 / 0/0和PE32 / 0/1分别是首选32位AnyCPU和AnyCPU。
– Angularsen
2015年1月30日11:36
#3 楼
只是为了澄清起见,CorFlags.exe是.NET Framework SDK的一部分。我的机器上装有开发工具,而确定DLL是否仅是32位的最简单方法是:打开Visual Studio命令提示符(在Windows中:菜单开始/程序/ Microsoft Visual Studio / Visual Studio工具/ Visual Studio 2008命令提示符)CD到包含有问题的DLL的目录
运行像这样的标志:
corflags MyAssembly.dll
您将得到类似以下的输出:
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
根据评论,上面的标志应如下所示:
任何CPU:PE = PE32和32BIT = 0
x86:PE = PE32和32BIT = 1
64位:PE = PE32 +和32BIT = 0
评论
同时,这似乎已经改变了。现在,corflags显示32BITREQ和32BITPREF而不是单个32BIT值。
– O. R. Mapper
2015年3月10日14:11在
Microsoft .NET 4.5引入了一个新选项,即“首选32位CPU”。这是详细信息。
– RBT
17年4月10日在12:02
如今,“ Visual Studio命令提示符”被称为“ Visual Studio 2019开发人员命令提示符”。
– Uwe Keim
19-10-27在8:31
#4 楼
你自己写自己怎么样?自从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 PE0x10B - PE32 format.
0x20B - PE32+ format.
q4312078q 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;
}
}
现在,当前常量为:
q4312078q
但是使用这种方法,它可以提供新的常量,只需根据需要验证返回值即可。
评论
有趣,感谢您提供解释的代码。 Module.GetPEKind可能是最简单的路径。但这对学习很有帮助。谢谢。
–犹大·加布里埃尔·Himango
2012年3月19日17:47
非常有趣,但是当我使用任何CPU编译应用程序时,结果为0x10B。这是错误的,因为我的应用程序在x64系统上运行。还有其他标志要检查吗?
–塞缪尔
2012年7月24日在17:41
GetPEArchitecture适用于使用.net 3.5、4.0、4.5和4.5.1编译的程序集吗?无论如何,我认为Module.GetPEKind在检查32位程序集时在64位进程中失败。
– Kiquenet
2014年3月25日在20:51
#5 楼
尝试从CodePlex的此项目中使用CorFlagsReader。它没有对其他程序集的引用,可以按原样使用。评论
这是最准确和有用的答案。
–基里尔·奥森科夫(Kirill Osenkov)
13年3月25日在5:01
在撰写本文时,该链接仍然有效,但是由于CodePlex将要关闭,因此在为时已晚之前最好执行适当的操作。
– Peter Mortensen
17年6月18日在9:50
#6 楼
JetBrains的DotPeek提供了快速简便的方法来查看msil(anycpu),x86,x64#7 楼
[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);
}
}
评论
为此,我们的应用程序之一必须构建为x86,添加一个单元测试可确保构建服务器的构建库为32位,并避免发生这些错误:)
–美多
2015年5月5日9:00
#8 楼
下面是一个批处理文件,它将对当前工作目录和所有子目录中的所有corflags.exe
和dlls
运行exes
,分析结果并显示每个文件的目标体系结构。取决于
corflags.exe
的版本也就是说,输出中的订单项将包含32BIT
或32BITREQ
(和32BITPREF
)。输出中包括这两者中的哪一个是关键行项目,必须对其进行检查以区分Any CPU
和x86
。如果您使用的是旧版本的corflags.exe
(Windows SDK v8.0A之前的版本),则输出中将仅显示32BIT
订单项,正如其他人在过去的答案中指出的那样。否则,用32BITREQ
和32BITPREF
替换它。假定
corflags.exe
在%PATH%
中。确保这一点的最简单方法是使用Developer Command Prompt
。或者,您可以从默认位置复制它。如果下面的批处理文件是针对非托管
dll
或exe
运行的,则它将错误地显示为x86
,因为Corflags.exe
的实际输出将是错误的类似于以下消息:corflags:错误CF008:指定的文件没有有效的托管标头
@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.
#9 楼
另一种方法是在DLL上使用Visual Studio工具中的dumpbin并查找适当的输出。dumpbin.exe /HEADERS <your dll path>
FILE HEADER VALUE
14C machine (x86)
4 number of sections
5885AC36 time date stamp Mon Jan 23 12:39:42 2017
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
2102 characteristics
Executable
32 bit word machine
DLL
注意:以上o / p用于32位dll
dumpbin.exe的另一个有用选项是/ EXPORTS,它将向您显示dll公开的功能
dumpbin.exe /EXPORTS <PATH OF THE DLL>
#10 楼
更通用的方法-使用文件结构确定位数和图像类型: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);
}
}
编译模式枚举
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
>源代码以及GitHub上的说明
#11 楼
我已经克隆了一个超级方便的工具,该工具在Windows资源管理器中为程序集添加了一个上下文菜单项,以显示所有可用信息:下载此处:
https://github.com/tebjan / AssemblyInformation / releases
评论
“源代码(zip)”下载具有一个项目文件,该项目文件包含您计算机上文件的硬编码路径,而未包括在下载中:(
– Ben Voigt
20年7月31日在17:21
#12 楼
检查.NET程序集的目标平台的另一种方法是使用.NET Reflector检查程序集...@#〜#€〜!我刚刚意识到新版本不是免费的!因此,更正一下,如果您拥有.NET反射器的免费版本,则可以使用它来检查目标平台。
评论
使用ILSpy,这是一个基本的开源应用,其功能与Reflector相同
–二进制担忧者
2011年8月5日,11:01
#13 楼
cfeduke指出了调用GetPEKind的可能性。从PowerShell进行此操作可能很有趣。例如,以下是可使用的cmdlet的代码:https://stackoverflow.com/a/16181743/64257或者,在https://stackoverflow.com/a/4719567/64257上注意到,“ PowerShell社区扩展中还有Get-PEHeader cmdlet,可用于测试可执行映像。”
#14 楼
您可以在此处找到更高级的应用程序:CodePlex-ApiChange示例:
C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\winhlp32.exe
File Name; Type; Size; Processor; IL Only; Signed
winhlp32.exe; Unmanaged; 296960; X86
C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\HelpPane.exe
File Name; Type; Size; Processor; IL Only; Signed
HelpPane.exe; Unmanaged; 733696; Amd64
评论
如何确定可执行文件在哪个平台上编译的可能重复项?您可能还需要检查以下一项:check-if-unmanaged-dll-is-32位或64位。
在与.NET 4.5对应的更高版本的CorFlags中,“ 32BIT”被“ 32BITREQ”和“ 32BITPREF”取代。.
如何确定.NET程序集是为x86还是x64构建的?