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

9

我刚刚收到了一个错误报告,称在“64位机器”上运行程序时才会出现问题。 现在,Delphi不生成64位代码,所以理论上这不应该有影响,但显然在这种情况下确实有影响。 我想我有一种解决方法,但这将破坏在32位Windows上的东西,因此我需要一些方式来判断:

  1. 如果我正在运行x64或x86处理器
  2. 如果我正在运行在Win32仿真或本地Win32上的64位Windows版本或32位操作系统上的本机Win32。

有人知道如何从我的应用程序中获取这些答案吗?

7个回答

21

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;

再见。


当运行应用程序具有中等或低权限时,Windows的UAC是否允许这样做? - FileVoyager
1
我回答自己的评论:是的!因为kernel32.dll是每个Delphi进程的一部分。 - FileVoyager

8

我看到你的第二个问题(你是否在Win64上运行?)已经得到了回答。请记住,为了使您的代码具有未来性,您需要考虑在Win64上运行的(假设的)64位Delphi应用程序中,IsWow64Process也将返回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 //如果CPUID.80000001h.EDX[bit29] = 1,则表示该处理器支持64位。 //但首先需要检查是否存在函数80000001h。 push ebx //由于CPUID将改变EBX,因此保存EBX push esi //我们将在内部使用ESI,因此保存ESI

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 //结果{AL/EAX}:=0{假; 这是一个32位处理器}; @Exit: pop esi //恢复ESI pop ebx //恢复EBX end;

编辑1: 关于的说明: 这当然是基于>= 32位的x86处理器(80386或更高版本),但Delphi Win32代码在早期机器上也无法运行。CPUID指令是在晚期80486处理器中引入的。


3

您可以检查并调用IsWow64Process来确定其是否存在。链接的MSDN页面显示了所需的代码。


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

0

由于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;

-1
在第一个函数的开头,您需要添加:
if SizeOf(Pointer)=8 then
  Exit(True); // Current app is 64 bit

2
问题是如何判断Windows操作系统是否为64位,而不是应用程序是否为64位。 - LU RD

-2

如果 sizeof(IntPtr) == 8,则您是在64位Windows上的64位应用程序(编辑:仅适用于Delphi Prism)

否则,如果{{link1:IsWow64Process}}成功并返回true,则您是在64位Windows上的32位应用程序

否则,您将在32位Windows上


第一部分不适用,因为Delphi无法编译64位应用程序。 - Mason Wheeler
Delphi Prism不是构建.NET应用程序到IL吗? :-) - Franci Penov
是的,但 Delphi 和 Delphi Prism 是两种不同的语言。当有人只说“Delphi”时,他们通常指的是本机版本。 - Mason Wheeler
如果我们在未来进入128位,由于它不是8个字节,你会将其检测为x86。 - Remko
@Remko,你在技术上是正确的,我的答案会失败,因为它不知道如何处理>64位操作系统。然而,它将无法检测到是否为128位应用程序,或者在128位操作系统上运行的64位WOW应用程序,或者在64位WOW模拟器上运行的32位WOW应用程序。我认为你现在很难更新我的答案以便检测在128位操作系统上运行的任何应用程序,因为没有正确的方法来检测尚不存在的东西。 - Franci Penov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接