How can I tell whether my console program was launched from Explorer or from a command prompt?


So you have a console program. This console program could be run by typing its name at the command prompt, or it could be run by the user double-clicking it from Explorer. And you want to know which case you're in.

This is another case of digging into the question to find the problem. In this case, the problem is "Well, if I'm run directly from Explorer, then when my program exits, the console is destroyed with it, and the user can't see the output. In that case, I want to prompt the user to hit Enter before the program exits."

Okay, so what you really want to know is not whether you were run from Explorer. (After all, you would have this problem if the program were run from Task Manager or some other program launcher.) What you really want to know is whether the console will continue to exist after your program exits.

For that, you can use Get­Console­Process­List.

If your process is the only one attached to the console, then the console will be destroyed when your process exits. If there are other processes attached to the console, then the console will continue to exist (because your program won't be the last one).

#include <windows.h>
#include <stdio.h>

int __cdecl wmain()
{
    printf("this process = %d\n", GetCurrentProcessId());
    DWORD count = GetConsoleProcessList(nullptr, 0);
    if (count == 1) {
      printf("I'm the last one!\n");
      Sleep(2000);
    } else {
      printf("I'm not the last one!\n");
    }
    return 0;
}

We care only how many processes are in the console process list; we don't care what they are. After getting the count, we either declare that we're the last one (and pause so you can see the message), or we say that we aren't (and exit immediately).

This is accurate as far as it goes: It tells you whether the console will be destroyed when the process exits. What it doesn't tell you is whether the other processes in the process list will also exit when you exit. For example, if somebody does

start cmd /c scratch.exe

then the program will correctly report that it's not the last one, but what it doesn't know is that the cmd.exe is going to exit as soon as the scratch.exe program exits. There's not much you can do to detect this, because that information is internal to whatever other process launched your program.

Comments (22)
  1. I suppose "real" solutions might include create a double-clickable file batch that included "pause" and/or a command-line-typable /nopause switch.

    1. cheong00 says:

      Or a context menu command that reads something like this?
      %SystemRoot%\System32\cmd.exe /k "%1"&pause

      1. Neil says:

        If you're going to use /k then you hardly need the pause as CMD.EXE will prompt once the command finishes.

  2. Kevin says:

    At some point, you have to abdicate responsibility. If the end user wants to shoot themself in the foot by pulling cmd.exe in where it doesn't belong, let them.

  3. Ben Voigt says:

    And then there's redirection. And a whole bunch more combinations which I worked out, leading to this question: http://stackoverflow.com/q/4028353/103167

  4. BZ says:

    While the intention here is good, most console apps (on any system) don't bother with it on any system (not just in Windows) because there are so many scenarios where you don't want to pause (redirection, pipe, etc). That said, I wish Explorer were a bit smarter and did this for you like Visual Studio does. Then again, the same issues come into play for Explorer too.

    1. Joey says:

      @BZ: Visual Studio only does this when you launch without debugging (Ctrl+F5). And contrary to Explorer, Visual Studio knows the type of application (GUI or Console) it's launching.

    2. Ken in NH says:

      Yes, the same issues come into play for Explorer also. If Explorer behaved liked VS does, then someone would complain that then they paste a line into Start->Run expecting the output to be a file containing the redirected results, they get a zombie console window. Or network admins: "My login scripts litter the screen with a bunch of zombie console windows; how do I get rid of them". I believe the correct answer is the current behavior, last program on the console decides whether to turn out the lights or not.

  5. Killer{R} says:

    Your program may spawn another own copy, specifying some information in command line about itself and exit. And that another copy should wait for exit its parent and then check if it last or not and do pause as needed. Sure this doesn't cover some edge cases, for example if parent tracks process tree using jobs or stupid process list polling, but I guess this should fix cmd /c.

  6. Yuri Khan says:

    At my job, we give candidates a pre-interview homework that involves writing a console program. I deduct points if it includes any kind of attempting to pause before exiting.

    1. cheong00 says:

      Why? I think it shouldn't matter unless your projects involves writting console applications.

      1. Yuri Khan says:

        Code that pauses before exiting (a) is non-portable, (b) breaks non-interactive use, (c) is unnecessarily complicated, or (d) suffers from any combination of the above.

        Programmers who write code that pauses before exiting a console program will probably struggle in an environment which involves the use of console programs, including but not limited to compilers, linkers, build systems, version control systems and in-house data manipulation tools.

        1. And do you specify any of those as requirements when you set the task?

          1. smf says:

            Why would you need to? It's just a random way of eradicating people from the process, anyone who happens to make it through will have to decide whether they like having a passive aggressive boss.

          2. Yuri Khan says:

            The purpose of the test task is not to see how a given candidate solves a well-defined ideal spherical exercise in vacuum. It is to see how they react to vague underspecified requirements that are prevalent in the real world.

        2. Yukkuri says:

          {{Citation needed}}

  7. I recall that there used to be a way to tell WINDOWS to keep console windows open after the app completed... I'd used this on many occasions, back before things like PowerShell... now I can't find the option (was pretty sure it used to be in properties of the exe or shortcut or something), maybe it's been removed.

    1. Joshua says:

      You can't find the option because it only exists for MS-DOS programs not Win32 console programs. I remember it well.

    2. It was a setting available for PIF-based shortcuts. It wasn't carried over into the newer LNK format.

    3. Darran Rowe says:

      It is still possible, but in a more convoluted way now.
      C:\Users\xxx>cmd /?
      Starts a new instance of the Windows command interpreter

      CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
      [[/S] [/C | /K] string]

      /C Carries out the command specified by string and then terminates
      /K Carries out the command specified by string but remains

      So in order to do it these days, after you create the link to the console program, change the target so that it becomes cmd /k ""

      1. Darran Rowe says:

        Meh, the comments on this blog seems like they just remove stuff surrounded by less than and greater than symbols, assuming that they are html. The problem is, I normally use those as indicators of it being user input or variable depending on the input.
        Well, lets try that again with square brackets.
        cmd /k "[old contents of the target text box]"

      2. Possible, sure... but to me, the bigger question is how the PIF implementation works... and how the approaches discussed in article would work (or not)

Comments are closed.

Skip to main content