Distinguish if a program is launched by clicking on the icon by typing its name in the console or from a batch file

The program I am writing is a simple console application that takes parameters, calculates and then returns data.

I ask about this because I'm trying to implement a smart "press enter to exit" message that will only start when the console program is called by clicking on its icon in Explorer. Without this, the result is that the program only blinks to separate the second, but if the program is launched from the context of an already open console, then the same becomes annoying. A similar situation occurs when a program is launched inside a bat or cmd file, and then pausing at the end is also undesirable, since bat files have a "pause" command that should do this.


So, we have 2 modes:

  • the program says "press enter to exit" when it starts:
    • direct click in the conductor
    • clicking on a shortcut
  • Just exit when:
    • his name is entered in the console
    • it is launched from the bat / cmd file
    • it starts from another console application
+4
source share
4 answers

Using the Windows API:

You can use the GetConsoleProcessList API function (available only in Windows XP / 2003 and later only ). It returns a list of processes connected to the current console. When your program starts in "no console" mode, your program is the only process connected to the current console. When your program starts from another process that already has a console, more than one process will be connected to the current console.

In this case, we do not need a list of process identifiers returned by the function, we only care about the returned counter.

Sample program (I used Visual C ++ with the console application template):

 #include "stdafx.h" #include <iostream> #include <Windows.h> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { DWORD procIDs[2]; DWORD maxCount = 2; DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount); cout << "Number of processes listed: " << result << endl; if (result == 1) { system("pause"); } return 0; } 

We only need to specify up to 2 processes, because we only need 1 or more than 1 .


Using the Windows APIs present in Windows 2000:

GetConsoleWindow returns the handle of the console window associated with the current process (if any). GetWindowThreadProcessId can tell you which process created the window. And finally, GetCurrentProcessId tells you the identifier of the current process. You can draw some useful conclusions based on this information:

 #include "stdafx.h" #include <iostream> #include <Windows.h> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { HWND consoleWindow = GetConsoleWindow(); if (consoleWindow != NULL) { DWORD windowCreatorProcessId; GetWindowThreadProcessId(consoleWindow, &windowCreatorProcessId); if (windowCreatorProcessId == GetCurrentProcessId()) { cout << "Console window was created by this process." << endl; system("pause"); } else cout << "Console window was not created by this process." << endl; } else cout << "No console window is associated with this process." << endl; return 0; } 

This method seems a little less accurate than the first, but I think in practice it should work equally well.

+5
source

The simplest solution I can think of is to require the first parameter to be a flag on whether the program should pause at the end. If the parameter is absent, that is, it was launched through the explorer, and the user was not able to pass it, then he must pause.

 //Pseudo-code!! int main(int argc, char** argv) { //... if(argv[1] == SHOULD_PAUSE) system("pause"); return 0; } 
+2
source

There is an easy way to do this, and, of course, in a more complicated way. A more complicated way may be more fun in the end, but there are probably more problems than it costs.

In a simple way, add a command line argument to the program, --pause-on-exit or something like that. Pass an additional argument that calls it from a batch file or launch icon. Of course, you could rather check the environment variable for a similar effect.

For a more complex (and automatic) way, you can probably try to figure out who is the parent process of your application. You may have to go further down the chain than your closest parent, and this may not work in all cases. I would go for a command line argument.

0
source

While developing my comment, instead of trying to talk about how the program was executed (which I don’t know, even maybe I wouldn’t have expected any differences / differences there at all), I would implement the same functionality either in one of two ways:

  • Add an additional argument to the program, which will either pause it at the end before terminating or not. i.e. You may have something like -w so that it waits, or -w so that it does not wait, and by default, do not wait (or vice versa). You can add arguments using shortcuts.

  • Add a timer at the end of the program so that you wait a few seconds long enough for the user to read the input, so that the program does not wait indefinitely when used in a batch.

0
source

Source: https://habr.com/ru/post/1387652/


All Articles