Mason Wheeler
Mason Wheeler

Reputation: 84540

How can I tell if I'm running on x64?

I just got a bug report for an issue that only occurs when the program is running "on a 64-bit machine." Now, Delphi doesn't produce 64-bit code, so theoretically that shouldn't matter, but apparently it does in this case. I think I have a workaround, but it will break things on 32-bit Windows, so I need some way to tell:

  1. If I'm running on a x64 or an x86 processor and
  2. If I'm running under a 64-bit version of Windows under Win32 emulation or native Win32 on a 32-bit OS.

Does anyone know how I can get those answers from within my app?

Upvotes: 9

Views: 11140

Answers (7)

Daniel Marschall
Daniel Marschall

Reputation: 3879

Since Delphi can now compile Win64, I'd like to share my solution:

function WindowsBits: integer;

  function IsWow64: Boolean;
  {$IFDEF WIN64}
  begin
    // Native 64 Bit App means OS and CPU is 64 Bit, too.
    result := false;
  {$ELSE}
  type
    TIsWow64Process = function( // Type of IsWow64Process API fn
      Handle: Windows.THandle; var Res: Windows.BOOL
    ): Windows.BOOL; stdcall;
  var
    IsWow64Result: Windows.BOOL;      // Result from IsWow64Process
    IsWow64Process: TIsWow64Process;  // IsWow64Process fn reference
  begin
    // Try to load required function from kernel32
    IsWow64Process := Windows.GetProcAddress(
      Windows.GetModuleHandle('kernel32'), 'IsWow64Process'
    );
    if Assigned(IsWow64Process) then
    begin
      // Function is implemented: call it
      if not IsWow64Process(
        Windows.GetCurrentProcess, IsWow64Result
      ) then
        raise SysUtils.Exception.Create('IsWow64: bad process handle');
      // Return result of function
      Result := IsWow64Result;
    end
    else
      // Function not implemented: can't be running on Wow64
      Result := False;
  {$ENDIF}
  end;

begin
  {$IFDEF WIN64}
  result := 64;
  {$ELSE}
  if IsWow64 then
    result := 64
  else
    result := 32;
  {$ENDIF}
end;

Upvotes: 0

Anton Alisov
Anton Alisov

Reputation: 1

At the beginning of the first function you need to add

if SizeOf(Pointer)=8 then
  Exit(True); // Current app is 64 bit

Upvotes: -1

Montanto
Montanto

Reputation: 21

The MSDN page says:

For compatibility with operating systems that do not support this function, call GetProcAddress to detect whether IsWow64Process is implemented in Kernel32.dll. If GetProcAddress succeeds, it is safe to call this function. Otherwise, WOW64 is not present. Note that this technique is not a reliable way to detect whether the operating system is a 64-bit version of Windows because the Kernel32.dll in current versions of 32-bit Windows also contains this function.

Which means: this is a new function and you have to be careful statically linking to it.

Upvotes: 2

PhiS
PhiS

Reputation: 4650

I see the your question 2 (are you running on Win64?) is already answered. Just keep in mind that for your code to be future-proof, you need to consider that in a (hypothetical) 64-bit Delphi app running on Win64, IsWow64Process would also return FALSE.

As regards your first question - are you on a 64-bit CPU -, you can check the hardware for the respective CPUID feature flag, like in the code below.


function Is64BitProcessor: boolean;
begin
  Result:=false;
  if CpuidAvailable = true then Result := Has64BitFeatureFlag;
end;

which uses the following two low-level functions:


function CPUIDavailable:boolean;
asm // if EFLAGS bit 21 can be modified then CPUID is available
    pushfd              //Save Flags
          pushfd        //Copy flags to EAX
          pop eax
          mov ecx,eax   //Make another copy in ECX
          btc eax,21    //Complement bit 21
          push eax      //Copy EAX to flags
          popfd
          pushfd        //Copy flags back to EAX
          pop eax
          cmp eax,ecx   //Compare "old" flags value with potentially modified "new" value
          setne al      //Set return value
    popfd               //Restore flags
end;

function Has64BitFeatureFlag: boolean; asm //IF CPUID.80000001h.EDX[bit29]=1 THEN it's a 64bit processor. //But we first need to check whether there's a function 80000001h. push ebx //Save EBX as CPUID will modify EBX push esi //Save ESI as we'll use ESI internally

xor eax,eax             //Setting EAX = input param for CPUID to 0
cpuid                   //Call CPUID.0
                        //Returns -> EAX = max "standard" EAX input value
mov esi, eax            //Saving MaxStdInput Value

mov eax,80000000h       //Setting EAX = input param for CPUID to $80000000
cpuid                   //Call CPUID.80000000h
                        //Returns -> EAX = max "extended" EAX input value
                        //If 80000000h call is unsupported (no 64-bit processor),
                        //cpuid should return the same as in call 0
cmp eax, esi
je @No64BitProcessor    //IF EAX{MaxExtInput} = ESI{MaxStdInput} THEN goto No64BitProcessor;

cmp eax, 80000001h
jb @No64BitProcessor    //IF EAX{MaxExtInput} < $80000001 THEN goto No64BitProcessor;

mov eax,80000001h       //Call $80000001 is supported, setting EAX:=$80000001
cpuid                   //Call CPUID.80000001h
                        //Checking "AMD long mode"/"Intel EM64T" feature bit (i.e., 64bit processor)
bt edx, 29              //by checking CPUID.80000001h.EDX[bit29]
setc al                 //IF Bit29=1 then AL{Result}:=1{true; it's a 64-bit processor}
jmp @Exit               //Exit {Note that Delphi may actually recode this as POP ESI; POP EBX; RET}

@No64BitProcessor: xor eax, eax //Result{AL/EAX}:=0{false; it's a 32-bit processor}; @Exit: pop esi //Restore ESI pop ebx //Restore EBX end;

EDIT1: A note on CPUIDavailable: This is of course assuming a >= 32-bit x86 processor (80386 or later), but Delphi Win32 code won't run on earlier machines anyway. The CPUID instruction was introduced with late 80486 processors.

Upvotes: 8

Franci Penov
Franci Penov

Reputation: 75991

if sizeof(IntPtr) == 8 you're a 64-bit application on 64-bit Windows (edit: applies only to Delphi Prism)

else if IsWow64Process succeeds and returns true, you're a 32-bit application on 64-bit Windows

else you're on 32-bit Windows

Upvotes: -2

RRUZ
RRUZ

Reputation: 136391

Mason, you can use IsWow64Process (WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows)

Uses Windows;

type
  WinIsWow64 = function( Handle: THandle; var Iret: BOOL ): Windows.BOOL; stdcall;


function IAmIn64Bits: Boolean;
var
  HandleTo64BitsProcess: WinIsWow64;
  Iret                 : Windows.BOOL;
begin
  Result := False;
  HandleTo64BitsProcess := GetProcAddress(GetModuleHandle('kernel32.dll'), 'IsWow64Process');
  if Assigned(HandleTo64BitsProcess) then
  begin
    if not HandleTo64BitsProcess(GetCurrentProcess, Iret) then
    Raise Exception.Create('Invalid handle');
    Result := Iret;
  end;
end;

Bye.

Upvotes: 21

Reed Copsey
Reed Copsey

Reputation: 564403

You can check for the existence of and then call IsWow64Process. The linked MSDN page shows the required code.

Upvotes: 3

Related Questions