Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the name of the parent program that started us?

Tags:

delphi

We want a program of ours in D7 to know if it was run via a ShellExecute command from one of our apps, or directly started by the user.

Is there a reliable way for a Delphi 7 program to determine the name of the program that ran it?

We of course could have our parent program use a command line argument or other flag, but we'd prefer the above approach.

TIA

like image 765
RobertFrank Avatar asked Oct 26 '11 21:10

RobertFrank


3 Answers

There's no way to do what you want, I'm afraid. The application isn't told whether it's being run pro grammatically via ShellExecute (or CreateProcess), via a command line, a shortcut, or a double-click in Explorer.

Raymond Chen did an article a while back on this very topic, if I remember correctly; I'll see if I can find it and update my answer here.

like image 186
Ken White Avatar answered Nov 15 '22 05:11

Ken White


Based on another answer and some code on Torry.net, I came to this function to get the parent process id. It seems to return a relevant number on Windows 7, and the windows functions it uses should be available at least since Win 2000.

uses Tlhelp32;

function GetProcessInfo(ProcessId: Cardinal; out ParentProcessId: Cardinal; out ExeFileName: string): Boolean;
var
  hSnapShot: THandle;
  ProcInfo: TProcessEntry32;
begin
  hSnapShot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (hSnapShot <> THandle(-1)) then
  try
    ProcInfo.dwSize := SizeOf(ProcInfo);

    if (Process32First(hSnapshot, ProcInfo)) then
      repeat
        if ProcInfo.th32ProcessID = ProcessId then
        begin
          ExeFileName := string(ProcInfo.szExeFile);
          ParentProcessId := ProcInfo.th32ParentProcessID;
          Result := True;
          Exit;
        end;
      until not Process32Next(hSnapShot, ProcInfo);
  finally
    CloseHandle(hSnapShot);
  end;

  Result := False;
end;

procedure Test;
var
  ProcessId, ParentProcessId, Dummy: Cardinal;
  FileName: string;
begin
  ProcessId := GetCurrentProcessId();
  // Get info for current process
  if GetProcessInfo(ProcessId, ParentProcessId, FileName) then
    // Get info for parent process
    if GetProcessInfo(ParentProcessId, Dummy, FileName) then
      // Show it.
      ShowMessage(IntToStr(ParentProcessId) + FileName);
end;

A word of caution! The parent process may no longer exist. Even worse, it's ID may have been recycled, causing this function to give you a different process than you asked for.

like image 27
GolezTrol Avatar answered Nov 15 '22 05:11

GolezTrol


The simple answer is "No".

A more complex answer is "Not as easily as simply passing a command line param would be".

:)

What you need to do is identify the parent process of your process. Obtaining this is possible but not straightforward. Details of how to go about it can be obtained in this CodeProject article.

The biggest problem is that there is not strict hierarchical relationship between processes in Windows and PID (Process ID's) may be re-used. The PID you identify as your "parent" may not be your parent at all. If the parent process has subsequently terminated then it's PID may be re-used which could lead to some seemingly perplexing results ("My process was started by calc.exe? How is that possible?").

Trying to find bullet, water and idiot proof mechanisms to protect against the possible ways such a process might fail will be significantly more effort than simply devising and implementing a command line based convention between your launcher applications and the launchee by which the latter may identify the former.

A command line parameter is one such option but could be "spoofed" (if someone figures out what you are passing on the command line and for some reason could derive some value or benefit from mimicking this themselves).

Depending on how reliable and tamper proof you need the mechanism to be, this could still be enough however.

like image 37
Deltics Avatar answered Nov 15 '22 06:11

Deltics