Ho un elenco arbitrario di assembly .NET.
Devo controllare a livello di programmazione se ogni DLL è stata creata per x86 (al contrario di x64 o qualsiasi CPU). È possibile?
Ho un elenco arbitrario di assembly .NET.
Devo controllare a livello di programmazione se ogni DLL è stata creata per x86 (al contrario di x64 o qualsiasi CPU). È possibile?
Risposte:
Guarda a System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
È possibile esaminare i metadati dell'assembly dall'istanza AssemblyName restituita:
Utilizzando PowerShell :
[36] C: \> [reflection.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | fl Nome: Microsoft.GLEE Versione: 1.0.0.0 CultureInfo: Base di codice: file: /// C: / projects / powershell / BuildAnalyzer / ... EscapedCodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ... ProcessorArchitecture: MSIL Bandiere: PublicKey Algoritmo hash: SHA1 Compatibilità versione: SameMachine KeyPair: Nome completo: Microsoft.GLEE, Versione = 1.0.0.0, Cultura = neut ...
Qui, ProcessorArchitecture identifica la piattaforma di destinazione.
Sto usando PowerShell in questo esempio per chiamare il metodo.
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
come a volte la directory corrente del processo non è la stessa del provider corrente (che è dove presumo che la DLL sia per te)
// DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.
Purtroppo, non c'è modo di leggere ProcessorArchitecture senza usare il GetName instance method
; utilizzando AssemblyName constructor
, il campo è sempre impostato su None
.
È possibile utilizzare lo strumento CLI di CorFlags (ad esempio, C: \ Programmi \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) per determinare lo stato di un assembly, in base al suo output e aprendo un assembly come risorsa binaria dovresti essere in grado di determinare dove devi cercare per determinare se il flag 32BIT è impostato su 1 ( x86 ) o 0 ( qualsiasi CPU o x64 , a seconda ):PE
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
Il post sul blog Sviluppo x64 con .NET contiene alcune informazioni su corflags
.
Ancora meglio, è possibile utilizzareModule.GetPEKind
per determinare se un assembly è PortableExecutableKinds
value PE32Plus
(64-bit), Required32Bit
(32-bit e WOW) o ILOnly
(qualsiasi CPU) insieme ad altri attributi.
Solo per chiarimenti, CorFlags.exe fa parte di .NET Framework SDK . Ho gli strumenti di sviluppo sulla mia macchina e il modo più semplice per me determinare se una DLL è solo a 32 bit è:
Apri il prompt dei comandi di Visual Studio (in Windows: menu Start / Programmi / Microsoft Visual Studio / Visual Studio Tools / Prompt dei comandi di Visual Studio 2008)
CD nella directory contenente la DLL in questione
Esegui corflags in questo modo:
corflags MyAssembly.dll
Otterrai un output simile a questo:
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
Come da commenti, i flag sopra devono essere letti come segue:
32BITREQ
e 32BITPREF
non un singolo 32BIT
valore.
Che ne dici di scrivere solo il tuo? Il nucleo dell'architettura PE non è stato seriamente modificato dalla sua implementazione in Windows 95. Ecco un esempio in 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\0\0 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;
}
}
Ora le costanti attuali sono:
0x10B - PE32 format.
0x20B - PE32+ format.
Ma con questo metodo consente le possibilità di nuove costanti, basta convalidare il ritorno come meglio credi.
Prova a utilizzare CorFlagsReader da questo progetto su CodePlex . Non ha riferimenti ad altri assiemi e può essere utilizzato così com'è.
[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);
}
}
Di seguito è riportato un file batch che verrà eseguito corflags.exe
su tutti dlls
eexes
nella directory di lavoro corrente e in tutte le sottodirectory, analizza i risultati e visualizza l'architettura di destinazione di ciascuno.
A seconda della versione di corflags.exe
che viene utilizzato, le voci in uscita sarà o includere 32BIT
, o 32BITREQ
(e 32BITPREF
). Qualunque di questi due sia incluso nell'output è l'elemento pubblicitario critico che deve essere verificato per distinguere tra Any CPU
e x86
. Se stai utilizzando una versione precedente di corflags.exe
(pre Windows SDK v8.0A), nell'output 32BIT
sarà presente solo l' elemento pubblicitario, come altri hanno indicato nelle risposte precedenti. Altrimenti 32BITREQ
e 32BITPREF
sostituirlo.
Questo presuppone corflags.exe
sia nel %PATH%
. Il modo più semplice per assicurarsi che ciò sia utilizzare a Developer Command Prompt
. In alternativa, è possibile copiarlo dalla posizione predefinita .
Se il file batch di seguito viene eseguito su un non gestito dll
o exe
, lo visualizzerà erroneamente come x86
, poiché l'output effettivo da Corflags.exe
sarà un messaggio di errore simile a:
corflags: errore CF008: il file specificato non ha un'intestazione gestita valida
@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.
Un altro modo sarebbe utilizzare dumpbin dagli strumenti di Visual Studio su DLL e cercare l'output appropriato
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
Nota: sopra o / p è per dll a 32 bit
Un'altra opzione utile con dumpbin.exe è / EXPORTS, che mostrerà la funzione esposta dalla dll
dumpbin.exe /EXPORTS <PATH OF THE DLL>
Modo più generico: utilizzare la struttura dei file per determinare il tipo di immagine e testimone:
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);
}
}
Enumerazione della modalità di compilazione
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
Codice sorgente con spiegazione su GitHub
Ho clonato uno strumento super pratico che aggiunge una voce del menu di scelta rapida per gli assiemi in Windows Explorer per mostrare tutte le informazioni disponibili:
Scarica qui: https://github.com/tebjan/AssemblyInformation/releases
Un altro modo per verificare la piattaforma di destinazione di un assembly .NET è l'ispezione dell'assembly con .NET Reflector ...
@ # ~ # € ~! Ho appena realizzato che la nuova versione non è gratuita! Quindi, correzione, se hai una versione gratuita di .NET reflector, puoi usarla per controllare la piattaforma di destinazione.
cfeduke rileva la possibilità di chiamare GetPEKind. È potenzialmente interessante farlo da PowerShell.
Ecco, ad esempio, il codice per un cmdlet che potrebbe essere utilizzato: https://stackoverflow.com/a/16181743/64257
In alternativa, su https://stackoverflow.com/a/4719567/64257 si noti che "esiste anche il cmdlet Get-PEHeader nelle estensioni della community di PowerShell che può essere utilizzato per testare immagini eseguibili".
Un'applicazione più avanzata per questo è possibile trovare qui: CodePlex - ApiChange
Esempi:
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
Un'alternativa agli strumenti già menzionati è Telerik JustDecompile (strumento gratuito) che visualizzerà le informazioni accanto al nome dell'assembly: