Mam dowolną listę zestawów .NET.
Muszę programowo sprawdzić, czy każda biblioteka DLL została zbudowana dla x86 (w przeciwieństwie do x64 lub dowolnego procesora). czy to możliwe?
Mam dowolną listę zestawów .NET.
Muszę programowo sprawdzić, czy każda biblioteka DLL została zbudowana dla x86 (w przeciwieństwie do x64 lub dowolnego procesora). czy to możliwe?
Odpowiedzi:
Patrzeć na System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
Możesz sprawdzić metadane zestawu z zwróconej instancji AssemblyName:
Za pomocą programu PowerShell :
[36] C: \> [reflection.assemblyname] :: GetAssemblyName („$ {pwd} \ Microsoft.GLEE.dll”) | fl Nazwa: Microsoft.GLEE Wersja: 1.0.0.0 CultureInfo: CodeBase: plik: /// C: / projects / powershell / BuildAnalyzer / ... EscapedCodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ... ProcesorArchitektura: MSIL Flagi: PublicKey Algorytm Hash: SHA1 VersionCompatibility: SameMachine KeyPair: Pełna nazwa: Microsoft.GLEE, wersja = 1.0.0.0, kultura = neut ...
Tutaj ProcessorArchitecture identyfikuje platformę docelową.
Korzystam z programu PowerShell w tym przykładzie do wywołania metody.
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
ponieważ czasami bieżący katalog procesu nie jest taki sam jak bieżący dostawca (w którym zakładam, że biblioteka DLL jest dla Ciebie)
// 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.
Niestety nie ma możliwości odczytania architektury procesora bez użycia GetName instance method
; przy użyciu AssemblyName constructor
pole jest zawsze ustawione na None
.
Możesz użyć narzędzia CorFlags CLI (na przykład C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe), aby określić status zestawu na podstawie jego danych wyjściowych i otwarcia zestawu jako binarny zasób, powinieneś być w stanie określić, gdzie musisz szukać, czy flaga 32BIT jest ustawiona na 1 ( x86 ) lub 0 ( dowolny procesor lub x64 , w zależności od PE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
W poście na blogu x64 Development with .NET znajduje się kilka informacji na temat corflags
.
Co więcej, możesz użyć,Module.GetPEKind
aby określić, czy zestaw jest PortableExecutableKinds
wartością PE32Plus
(64-bit), Required32Bit
(32-bit i WOW) lub ILOnly
(dowolny procesor) wraz z innymi atrybutami.
Dla wyjaśnienia, CorFlags.exe jest częścią zestawu .NET Framework SDK . Mam narzędzia programistyczne na moim komputerze, a najprostszym sposobem na określenie, czy biblioteka DLL jest 32-bitowa, jest:
Otwórz wiersz polecenia programu Visual Studio (w systemie Windows: menu Start / Programy / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Wiersz polecenia)
CD do katalogu zawierającego daną bibliotekę DLL
Uruchom corflags w następujący sposób:
corflags MyAssembly.dll
Otrzymasz coś takiego:
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
Zgodnie z komentarzami powyższe flagi należy rozumieć następująco:
32BITREQ
i 32BITPREF
zamiast pojedynczej 32BIT
wartości.
Co powiesz na napisanie własnego? Rdzeń architektury PE nie został poważnie zmieniony od czasu jego implementacji w Windows 95. Oto przykład 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;
}
}
Teraz obecne stałe to:
0x10B - PE32 format.
0x20B - PE32+ format.
Ale dzięki tej metodzie pozwala ona na możliwości nowych stałych, wystarczy zweryfikować zwrot według własnego uznania.
Spróbuj użyć CorFlagsReader z tego projektu w CodePlex . Nie ma odniesień do innych zestawów i może być używany w takiej postaci, w jakiej jest.
[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);
}
}
Poniżej znajduje się plik wsadowy, który będzie działał corflags.exe
dla wszystkich dlls
oraz exes
w bieżącym katalogu roboczym i wszystkich podkatalogach, analizował wyniki i wyświetlał architekturę docelową każdego z nich.
W zależności od wersji corflags.exe
, która jest używana, gdy pozycje w wyjścia albo będzie zawierać 32BIT
, lub 32BITREQ
(i 32BITPREF
). Którykolwiek z tych dwóch elementów jest uwzględniony w danych wyjściowych, jest to krytyczny element zamówienia, który należy sprawdzić, aby odróżnić od Any CPU
i x86
. Jeśli używasz starszej wersji corflags.exe
(wcześniejszej wersji Windows SDK 8.0A), tylko wynik 32BIT
będzie obecny na wyjściu, jak wskazali inni w poprzednich odpowiedziach. W przeciwnym razie 32BITREQ
i 32BITPREF
wymień go.
Zakłada się, że corflags.exe
jest w %PATH%
. Najprostszym sposobem zapewnienia tego jest użycie Developer Command Prompt
. Możesz też skopiować go z domyślnej lokalizacji .
Jeśli plik wsadowy poniżej jest uruchamiany z niezarządzanym dll
lub exe
, niepoprawnie wyświetli go jako x86
, ponieważ rzeczywiste wyjście z Corflags.exe
będzie komunikatem o błędzie podobnym do:
corflags: error CF008: Podany plik nie ma prawidłowego zarządzanego nagłówka
@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.
Jeszcze jednym sposobem byłoby użycie śmietnika z narzędzi Visual Studio na DLL i poszukiwanie odpowiedniego wyjścia
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
Uwaga: powyżej o / p jest dll dla 32-bitów
Jeszcze jedną przydatną opcją z dumpbin.exe jest / EXPORTS, pokaże ci funkcję ujawnioną przez dll
dumpbin.exe /EXPORTS <PATH OF THE DLL>
Bardziej ogólny sposób - użyj struktury pliku, aby określić bitowość i typ obrazu:
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);
}
}
Wyliczanie trybu kompilacji
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
Kod źródłowy z wyjaśnieniem na GitHub
Sklonowałem bardzo przydatne narzędzie, które dodaje pozycję menu kontekstowego dla zestawów w Eksploratorze Windows, aby wyświetlić wszystkie dostępne informacje:
Pobierz tutaj: https://github.com/tebjan/AssemblyInformation/releases
Innym sposobem sprawdzenia platformy docelowej zestawu .NET jest sprawdzenie zestawu za pomocą .NET Reflector ...
@ # ~ # € ~! Właśnie zdałem sobie sprawę, że nowa wersja nie jest darmowa! Tak więc, jeśli masz darmową wersję odbłyśnika .NET, możesz go użyć do sprawdzenia platformy docelowej.
cfeduke zauważa możliwość wywołania GetPEKind. Potencjalnie interesujące jest to zrobić z PowerShell.
Oto na przykład kod polecenia cmdlet, którego można użyć: https://stackoverflow.com/a/16181743/64257
Alternatywnie na https://stackoverflow.com/a/4719567/64257 można zauważyć, że „w rozszerzeniach społeczności PowerShell znajduje się również polecenie cmdlet Get-PEHeader, które można wykorzystać do testowania obrazów wykonywalnych”.
Bardziej zaawansowaną aplikację do tego można znaleźć tutaj: CodePlex - ApiChange
Przykłady:
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
Alternatywą dla już wspomnianych narzędzi jest Telerik JustDecompile (darmowe narzędzie), które wyświetla informacje obok nazwy zestawu: