Delphi: 如何判断一个应用程序在 Win32 / Win64 下是否 运行 并在 64 位上自动启动 64 位版本?

Delphi: How to determine if an application is running under Win32 / Win64 and launch the 64-bit version automatically if on 64-bit?

情况

我打算将我的 Delphi (XE6) GUI 应用程序的 32 位和 64 位版本捆绑在一个 Zip 存档中。

注意:在这个问题中,我们假设用户提取了整个存档,即没有 运行 直接从存档管理器中提取可执行文件。

所以,假设我们已经提取了存档并有两个文件:

  1. program.exe

  2. program64.exe

为了crystal明确,命名约定是 32 位版本的名称中除了程序名称外没有任何其他内容,而 64 位版本的程序名称与64 后缀.

意图

如果用户 运行 在 64 位 Windows 机器上使用 32 位版本,我希望它检测到它,然后自行关闭并 运行 64-位版本。

备注

在我自己的回答中,我会记录我在使用代码期间的所有发现,请随意添加更好的答案或替代方案,如果它真的有所贡献,我肯定会投票。也许更重要的是,请对您发现错误的特定部分发表评论。

正在启动其他可执行文件

首先,我们需要一个能够启动其他可执行文件的函数,下面是我非常通用的示例,您可以根据需要使用它来启动几乎任何其他可执行文件:

function LaunchExecutableFile(const ExecutableFilePath, Parameters: string; const ShowCmd: Integer): Boolean;
begin
  Result := Winapi.ShellAPI.ShellExecute(Application.MainFormHandle, 'open', PChar(StringFunctions.DoubleQuoteStr(ExecutableFilePath)), PChar(Parameters), nil, ShowCmd) > 32;
end;

备注:

  1. 我特意添加了可选名称space,例如Winapi.ShellAPI...,以便您准确了解这些函数的定义位置。

  2. 定义了 32 个错误代码,这就是为什么函数 returns True 如果 ShellExecute 的结果大于 32

  3. 我定义了函数DoubleQuoteStr,因为如果路径中有一些space,否则系统会在每个space分隔中寻找文件因此错误的道路。这是一个非常简单的功能,而且是完全可选的,只是优化而已。这个也是通用的,函数如下:

    function DoubleQuoteStr(S: string): string;
    begin
      if (S = '') or (S = '"')
        then S := '""'
        else begin
          if S[1] <> '"' then S := '"' + S;
          if S[System.Length(S)] <> '"' then S := S + '"';
        end;
      Result := S;
    end;
    
  4. 可悲的是,我仍然不确定第一个 ShellExecute HWND 参数,更具体地说,如果我的通用方法是正确的,请随时纠正我!


检测64位系统

其次,我们需要一个能够检测64位系统的函数,更具体地说,如果可执行文件在WOW64下是运行。

function IsWow64Process: Boolean;

type
  TIsWow64Process = function(AHandle: DWORD; var AIsWow64: BOOL): BOOL; stdcall;

var
  hIsWow64Process: TIsWow64Process;
  hKernel32: DWORD;
  IsWow64: BOOL;

begin
  Result := False;

  hKernel32 := Winapi.Windows.LoadLibrary('kernel32.dll');
  if hKernel32 = 0 then Exit;

  try
    @hIsWow64Process := Winapi.Windows.GetProcAddress(hKernel32, 'IsWow64Process');
    if not System.Assigned(hIsWow64Process) then Exit;

    IsWow64 := False;
    if hIsWow64Process(Winapi.Windows.GetCurrentProcess, IsWow64) then
      Result := IsWow64;

  finally
    Winapi.Windows.FreeLibrary(hKernel32);
  end;
end;

备注:

  1. 如您所见,该函数从中加载库 kernel32.dll 和函数 IsWow64Process

  2. 为了返回正确的结果,应采取一切安全措施。


运行 程序

最后,我们需要调整 dpr 文件。

在变量部分,添加:

var
{$IFNDEF WIN64}
  App64: string;
{$ENDIF}

将您的主要 begin - end 部分放入另一个 begin - end.

并在开头添加如下内容:

{$IFNDEF WIN64}

  App64 := System.SysUtils.ChangeFileExt(Application.ExeName, '64.exe');

  if not (ProcessFunctions.IsWow64Process and System.SysUtils.FileExists(App64) and
          ProcessFunctions.LaunchExecutableFile(App64, '', SW_SHOWNORMAL)) then

{$ENDIF}