Recent

Author Topic: Detecting how an application was launched  (Read 5036 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 7120
Re: Detecting how an application was launched
« Reply #15 on: June 17, 2024, 03:13:10 pm »
Since not already mentioned, on posix-compliant systems you can use

Code: Pascal  [Select][+][-]
  1. function isatty(fd: integer = 0): integer; cdecl;

The running program (if fd is 0, i.e the file des of the output stream, as set as default) can call this to determine if it's called from a term.

Not reliable IME. There's lots of other things one has to take into account: redirected files and so on.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

BildatBoffin

  • New Member
  • *
  • Posts: 20
Re: Detecting how an application was launched
« Reply #16 on: June 18, 2024, 03:48:05 pm »
Since not already mentioned, on posix-compliant systems you can use

Code: Pascal  [Select][+][-]
  1. function isatty(fd: integer = 0): integer; cdecl;

The running program (if fd is 0, i.e the file des of the output stream, as set as default) can call this to determine if it's called from a term.

Not reliable IME. There's lots of other things one has to take into account: redirected files and so on.

MarkMLl

Yes when you fork with inherited file descriptors that does not always work.  :-X

MarkMLl

  • Hero Member
  • *****
  • Posts: 7120
Re: Detecting how an application was launched
« Reply #17 on: June 18, 2024, 04:45:34 pm »
I can't remember the details (and I'm supposed to be doing company tax stuff, so would prefer not to investigate) but a few years ago I had a cross-platform program (Windows/Solaris/Linux) that tried to handle all possibilities of being started from the desktop GUI (possibly with a parameter), from a script, or from a shell with or without a parameter and/or redireaction. I think I allowed for multiple parameters which were implicitly concatenated, and for a directory/folder being passed as the parameter.

I remember that isatty() was useful for some cases, but it's definitely not comprehensive.

I know I was looking at the "how was it started?" question more recently, but as I think I've said I can't remember the context. However even without being able to go back to that specific project I still with my position, which is that one needs to look at PPID and then be cautious because of the difference between Linux and BSD-derivatives.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #18 on: June 20, 2024, 09:29:23 pm »
I finally got to run this on a Windows machine...and it didn't work:
Code: Pascal  [Select][+][-]
  1. ProcessCount:=0;
  2.  ProcessCount:=GetConsoleProcessList(ProcessIDs,high(ProcessIDs));
Returns 0 when running from either Explorer or Command Prompt
Code: Pascal  [Select][+][-]
  1. GetConsoleWindow()
Returns 0 when running from either Explorer or Command Prompt
Code: Pascal  [Select][+][-]
  1. GetWindowThreadProcessId(GetConsoleWindow, @pid);
Returns 0 when running from either Explorer or Command Prompt

So, I went off investigating other Windows API calls and found:
Code: Pascal  [Select][+][-]
  1. GetCommandLineA
This returns the command as run from the command prompt. As it happens, when you double click on an exe in Explorer, this contains the complete path enclosed in quotes. But, when you type in the exe name in command prompt, what you type in is contained here, without quotes (unless you enter the quotes). So, this appears to work:
Code: Pascal  [Select][+][-]
  1. function IsRunFromConsole: Boolean;
  2. {$IFDEF Windows}
  3. var
  4.  cmdLine: String;
  5. {$ENDIF}
  6. {$IFDEF Linux}
  7. var
  8.  ParentProcess: String;
  9. {$ENDIF}
  10. {$IFDEF Darwin}
  11. var
  12.  path: String;
  13. {$ENDIF}
  14. begin
  15.  Result:=False;//Default, if not covered by Windows, Linux or Darwin
  16. {$IFDEF Windows}
  17.  cmdLine:=GetCommandLineA;
  18.  Result:=(cmdLine[1]<>'"')AND(cmdLine[Length(cmdLine)]<>'"');
  19. {$ENDIF}
  20. {$IFDEF Linux}
  21.  ParentProcess:=fpReadLink('/proc/'+fpGetppid.ToString+'/exe');
  22.  if ParentProcess<>'' then Result:=True else Result:=False;
  23. {$ENDIF}
  24. {$IFDEF Darwin}
  25.  path:=ParamStr(0);
  26.  if path[1]='.' then Result:=True else Result:=False;
  27. {$ENDIF}
  28. end;

However, I'm not entirely happy about either the Windows method or the macOS method. There must be another, more confident, way of determining this.

Thoughts anyone?

MarkMLl

  • Hero Member
  • *****
  • Posts: 7120
