简体   繁体   中英

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

Situation

I intend to have both 32-bit and 64-bit versions of my Delphi (XE6) GUI application bundled within a Zip archive.

Note: In this question we suppose, the user extracted the whole archive, ie did not run the executable file directly from an archive manager.

So, let's suppose we have extracted the archive and have two files:

  1. program.exe

  2. program64.exe

To be crystal clear, the naming convention is that the 32-bit version does not have anything else than program name in its name, and the 64-bit version has the very same program name with the 64 suffix.

Intention

If the user runs the 32-bit version on a 64-bit Windows machine, I want it to detect it, and close itself and run the 64-bit version instead.

Note

In my own answer I will document all of my findings during the time I use the code, feel free to add better answer or alternative, and if it really makes some contribution, I will upvote for sure. And maybe more importantly, please do comment on specific sections you find wrong.

Launching other executable

First, we need a function capable of launching other executable file, my very generic example follows, you can use it for launching almost any other executable depending on your demands:

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;

Notes:

  1. I intentionally added the optional namespaces like Winapi.ShellAPI... in order for you to know exactly where those functions are defined.

  2. There are 32 error codes defined, that is why the function returns True if the result of ShellExecute was greater than 32 .

  3. I defined function DoubleQuoteStr , because if there are some spaces in the path, the system would otherwise look for the file in each space delimited and therefore wrong path. It's a very simple function, and it is completely optional, it is just optimization. This, also generic, function follows:

     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. Sadly, I am still unsure about the first ShellExecute HWND argument, more specifically if my generic way is right, feel free to correct me!


Detecting 64-bit system

Second, we need a function capable of detecting 64-bit system, more specifically, if the executable is running under 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;

Notes:

  1. As you can see, the function loads library kernel32.dll and function IsWow64Process from it.

  2. Every safety measure should be in place as for the correct result to be returned.


Running the program

Finally, we need to adjust our dpr file.

To the variables section, add:

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

Enclose your main begin - end section into another begin - end .

And add something like this at the beginning:

{$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}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM