Home > Enterprise >  How to detect whether a SPECIFIC Delphi version is currently running?
How to detect whether a SPECIFIC Delphi version is currently running?

Time:02-24

In a 32-bit VCL application on Windows 10 in Delphi 11 Alexandria, I try to detect whether a specific Delphi version is currently running. So I used the Winapi.TlHelp32.CreateToolhelp32Snapshot function to search for "bds.exe":

function ProcessExists(exeFileName: string): Boolean;
var
  ContinueLoop: Winapi.Windows.BOOL;
  FSnapshotHandle: Winapi.Windows.THandle;
  FProcessEntry32: Winapi.TlHelp32.TProcessEntry32;
begin
  FSnapshotHandle := Winapi.TlHelp32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := System.SizeOf(FProcessEntry32);
  ContinueLoop := Winapi.TlHelp32.Process32First(FSnapshotHandle, FProcessEntry32);
  Result := False;
  while Integer(ContinueLoop) <> 0 do
  begin
    if SameText(ExtractFileName(FProcessEntry32.szExeFile), ExeFileName) or SameText(FProcessEntry32.szExeFile, ExeFileName) then
    begin
      Result := True;
      CodeSite.Send('ProcessExists: FProcessEntry32.szExeFile', FProcessEntry32.szExeFile);
      BREAK;
    end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  Winapi.Windows.CloseHandle(FSnapshotHandle);
end;
...
CodeSite.Send('ProcessExists(ThisBdsExe)', ProcessExists('bds.exe'));

Unfortunately, FProcessEntry32.szExeFile returns only the FILENAME without the PATH information. So I get only the information whether Delphi is running, but NOT whether a specific Delphi version is running!

Is there any way to get the PATH information from the FProcessEntry32 structure?

Of course, I know the paths of each bds.exe that exists on my computer. But this does not work:

CodeSite.Send('ProcessExists(Delphi 11 bds.exe path)', ProcessExists('C:\Program Files (x86)\Embarcadero\Studio\22.0\bin\bds.exe'));

CodePudding user response:

The API help for PROCESSENTRY32's szExeFile entry:

szExeFile

The name of the executable file for the process. To retrieve the full path to the executable file, call the Module32First function and check the szExePath member of the MODULEENTRY32 structure that is returned. However, if the calling process is a 32-bit process, you must call the QueryFullProcessImageName function to retrieve the full path of the executable file for a 64-bit process.

So you need to make a Module32First call and currently at least BDS is a 32bit process so you don't need to use QueryFullProcessImageName even if your app is 32bit.

CodePudding user response:

GetModuleFileNameEx worked for me:

function GetPathFromPID(const PID: cardinal): string;
var
  hProcess: THandle;
  path: array[0..MAX_PATH - 1] of char;
begin
  hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
  if hProcess <> 0 then
  try
    if GetModuleFileNameEx(hProcess, 0, path, MAX_PATH) = 0 then
      RaiseLastOSError;
    result := path;
  finally
    CloseHandle(hProcess)
  end
  else
    RaiseLastOSError;
end;

function ProcessExists(exeFileName: string): Boolean;
var
  ContinueLoop: Winapi.Windows.BOOL;
  FSnapshotHandle: Winapi.Windows.THandle;
  FProcessEntry32: Winapi.TlHelp32.TProcessEntry32;
begin
  FSnapshotHandle := Winapi.TlHelp32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := System.SizeOf(FProcessEntry32);
  ContinueLoop := Winapi.TlHelp32.Process32First(FSnapshotHandle, FProcessEntry32);
  Result := False;
  var ThisExeName := ExtractFileName(exeFileName);
  while Integer(ContinueLoop) <> 0 do
  begin
    if SameText(ExtractFileName(FProcessEntry32.szExeFile), ThisExeName) or SameText(FProcessEntry32.szExeFile, ThisExeName) then
    begin
      var ThisBdsExePath := GetPathFromPID(FProcessEntry32.th32ProcessID);
      Result := SameText(exeFileName, ThisBdsExePath);
      if Result then BREAK;
    end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  Winapi.Windows.CloseHandle(FSnapshotHandle);
end;
  • Related