delphi 如何判断我是否在x64上运行?

brc7rcf0  于 2023-02-04  发布在  其他
关注(0)|答案(7)|浏览(228)

我刚收到一个bug报告,这个问题只会在程序运行在“64位机器”上时发生。现在, Delphi 不生成64位代码,所以理论上这不重要,但显然在这种情况下它有问题。我想我有一个变通方案,但它会破坏32位Windows上的东西,所以我需要一些方法来告诉:
1.如果我在x64或x86处理器上运行
1.如果我在Win32模拟下运行64位版本的Windows,或者在32位操作系统上运行本机Win32。
有人知道如何从我的应用程序中获得这些答案吗?

nfeuvbwi

nfeuvbwi1#

Mason,您可以使用IsWow64Process(WOW64是x86模拟器,它允许基于32位Windows的应用程序在64位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;

再见。

q9yhzks0

q9yhzks02#

我看到你的问题2(你在Win 64上运行吗?)已经得到了回答。请记住,为了让你的代码经得起未来的考验,你需要考虑到在一个(假设的)64位 Delphi 应用程序中,IsWow 64 Process也会返回FALSE。
关于您的第一个问题--您使用的是64位CPU吗--您可以检查硬件以查找相应的CPUID特性标志,如下面的代码所示。

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

其使用以下两个低级函数:

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;

编辑1:关于CPUIDavailable的注解:当然,这是在32位x86处理器(80386或更高版本)的前提下实现的,但 Delphi Win32代码在早期的机器上无法运行。CPUID指令是在80486处理器上引入的。

1bqhqjot

1bqhqjot3#

您可以检查是否存在,然后调用IsWow64Process。链接的MSDN页显示了所需的代码。

rt4zxlrg

rt4zxlrg4#

MSDN页面显示:
为了与不支持此函数的操作系统兼容,请调用GetProcAddress以检测IsWow64Process是否在Kernel32.dll中实现。如果GetProcAddress成功,则可以安全地调用此函数。否则,WOW64不存在。请注意,此技术不是检测操作系统是否为Windows 64位版本的可靠方法,因为Kernel32.当前版本的32位Windows中的dll也包含此函数。
这意味着:这是一个新函数,你必须小心地静态链接到它。

bvhaajcl

bvhaajcl5#

既然 Delphi 现在可以编译Win64,我想分享我的解决方案:

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;
at0kjp5o

at0kjp5o6#

在第一个函数的开头,您需要添加

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

aij0ehis7#

**如果sizeof(IntPtr) == 8**您是64位Windows上的64位应用程序(**编辑:**仅适用于 Delphi Prism)
否则如果IsWow64Process成功并返回true,则表示您是64位Windows上的32位应用程序
否则您使用的是32位Windows

相关问题