2

別のプログラムをロードして使用するために、ユーザー提供のdllをコピーする必要があるC#プログラムがあります。64ビットマシンで実行されているプログラムの場合、ユーザーは32ビットdllを渡すことを許可されるべきではなく、間違ったdllを提供したことをユーザーに通知する必要があります。では、どうすればdllのアーキテクチャを見つけることができますか?

同様の質問がいくつか見られ、DUMPBINとCorflags.exeについて言及されましたが、サンプルコードがないので、これらのプログラムはどこにあり、どのように使用すればよいですか?

4

3 に答える 3

5

コード例

C#これは、必要なアーキテクチャを含むアーキテクチャを検出できるコンソールアプリケーションの完全なコードですdll

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MachineType type = GetDllMachineType("path/to/MyAssembly.dll");

            if (type.Equals(MachineType.IMAGE_FILE_MACHINE_I386)) 
            {
                Console.WriteLine("Dll architecture: x86/32bit");
            }
            else if (type.Equals(MachineType.IMAGE_FILE_MACHINE_IA64)) 
            {
                Console.WriteLine("Dll architecture: x64/64bit");
            }

            Console.ReadKey();
        }

        public static MachineType GetDllMachineType(string dllPath)
        {
            //see http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
            //offset to PE header is always at 0x3C
            //PE header starts with "PE\0\0" =  0x50 0x45 0x00 0x00
            //followed by 2-byte machine type field (see document above for enum)
            FileStream fs = new FileStream(dllPath, FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            fs.Seek(0x3c, SeekOrigin.Begin);
            Int32 peOffset = br.ReadInt32();
            fs.Seek(peOffset, SeekOrigin.Begin);
            UInt32 peHead = br.ReadUInt32();
            if (peHead != 0x00004550) // "PE\0\0", little-endian
                throw new Exception("Can't find PE header");
            MachineType machineType = (MachineType)br.ReadUInt16();
            br.Close();
            fs.Close();
            return machineType;
        }

        public enum MachineType : ushort
        {
            IMAGE_FILE_MACHINE_UNKNOWN = 0x0,
            IMAGE_FILE_MACHINE_AM33 = 0x1d3,
            IMAGE_FILE_MACHINE_AMD64 = 0x8664,
            IMAGE_FILE_MACHINE_ARM = 0x1c0,
            IMAGE_FILE_MACHINE_EBC = 0xebc,
            IMAGE_FILE_MACHINE_I386 = 0x14c,
            IMAGE_FILE_MACHINE_IA64 = 0x200,
            IMAGE_FILE_MACHINE_M32R = 0x9041,
            IMAGE_FILE_MACHINE_MIPS16 = 0x266,
            IMAGE_FILE_MACHINE_MIPSFPU = 0x366,
            IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,
            IMAGE_FILE_MACHINE_POWERPC = 0x1f0,
            IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,
            IMAGE_FILE_MACHINE_R4000 = 0x166,
            IMAGE_FILE_MACHINE_SH3 = 0x1a2,
            IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,
            IMAGE_FILE_MACHINE_SH4 = 0x1a6,
            IMAGE_FILE_MACHINE_SH5 = 0x1a8,
            IMAGE_FILE_MACHINE_THUMB = 0x1c2,
            IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169,
        }

        // returns true if the dll is 64-bit, false if 32-bit, and null if unknown
        public static bool? UnmanagedDllIs64Bit(string dllPath)
        {
            switch (GetDllMachineType(dllPath))
            {
                case MachineType.IMAGE_FILE_MACHINE_AMD64:
                case MachineType.IMAGE_FILE_MACHINE_IA64:
                    return true;
                case MachineType.IMAGE_FILE_MACHINE_I386:
                    return false;
                default:
                    return null;
            }
        }
    }
}

Corflagsの使用...

dllあなたはこれについて書きました、そして、ちょうど知っているために、これはあなたがあなたのアセンブリ( )に関するいくつかの情報を得るのを助けるでしょう、しかしこれはそうではありませんC#Visual Studioこれは、コンソールで使用できるツールです。

Visual Studioコンソールを開いて、次のコマンドを使用するだけです。

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>corflags C:/path/to/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 : 24
ILONLY : 0
32BIT : 0
Signed : 1

次に、に焦点を当てPE:PE32ます。これにより、アセンブリアーキテクチャが説明されます。

