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:
- If I'm running on a x64 or an x86 processor and
- 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?
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.
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.
You can check for the existence of and then call IsWow64Process. The linked MSDN page shows the required code.
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.
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