Comment déterminer si a.NET l'assemblage a été construit pour x86 ou x64?
j'ai une liste arbitraire d'assemblages .NET.
je dois programmatiquement vérifier si chaque DLL a été construit pour x86 (par opposition à x64 ou tout CPU). Est-ce possible?
14 réponses
Regardez System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
vous pouvez examiner les métadonnées d'assemblage à partir de L'instance de retour du nom D'assemblage:
Utilisant 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...
ici, ProcessorArchitecture identifie la plate-forme cible.
J'utilise PowerShell dans cet exemple pour appeler la méthode.
vous pouvez utiliser le CorFlags 1519110920" CLI outil (par exemple, C:\Program fichiers\Microsoft SDKs\Windows\v7.0 \ Bin\CorFlags.exe) pour déterminer le statut d'un assemblage, basé sur sa sortie et l'ouverture d'un assemblage en tant qu'actif binaire, vous devriez être en mesure de déterminer où vous devez chercher à déterminer si le drapeau 32BIT est fixé à 1 ( x86 ) ou 0 ( N'importe quel CPU ou x64 , selon PE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
le billet de blog x64 développement avec .NET a quelques informations sur corflags
.
encore mieux, vous pouvez utiliser Module.GetPEKind
pour déterminer si un assemblage est PortableExecutableKinds
valeur PE32Plus
(64 bits), Required32Bit
(32 bits et WOW), ou ILOnly
(tout CPU) avec d'autres attributs.
juste pour clarifier, CorFlags.exe fait partie du .net Framework SDK . J'ai les outils de développement sur ma machine, et le moyen le plus simple pour moi de déterminer si une DLL est 32-bit seulement est de:
-
ouvrir L'invite de commande Visual Studio (dans Windows: menu Start/Programs/Microsoft Visual Studio/Visual Studio Tools/Visual Studio 2008)
-
CD à l' répertoire contenant la DLL en question
-
Exécuter corflags comme ceci:
corflags MyAssembly.dll
vous obtiendrez une sortie de ce genre:
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
selon les commentaires, les drapeaux ci-dessus doivent être lus comme suit:
- tout CPU: PE = PE32 et 32BIT = 0
- x86: PE = PE32 et 32BIT = 1
- 64 bits: PE = PE32+ et 32BIT = 0
et si tu écrivais toi-même? Le cœur de l'architecture PE n'a pas été sérieusement modifié depuis sa mise en œuvre dans Windows 95. Voici un exemple de 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"151900920""151900920" 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;
}
}
maintenant les constantes actuelles sont:
0x10B - PE32 format.
0x20B - PE32+ format.
mais avec cette méthode il permet les possibilités de nouvelles constantes, il suffit de valider le retour comme vous le souhaitez.
Essayez d'utiliser CorFlagsReader de ce projet sur CodePlex . Il ne fait pas référence à d'autres assemblages et peut être utilisé tel quel.
[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);
}
}
ci-dessous est un fichier batch qui va exécuter corflags.exe
contre tous dlls
et exes
dans le répertoire courant de travail et tous les sous-répertoires, analyser les résultats et afficher l'architecture cible de chacun.
selon la version de corflags.exe
qui est utilisée, les lignes dans la sortie sera soit 32BIT
, ou 32BITREQ
(et 32BITPREF
). Celui de ces deux est inclus dans la sortie est l'élément critique qui doit être vérifié pour faire la différence entre Any CPU
et x86
. Si vous utilisez une ancienne version de corflags.exe
(pre Windows SDK v8.0A), alors seule la ligne 32BIT
sera présente dans la sortie, comme d'autres l'ont indiqué dans des réponses antérieures. Sinon 32BITREQ
et 32BITPREF
le remplacent.
cela suppose que corflags.exe
est dans le %PATH%
. La façon la plus simple d'y parvenir est d'utiliser un Developer Command Prompt
. Vous pouvez également le copier à partir de son emplacement par défaut .
si le fichier de lot ci-dessous est exécuté contre un dll
ou exe
non géré , il s'affichera incorrectement comme x86
, puisque la sortie réelle de Corflags.exe
sera un message d'erreur similaire à:
corflags: error CF008 : le fichier spécifié n'a pas d'en-tête géré valide
@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.
une autre façon de vérifier la plate-forme cible d'un ensemble .NET consiste à inspecter l'ensemble avec un réflecteur .NET ...
@#~#€~! Je viens de réaliser que la nouvelle version n'est pas gratuit! Donc, correction, si vous avez une version gratuite de .net reflector, vous pouvez l'utiliser pour vérifier la plateforme cible.
cfeduke note la possibilité d'appeler GetPEKind. C'est potentiellement intéressant de faire ça de PowerShell.
ici, par exemple, est le code pour un cmdlet qui pourrait être utilisé: https://stackoverflow.com/a/16181743/64257
Sinon, à https://stackoverflow.com/a/4719567/64257 il est noté que "il y a aussi le PEHeader applet de commande dans le PowerShell Communauté Extensions qui peut être utilisé pour tester exécutable images."
une application plus avancée pour que vous pouvez trouver ici: CodePlex-ApiChange
exemples:
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
une autre façon serait d'utiliser dumpbin à partir des outils Visual Studio sur DLL et de chercher la sortie appropriée
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
Note: au-dessus de o / p est pour dll 32bit
une autre option utile avec dumpbin.exe is / EXPORTS, il va vous montrer la fonction exposée par la dll
dumpbin.exe /EXPORTS <PATH OF THE DLL>
j'ai cloné un outil très pratique, qui ajoute un menu contextuel pour les assemblages dans l'explorateur windows pour afficher toutes les informations disponibles:
télécharger ici: https://github.com/tebjan/AssemblyInformation/releases
voie plus générique - utiliser la structure du fichier pour déterminer le bitness et le type d'image:
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);
}
}
mode de Compilation enumeration
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
code Source avec explication à GitHub