Re: Detecting how an application was launched
« Reply #19 on: June 20, 2024, 10:19:06 pm »
Apart from

Code: Pascal  [Select][+][-]
  1. {$IFDEF Linux}
  2.  ParentProcess:=fpReadLink('/proc/'+fpGetppid.ToString+'/exe');
  3.  result := ParentProcess <> ''
  4. {$ENDIF}
  5. {$IFDEF Darwin}
  6.  path:=ParamStr(0);
  7.  result := path[1] = '.' // Needs check that path is not in fact empty
  8. {$ENDIF}
  9.  

I'm a little surprised that you have to treat Linux and Mac quite so differently and disappointed that you automatically exclude other BSD derivatives (of which I believe MacOS is but one).

When I was looking at shebang handling in relation to some other thread a few days ago I came across a succinct explanation of the reason why the pid/ppid structure of Linux and BSD differs. My recollection from working with SunOS (hence Solaris) is that /proc contains similar per-process stuff to Linux, but omits a whole lot of non-process stuff which Linux belatedly tried to move into /sys. Looking at https://github.com/MarkMLl/fpclaz_build_scripts/blob/main/fpc-filter-vt I was certainly able to use Perl to get ppid, even if I parsed ps output rather than walking the /proc tree myself.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Fibonacci

  • Sr. Member
  • ****
  • Posts: 453
  • Internal Error Hunter
Re: Detecting how an application was launched
« Reply #20 on: June 20, 2024, 11:28:28 pm »
Returns 0 when running from either Explorer or Command Prompt

Is the application a console application?

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1355
    • Lebeau Software
Re: Detecting how an application was launched
« Reply #21 on: June 21, 2024, 05:09:40 am »
Just did a small test in Windows.
Created a Desktop-Link pointing to my exe, right-click on Desktop-Link, Properties, and then in Target, where the fully qualified path incl. exe-name is, i just appended a " -g" (arbitrary value, g=GUI)
It returns, that the ParamCount is >0, writeln-ing (ParamStr(1)) returns the "-g"

Another way to detect if your app is launched via a shortcut is to use GetStartupInfo() and check if the STARTUPINFO.dwFlags field contains the STARTF_TITLEISLINKNAME flag (if so, the STARTUPINFO.lpTitle field contains the full path to the shortcut file).
« Last Edit: June 21, 2024, 05:11:32 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #22 on: June 21, 2024, 08:40:40 am »
I'm a little surprised that you have to treat Linux and Mac quite so differently and disappointed that you automatically exclude other BSD derivatives (of which I believe MacOS is but one).
Me too. But the Unix solution didn't work on my Mac, which is running Sonoma, so had to find another.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #23 on: June 21, 2024, 08:42:28 am »
Is the application a console application?
It isn't defined as such. This is why I'm wondering if there was a way of seeing how one is launched. I thought of the possibility that if it were launched from Explorer/Filer then it would open a window, otherwise it would open a console.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #24 on: June 21, 2024, 07:14:06 pm »
Another way to detect if your app is launched via a shortcut is to use GetStartupInfo() and check if the STARTUPINFO.dwFlags field contains the STARTF_TITLEISLINKNAME flag (if so, the STARTUPINFO.lpTitle field contains the full path to the shortcut file).

I did see that, and I've now had a play with it. The results are as follows:
When launched direct from Explorer:
stdOutput is set to 0x0000000000010001
dwFlags is set to 0x00000401


When launched from Explorer, via shortcut:
stdOutput is set to 0x0000000000010001
dwFlags is set to 0x00000C01


and, finally, when launched from command prompt:
stdOutput is set to 0xFFFFFFFFFFFFFFFF
dwFlags is set to 0x00000000


From what I can see, dwFlags is:
0x00000001 : STARTF_USESHOWWINDOW - look at wShowWindow
0x00000400 : could be STARTF_USESTDHANDLES, as this affects stdOutput - but the spec says this is 0x100.
0x00000800 : STARTF_TITLEISLINKNAME


So, we now have:
Code: Pascal  [Select][+][-]
  1. function IsRunFromConsole: Boolean;
  2. {$IFDEF Windows}
  3. var
  4.  StartUp: StartUpInfoA;
  5. {$ENDIF}
  6. {$IFDEF Linux}
  7. var
  8.  ParentProcess: String;
  9. {$ENDIF}
  10. {$IFDEF Darwin}
  11. var
  12.  path: String;
  13. {$ENDIF}
  14. begin
  15.  Result:=False;//Default, if not covered by Windows, Linux or Darwin
  16. {$IFDEF Windows}
  17.  GetStartupInfo(StartUp);
  18.  Result:=not(((StartUp.dwFlags AND 1)=1)AND((Startup.dwFlags AND$400)=$400));
  19. {$ENDIF}
  20. {$IFDEF Linux}
  21.  ParentProcess:=fpReadLink('/proc/'+fpGetppid.ToString+'/exe');
  22.  Result:=ParentProcess<>'';
  23. {$ENDIF}
  24. {$IFDEF Darwin}
  25.  path:=ParamStr(0);
  26.  Result:=path[1]='.';
  27. {$ENDIF}
  28. end;

Which seems more reliable way for Windows.
« Last Edit: June 21, 2024, 07:33:40 pm by geraldholdsworth »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1355
    • Lebeau Software
Re: Detecting how an application was launched
« Reply #25 on: June 21, 2024, 11:26:45 pm »
0x00000400 : could be STARTF_USESTDHANDLES, as this affects stdOutput - but the spec says this is 0x100.

Unfortunately, that is an incorrect assumption. 0x400 is an undocumented flag that is used to specify the target monitor which the new process should display its UI on.  According to Undocumented CreateProcess:

Quote
Specify which monitor a process should start on

The next undocumented tip uses another unknown STARTUPINFO flag. This flag has the value 0x400, and I have given it the name STARTF_MONITOR.

When this flag is specified in the dwFlags member, the STARTUPINFO's hStdOutput member is used to specify a handle to a monitor, on which to start the new process. This monitor handle can be obtained by any of the multiple-monitor display functions (i.e. EnumDisplayMonitors, MonitorFromPoint, MonitorFromWindow etc).

...

There are certain restrictions which should be noted here. You may be asking yourself why the above example works, when you know full well that the hStdOutput member should be used for a standard-output pipe. The answer to this question is simple - when the undocumented STARTF_MONITOR flag is
specified, the STARTF_USESTDHANDLES flag is ignored. This means that these two flags cannot be used together, and the hStdInput, hStdOutput and hStdError handles act differently to how they are described in the documentation.

...

Note that the ShellExecuteEx API call makes use of this CreateProcess feature in order to implement it's own monitor settings.
« Last Edit: June 21, 2024, 11:34:26 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #26 on: June 22, 2024, 10:58:16 am »
Unfortunately, that is an incorrect assumption. 0x400 is an undocumented flag that is used to specify the target monitor which the new process should display its UI on.  According to Undocumented CreateProcess:
Ah...thank you. However, as the flag is set means it is starting on a monitor (as the application is set as a GUI initially), just which monitor depends on hStdOutput (which was 0x10001 when I tried it). But, if the application is configured as a console application, then I guess this won't be set?
Need some more playing with, me thinks.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #27 on: June 22, 2024, 12:45:14 pm »
OK, I've had a wee play with StartUpInfo again, and here are the results:
GUI appGUI appGUI appConsole appConsole appConsole app
VariableExplorerCMDShortcutExplorerCMDShortcut
dwFlags0x000004010x000000000x00000C010x000000010x000000000x00000801
wShowWindow0x00010x00010x00010x00010x00010x0001
hStdOutput0x00000000000100010xFFFFFFFFFFFFFFFF0x00000000000100010xFFFFFFFFFFFFFFFF0xFFFFFFFFFFFFFFFF0xFFFFFFFFFFFFFFFF

Notes
  • All tests done on Windows 10 via Remote Desktop.
  • Ran as a shortcut from Explorer, via command prompt, and pinned to the Taskbar - results were the same.
  • wShowWindow can be changed by changing if the application starts up as Normal, Minimised (0x0007), or Maximised (0x0003).

So, in conclusion, looks like we can use dwFlags bit 0 to test for whether the app started from Explorer or Command Prompt.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7120
Re: Detecting how an application was launched
« Reply #28 on: June 22, 2024, 01:53:58 pm »
  • All tests done on Windows 10 via Remote Desktop.

I'd advise you to check locally as well. I'm reminded of all the old WindowStation stuff.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

geraldholdsworth

  • Full Member
  • ***
  • Posts: 214
Re: Detecting how an application was launched
« Reply #29 on: June 22, 2024, 03:55:33 pm »
I'd advise you to check locally as well. I'm reminded of all the old WindowStation stuff.
No difference to the results.

 

TinyPortal © 2005-2018