Can a Win32 console application detect if it has been run from the explorer or not?

Viewed 6889

I have to create a console application which needs certain parameters. If they are missing or wrong I print out an error message.

Now the problem: If someone starts the program from the explorer by double-clicking the console window disappears immediately. (But the application is not entirely useless from the explorer, you could drag files onto it and it would work)

I could always wait for a keypress, but I don't want that if the user did start it from the command line.

Is there some way to distinguish between these situations?

6 Answers

See http://support.microsoft.com/kb/99115, "INFO: Preventing the Console Window from Disappearing".

The idea is to use GetConsoleScreenBufferInfo to determine that the cursor has not moved from the initial 0,0 position.

Code sample from @tomlogic, based on the referenced Knowledge Base article:

// call in main() before printing to stdout
// returns TRUE if program is in its own console (cursor at 0,0) or
// FALSE if it was launched from an existing console.
// See http://support.microsoft.com/kb/99115
#include <stdio.h>
#include <windows.h>
int separate_console( void)
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;

    if (!GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE), &csbi))
    {
        printf( "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
        return FALSE;
    }

    // if cursor position is (0,0) then we were launched in a separate console
    return ((!csbi.dwCursorPosition.X) && (!csbi.dwCursorPosition.Y));
}

I've found a much better solution using GetConsoleProcessList to get the attached process count to the current console. If this process is the only one attached it will be closed when the process exists.

I found it in a post https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922 But it had a bug (at least in windows 10) since the documentation forbids invoking this function with null.

My solution was:

DWORD procId;
DWORD count = GetConsoleProcessList(&procId, 1);
if (count < 2) ...

I believe cmd.exe sets the CMDCMDLINE and CMDEXTVERSION environemntal variables when it starts. So if these are set your program was most probably started from a shell.

This isn't foolproof but it's something.

It's also possible to determine your parent PID in a few convoluted and possibly unreliable ways, or so I gather. You may want to look into that.

Here is the excellent answer from @DanielBenSassoon adapted for C#. Tested in Visual Studio 2019 and Windows 10.

// Gets a list of the process IDs attached to this console
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint GetConsoleProcessList(uint[] processList, uint processCount);

public static bool IsFinalProcess()
{
    // See: https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
    uint[] procIDs = new uint[64];
    uint processCount = GetConsoleProcessList(procIDs, 64);
    return (processCount < 2);
}

This approach allows you to distinguish between four scenarios:

  • Debugging from the IDE (F5) [process count = 1]
  • Running from the IDE, but not debugging (Ctrl + F5) [process count = 2]
  • Double-clicking in Explorer [process count = 1]
  • Running from a command-prompt window [process count = 2]

When IsFinalProcess is true, you can use Console.ReadKey(false); to prevent the console window from disappearing after your application exits.

Related