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

2019-02-09 04:41发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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



回答4:

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.



回答5:

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



标签: delphi 64bit