.NETアセンブリがx86またはx64向けにビルドされたかどうかを判断する方法は?
-
06-07-2019 - |
質問
.NETアセンブリの任意のリストがあります。
各DLLが(x64またはAny CPUとは対照的に)x86用にビルドされているかどうかをプログラムで確認する必要があります。これは可能ですか?
解決
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 :ARMプロセッサ。
- IA64 :64ビットIntel Itaniumプロセッサのみ。
- MSIL :プロセッサおよびワードごとのビットに関してニュートラル。
- X86 :64ビットプラットフォーム(WOW64)上のネイティブまたはWindows on Windows環境の32ビットIntelプロセッサ。
- なし:プロセッサとビットごとのビットの不明または未指定の組み合わせ。
この例ではPowerShellを使用してメソッドを呼び出しています。
他のヒント
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
ブログ投稿 。NETによるx64開発 には、 corflags
に関するいくつかの情報があります。
さらに良いのは、 Module.GetPEKind
を使用して、アセンブリが PortableExecutableKinds
値 PE32Plus
(64ビット)、 Required32Bit
(32ビットおよびWOW)、または ILOnly
(任意のCPU)と他の属性。
明確にするために、CorFlags.exeは .NET Framework SDK の一部です。私のマシンには開発ツールがあり、DLLが32ビットのみかどうかを判断する最も簡単な方法は次のとおりです。
-
Visual Studioコマンドプロンプトを開きます(Windowsの場合:メニュースタート/プログラム/ Microsoft Visual Studio / Visual Studioツール/ Visual Studio 2008コマンドプロンプト)
-
問題のDLLを含むディレクトリへのCD
-
次のように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
あなたはあなた自身を書いてどうですか? 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);
}
}
Belowは、現在の作業ディレクトリおよびすべてのサブディレクトリ内のすべての dll
および exes
に対して corflags.exe
を実行するバッチファイルです。 、結果を解析し、それぞれのターゲットアーキテクチャを表示します。
使用されている corflags.exe
のバージョンに応じて、出力の行項目には 32BIT
、または 32BITREQ
(および 32BITPREF
)。これら2つのうちのどちらが出力に含まれるかは、 Any CPU
と x86
を区別するためにチェックする必要がある重要な項目です。古いバージョンの corflags.exe
(Windows SDK v8.0Aより前)を使用している場合、出力には 32BIT
項目のみが表示されます。過去の回答に示されています。それ以外の場合は、 32BITREQ
および 32BITPREF
で置き換えます。
これは、 corflags.exe
が%PATH%
にあることを前提としています。これを確実にする最も簡単な方法は、開発者コマンドプロンプト
を使用することです。または、デフォルトの場所からコピーすることもできます。
以下のバッチファイルがアンマネージ 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.
もう1つの方法は、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のもう1つの便利なオプションは/ EXPORTSです。dllによって公開されている機能が表示されます
dumpbin.exe /EXPORTS <PATH OF THE DLL>
利用可能なすべての情報を表示するために、Windowsエクスプローラーでアセンブリのコンテキストメニューエントリを追加する非常に便利なツールを複製しました:
ここからダウンロード: https://github.com/tebjan/AssemblyInformation/releases
.NETアセンブリのターゲットプラットフォームを確認する別の方法は、 .NETリフレクターでアセンブリを検査することです ...
@#〜#&#8364;〜!新しいバージョンが無料ではないことに気づきました!そのため、修正版です。無料版の.NETリフレクターがあれば、それを使用してターゲットプラットフォームを確認できます。
cfedukeは、GetPEKindを呼び出す可能性を指摘しています。 PowerShellからこれを行うのは興味深い可能性があります。
たとえば、使用できるコマンドレットのコードは次のとおりです。 https://stackoverflow.com/a/16181743/ 64257
別の方法として、 https://stackoverflow.com/a/4719567/64257 には、&quot;があるまた、実行可能イメージのテストに使用できる PowerShell Community Extensions の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
より一般的な方法-ファイル構造を使用してビットネスと画像タイプを決定します:
public static CompilationMode GetCompilationMode(this FileInfo info)
{
if (!info.Exists) throw new ArgumentException([Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
quot;{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);
}
}
コンパイルモードの列挙
<*> に説明があるソースコード