Pergunta

Como posso programaticamente dizer em C # se um não gerenciado arquivo DLL é x86 ou x64?

Foi útil?

Solução

Consulte as especificações . Aqui está uma implementação básica:

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.
    // The PE header starts with "PE\0\0" =  0x50 0x45 0x00 0x00,
    // followed by a 2-byte machine type field (see the document above for the 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;
}

A enumeração MachineType é definido como:

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,
}

Eu só precisava de três destes, mas eu incluí-los todos para ser completo. Verificação final 64-bit:

// 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;
    }
}

Outras dicas

Usando um Visual Studio prompt de comando, dumpbin / headers dllname.dll funciona também. Na minha máquina o início da saída afirmou:

FILE HEADER VALUES
8664 machine (x64)
5 number of sections
47591774 time date stamp Fri Dec 07 03:50:44 2007

Mais fácil: confira a classe System.Reflection.Module. Ele inclui o método GetPEKind, que retorna 2 enumerações que descrevem o tipo de código e o alvo da CPU. Não mais hex!

(o resto deste post muito informativo foi copiado descaradamente de http :? //www.developersdex.com/vb/message.asp p = 2,924 & r = 6413567 )

Exemplo de código:

Assembly assembly = Assembly.ReflectionOnlyLoadFrom(@"<assembly Path>");
PortableExecutableKinds kinds;
ImageFileMachine imgFileMachine;
assembly.ManifestModule.GetPEKind(out kinds, out imgFileMachine);

PortableExecutableKinds pode ser usado para verificar que tipo de assembléia. isto tem 5 valores:

ILOnly: O executável contém linguagem intermediária somente Microsoft (MSIL), e é, por conseguinte, neutra com respeito a 32 bits ou 64 bits plataformas.

NotAPortableExecutableImage: O arquivo não está em executável portátil (PE) formato de arquivo.

PE32Plus:. O executável requer uma plataforma de 64 bits

Required32Bit: O executável pode ser executado em uma plataforma de 32 bits, ou na 32-bit do Windows no Windows (WOW) ambiente em uma plataforma de 64 bits.

Unmanaged32Bit:. O executável contém código não gerenciado puro

A seguir estão os links:

Método Module.GetPEKind: http://msdn.microsoft.com/en- us / library / system.reflection.module.getpekind.aspx

PortableExecutableKinds enumeração: http://msdn.microsoft.com /en-us/library/system.reflection.portableexecutablekinds(VS.80).aspx

ImageFileMachine enumeração: http://msdn.microsoft.com/en-us/ biblioteca / system.reflection.imagefilemachine.aspx

Em vez de Assembly.LoadFile, uso Assembly.ReflectionOnlyLoadFrom. Isso permitirá que você contornar as exceções "Bad Formatar Imagem".

Eu sei que tem sido um tempo desde que este foi atualizado. Eu era capaz de fugir com as exceções "Bad Formatar Imagem" por carregar o arquivo em seu próprio AppDomain.

        private static (string pkName, string imName) FindPEKind(string filename)
    {
        // some files, especially if loaded into memory
        // can cause errors. Thus, load into their own appdomain
        AppDomain tempDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
        PEWorkerClass remoteWorker =
            (PEWorkerClass)tempDomain.CreateInstanceAndUnwrap(
                typeof(PEWorkerClass).Assembly.FullName,
                typeof(PEWorkerClass).FullName);

        (string pkName, string imName) = remoteWorker.TryReflectionOnlyLoadFrom_GetManagedType(filename);

        AppDomain.Unload(tempDomain);
        return (pkName, imName);
    }

Neste ponto, eu faço o seguinte:

        public (string pkName, string imName) TryReflectionOnlyLoadFrom_GetManagedType(string fileName)
    {
        string pkName;
        string imName;
        try
        {
            Assembly assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFile: fileName);
            assembly.ManifestModule.GetPEKind(
                peKind: out PortableExecutableKinds peKind,
                machine: out ImageFileMachine imageFileMachine);

            // Any CPU builds are reported as 32bit.
            // 32bit builds will have more value for PortableExecutableKinds
            if (peKind == PortableExecutableKinds.ILOnly && imageFileMachine == ImageFileMachine.I386)
            {
                pkName = "AnyCPU";
                imName = "";
            }
            else
            {
                PortableExecutableKindsNames.TryGetValue(
                    key: peKind,
                    value: out pkName);
                if (string.IsNullOrEmpty(value: pkName))
                {
                    pkName = "*** ERROR ***";
                }

                ImageFileMachineNames.TryGetValue(
                    key: imageFileMachine,
                    value: out imName);
                if (string.IsNullOrEmpty(value: pkName))
                {
                    imName = "*** ERROR ***";
                }
            }

            return (pkName, imName);
        }
        catch (Exception ex)
        {
            return (ExceptionHelper(ex), "");
        }
    }

A execução deste contra o meu diretório Widows \ Assembly me dá zero erros com mais de 3600 arquivos processados. nota:. Eu uso um dicionário para carregar os valores a serem devolvidos

Espero que ajude. YMMV

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top