views:

344

answers:

2

Using either Delphi 2007+ or Lazarus(Win64) I'm looking for a way to determine if a dll is compiled as x64 or x86?

+9  A: 

You should read and parse PE header.

Like this:

function Isx64(const Strm: TStream): Boolean;
const
  IMAGE_FILE_MACHINE_I386     = $014c; // Intel x86
  IMAGE_FILE_MACHINE_IA64     = $0200; // Intel Itanium Processor Family (IPF)
  IMAGE_FILE_MACHINE_AMD64    = $8664; // x64 (AMD64 or EM64T)
  // You'll unlikely encounter the things below:
  IMAGE_FILE_MACHINE_R3000_BE = $160;  // MIPS big-endian
  IMAGE_FILE_MACHINE_R3000    = $162;  // MIPS little-endian, 0x160 big-endian
  IMAGE_FILE_MACHINE_R4000    = $166;  // MIPS little-endian
  IMAGE_FILE_MACHINE_R10000   = $168;  // MIPS little-endian
  IMAGE_FILE_MACHINE_ALPHA    = $184;  // Alpha_AXP }
  IMAGE_FILE_MACHINE_POWERPC  = $1F0;  // IBM PowerPC Little-Endian
var
  Header: TImageDosHeader;
  ImageNtHeaders: TImageNtHeaders;
begin
  Strm.ReadBuffer(Header, SizeOf(Header));
  if (Header.e_magic <> IMAGE_DOS_SIGNATURE) or
     (Header._lfanew = 0) then
    raise Exception.Create('Invalid executable');
  Strm.Position := Header._lfanew;

  Strm.ReadBuffer(ImageNtHeaders, SizeOf(ImageNtHeaders));
  if ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE then
    raise Exception.Create('Invalid executable');

  Result := ImageNtHeaders.FileHeader.Machine <> IMAGE_FILE_MACHINE_I386;
end;
Alexander
Thanks for the response.Unfortunately this would required JCL to work. I have not added JCL to my Delphi 2007 but may if it looks like the only expedient solution.
TheSteven
What? This code doesn't use any JCL classes nor routines.
Alexander
Your updated version works just fine in Delphi 2007 and Delphi 2010.An elegant solution - thank you.
TheSteven
Note that these constants are in unit Windows on FPC. (at least in 2.4.0+ don't know about older ones)
Marco van de Voort
+2  A: 

You could use JclPeImage from the JCL. The following app shows how to do it.


program Isx64ImageTest;

{$APPTYPE CONSOLE}

uses
  SysUtils, JclWin32, JclPEImage;

var
  PEImage: TJclPeImage;
begin
  PEImage := TJclPeImage.Create;
  try
    //usage is "Isx64ImageTest filename"
    PEImage.FileName := ParamStr(1);
    //print the machine value as string
    WriteLn(Format('Machine value of image %s is %s',
      [PEImage.FileName, PEImage.HeaderValues[JclPeHeader_Machine]]));
    //check for a special machine value
    case PEImage.LoadedImage.FileHeader^.FileHeader.Machine of
      IMAGE_FILE_MACHINE_I386:  begin end;
      IMAGE_FILE_MACHINE_AMD64: begin end;
      else
      begin
      end;
    end;
  finally
    PEImage.Free;
  end;
end.
Uwe Schuster
If you're using JCL - there is more simpler approach - by using PeMapImgTarget function or PEImage.Target property (in your example). No need to analyze headers by yourself.
Alexander
Not using JCL yet, may eventually do so.I've been trying to mirror my Delphi2007 and Delphi2010 components because I've been planning on migrating to Delphi2010. Is JCL available for Delphi2010?
TheSteven
JCL is available for D2010.
Alexander