У меня есть произвольный список сборок .NET.
Мне нужно программно проверить, была ли каждая DLL построена для x86 (в отличие от x64 или любого процессора). Это возможно?
У меня есть произвольный список сборок .NET.
Мне нужно программно проверить, была ли каждая DLL построена для x86 (в отличие от x64 или любого процессора). Это возможно?
Ответы:
смотреть на System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
Вы можете проверить метаданные сборки из возвращенного экземпляра AssemblyName:
Использование PowerShell :
[36] C: \> [mirror.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | Флорида Имя: Microsoft.GLEE Версия: 1.0.0.0 CultureInfo: CodeBase: файл: /// C: / projects / powershell / BuildAnalyzer / ... EscapedCodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ... Архитектура процессора: MSIL Флаги: PublicKey Хэш-алгоритм: SHA1 Совместимость с версиями: SameMachine KeyPair: FullName: Microsoft.GLEE, версия = 1.0.0.0, культура = нейт ...
Здесь ProcessorArchitecture определяет целевую платформу.
В этом примере я использую PowerShell для вызова метода.
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
как иногда текущий каталог процесса не совпадает с текущим провайдером (именно здесь я предполагаю, что DLL для вас)
// 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.
К сожалению, нет способа прочитать ProcessorArchitecture без использования GetName instance method
; используя AssemblyName constructor
, поле всегда установлено в None
.
Вы можете использовать инструмент CLI CorFlags (например, C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe), чтобы определить состояние сборки на основе ее вывода и открытия сборки как бинарный актив, вы должны быть в состоянии определить, где вам нужно искать, чтобы определить, установлен ли флаг 32BIT на 1 ( x86 ) или 0 ( любой процессор или 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
(любым ЦП) вместе с другими атрибутами.
Просто для пояснения, CorFlags.exe является частью .NET Framework SDK . У меня есть инструменты разработки на моей машине, и самый простой способ определить, является ли DLL 32-битной, это:
Откройте командную строку Visual Studio (в Windows: меню Пуск / Программы / Microsoft Visual Studio / Инструменты Visual Studio / Командная строка Visual Studio 2008)
Компакт-диск в каталог, содержащий DLL
Запустите corflags, как это:
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
В соответствии с комментариями флаги выше должны читаться следующим образом:
32BITREQ
и 32BITPREF
вместо единого 32BIT
значения.
Как насчет того, чтобы написать себе? Ядро архитектуры PE не претерпело серьезных изменений с момента ее реализации в Windows 95. Вот пример 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;
}
}
Теперь текущие константы:
0x10B - PE32 format.
0x20B - PE32+ format.
Но с помощью этого метода он учитывает возможности новых констант, просто проверяйте возвращаемость по своему усмотрению.
Попробуйте использовать CorFlagsReader из этого проекта на CodePlex . Он не имеет ссылок на другие сборки и может использоваться как есть.
[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);
}
}
Ниже приведен пакетный файл, который будет работать 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.
Еще одним способом было бы использовать dumpbin из инструментов Visual Studio на DLL и искать соответствующий вывод
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>
Более общий способ - используйте структуру файла для определения битности и типа изображения:
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
Я клонировал очень удобный инструмент, который добавляет пункт контекстного меню для сборок в проводнике Windows, чтобы показать всю доступную информацию:
Загрузить здесь: https://github.com/tebjan/AssemblyInformation/releases
Другой способ проверки целевой платформы сборки .NET - проверка сборки с помощью .NET Reflector. ...
@ # ~ # ~ €! Я только что понял, что новая версия не бесплатна! Итак, исправление: если у вас есть бесплатная версия .NET рефлектора, вы можете использовать ее для проверки целевой платформы.
cfeduke отмечает возможность вызова GetPEKind. Это потенциально интересно сделать из PowerShell.
Вот, например, код для командлета, который можно использовать: https://stackoverflow.com/a/16181743/64257
В качестве альтернативы на https://stackoverflow.com/a/4719567/64257 отмечается, что «в расширениях сообщества PowerShell есть также командлет Get-PEHeader, который можно использовать для проверки наличия исполняемых образов».
Более продвинутое приложение для этого вы можете найти здесь: 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
Альтернативой уже упомянутым инструментам является Telerik JustDecompile (бесплатный инструмент), который будет отображать информацию рядом с именем сборки: