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:
program.exe
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.
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.
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.
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:
I intentionally added the optional namespaces like Winapi.ShellAPI...
in order for you to know exactly where those functions are defined.
There are 32 error codes defined, that is why the function returns True
if the result of ShellExecute
was greater than 32
.
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;
Sadly, I am still unsure about the first ShellExecute
HWND
argument, more specifically if my generic way is right, feel free to correct me!
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:
As you can see, the function loads library kernel32.dll
and function IsWow64Process
from it.
Every safety measure should be in place as for the correct result to be returned.
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.