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
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) ...
EDIT: I've been using this .bat/.cmd wrapper successfully for a couple of years now:
@ECHO OFF
REM Determine if script was executed from an interactive shell
(echo %CMDCMDLINE% | find /i "%~0" >NUL 2>&1) && (set IS_INTERACTIVE=false) || (set IS_INTERACTIVE=true)
<call console application here>
REM Wait for keystroke
if "%IS_INTERACTIVE%" == "false" (
echo.
echo Hit any key to close.
pause >NUL 2>&1
)
The advantage here is that this will work for all console applications, be it your own or someone else's (for which you might not have sources you could modify). The downside is, well, that you have a separate wrapper.
My original answer back in 2014 was this:
This works like a charm:
@echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" goto nonconsole
:console
<do something>
goto exit
:nonconsole
<do something>
pause
:exit
Copied from this thread. I also tried evaluating %cmdcmdline% myself, however there's an issue regarding quote characters ("), which prevents something like if "%cmdcmdline%" == "%ComSpec%" goto [target] from working.
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.
GetConsoleTitle()
I've seen code which performs
if (!GetConsoleTitle(NULL, 0) && GetLastError() == ERROR_SUCCESS) {
// Console
} else {
// GUI
}
BUT... I've found that AttachConsole() is more helpful
In C++ (off the top of my head, and I'm no C++ programmer)
if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
// GUI
} else {
// Console, and you have a handle to the console that already exists.
}
Is more effective. Additionally, if you find yourself in a GUI environment and would like to stay there as long as you can, but later find something catastrophic has happened that could really use a dump to a console window (you can't be arsed writing an edit box window to lot it to or attach to the NT System log and throw up a MessageBox()
) well then you can AllocConsole()
later on in the process, when GUI methods have failed.
How about waiting for a keystroke when you display the error message, and not other times?
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));
}