だから、これによると...

  • AnyCPUは、-> PE:PE32-> 32BIT:0を意味します

  • x86は->PE:PE32-> 32BIT:1を意味します

  • x64は、-> PE:PE32 +-> 32BIT:0を意味します

のアーキテクチャMyAssembly.dll32bit


アイディア...

さて、これをすべて単純化したい場合C#は、引数で上記のコマンドを使用してバックグラウンドプロセスを作成し、の出力を出力PE:XXしてアセンブリアーキテクチャを取得し、その値に従ってアプリケーションに何を伝えるかを考えます。やること。


私はちょうどいくつかの研究をしました、これが役立つことを願っています:-)

于 2012-10-26T00:56:17.883 に答える
3

しばらく前に、ビルド環境を変更せずに、ビルドで64ビット混合モードの単体テストを実行したいと考えていました。リフレクションエミットを使用してプロキシアセンブリを作成するツールを作成しました。これは、アセンブリが64ビットかどうかを検出するために作成したユーティリティクラスです。これは、corflagsによって制御されるフラグとは異なります

名前空間MstestRunner.TestProxyGenerator{システムを使用; System.Globalizationを使用します。System.IOを使用します。System.Reflectionを使用します。

/// <summary>
/// TODO: Update summary.
/// </summary>
public static class AssemblyUtility
{
    /// <summary>
    /// The value 'PE\0\0'
    /// </summary>
    private const uint PeHeaderValue = 0x4550;

    /// <summary>
    /// Image file value found at start of PE header that indicates assembly is 64bit.
    /// </summary>
    private const ushort ImageFileMachineAmd64 = 0x8664;

    /// <summary>
    /// The offset to PIMAGE_DOS_HEADER->e_lfanew
    /// </summary>
    private const int DosHeaderLfaNewOffset = 0x3c;

    /// <summary>
    /// Checks to see if the module is a 64 bit
    /// </summary>
    /// <param name="path">The path to the assembly.</param>
    /// <returns>
    /// True if is 64bit
    /// </returns>
    public static bool Is64BitImage(string path)
    {
        return ReadImageMachineType(path) == MachineType.ImageFileMachineAMD64;
    }

    /// <summary>
    /// Reads the machine type from the pe header.
    /// </summary>
    /// <param name="path">The path to the image.</param>
    /// <returns>The assembly machinetype.</returns>
    public static MachineType ReadImageMachineType(string path)
    {
        // The memory layout varies depending on 32/64 bit.  The portions of the PE header we are reading should be the same though regardless.
        byte[] buffer = new byte[4];
        using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            // skip to PIMAGE_DOS_HEADER->e_lfanew of dos header.
            fileStream.Seek(DosHeaderLfaNewOffset, SeekOrigin.Begin);

            // read and jump to offset in PIMAGE_DOS_HEADER->e_lfanew.  This is start of PIMAGE_NT_HEADERS
            fileStream.Read(buffer, 0, 4);
            fileStream.Seek(BitConverter.ToUInt32(buffer, 0), SeekOrigin.Begin);

            // Validate PE\0\0 header.
            fileStream.Read(buffer, 0, 4);
            if (BitConverter.ToUInt32(buffer, 0) != PeHeaderValue)
            {
                throw new TestRunnerException(string.Format(CultureInfo.InvariantCulture, "The specified assembly '{0}' does not appear to be valid.", path));
            }

            // Read the PIMAGE_FILE_HEADER->Machine value. 
            fileStream.Read(buffer, 0, 2);
            return (MachineType)BitConverter.ToUInt16(buffer, 0);
        }
    }

    /// <summary>
    /// Safely loads the assembly.
    /// </summary>
    /// <param name="path">The path to the assembly to load.</param>
    /// <returns>The loaded assembly</returns>
    public static Assembly SafeLoadAssembly(string path)
    {
        try
        {
            return Assembly.Load(path);
        }
        catch (ArgumentNullException)
        {
        }
        catch (FileNotFoundException)
        {
        }
        catch (FileLoadException)
        {
        }
        catch (BadImageFormatException)
        {
        }

        return null;
    }
}

}

于 2012-10-26T00:28:06.627 に答える
0

imageloadでdllをロードしてみてください

http://msdn.microsoft.com/en-us/library/ms680209(v=vs.85).aspx

もちろん、この関数が失敗した場合は、アンロードするか最後のエラーを取得するので、出力を調べて、このdllがc#アプリケーションと同じアーキテクチャであるかどうかを判断できます。

于 2012-10-26T00:25:15.847 に答える