A console application should always be designed to do whatever it is supposed to do and then exit without asking the user to press any key. The reason for this is that console applications are often used within scripts to automate several tasks. Obviously, you don’t want one console application launched by the script to wait until the user presses any key because that would be against the whole purpose of writing that script in the first place. However, sometimes it might be useful to pause the console application right before exiting. This article will explain a way to add this support to your application elegantly without breaking support for scripting.
The easiest way but not recommended way to add a pause to your console application would be something as follows:
int main() { // <Your application code goes here> // Wait until the user presses any key. system("pause.exe"); return 0; }
What’s wrong with the implementation above?
- It will pause execution every time, right before exiting the console application; therefore, it cannot be used inside an automation script.
- pause.exe is Windows specific; the above code will only run on Windows platforms.
- A last but important reason is that you are trusting pause.exe to do exactly what you think it should do. However, some virus or prankster could have replaced pause.exe with a program that wipes out your entire hard drive.
To solve the first problem, support for a command line parameter will be added. The console application will pause only at the end when that parameter is given to it. To solve the second problem, you will implement a pause function yourself. It will run on all platforms that have a C++ compiler; this automatically solves the third problem above as well.
So, all this is implemented in the following example:
#include <conio.h> #include <iostream> using namespace std; static void pause() { cout << "Press any key to continue..." << endl; // On Windows, use _getch() starting with VC++ 2005. // On *nix, you probably can use getch(). _getch(); } int main(int argc, char* argv[]) { // Loop over all supplied parameters and see if /P or /p // was specified. // Start looping at 1 because argv[0] is the executable // name itself. for (int i=1; i<argc; ++i) { if (!strcmp(argv[i], "/p") || !strcmp(argv[i], "/P")) { // By using atexit, the pause() function will be called // automatically when the program exits. atexit(pause); break; } } // <Your application code goes here> // This example will just print something to the console cout << "This is the output of your application." << endl; return 0; }
By using atexit(pause), there is no need to call the pause function manually right before the return statement of the main function. It will be called automatically. Also, note that the atexit call will only be done when the /p or /P command line parameter is given to the console application. For example, suppose the name of the executable is ConsoleWithPause; running it without /p or /P will result in:
c:> ConsoleWithPause This is the output of your application. c:>
As you can see, it is not waiting for a key press. Running it with /p or /P will result in:
c:> ConsoleWithPause /p This is the output of your application. Press any key to continue... c:>
This console application can be used by scripts when you omit the /p argument. When running outside scripts, you can force it to wait before exiting with /p or /P.
The rest of the article is Windows specific.
When you have a console application on Windows and you launch it by double-clicking its icon in Windows Explorer, a new console will be created but will disappear at the end of the execution and you probably won’t be able to read anything from the console. However, when you run your console application by typing the command in an existing console, your application will write all its output to that console and, when finished, you will be returned to the console prompt without the console being closed. There is a trick that can be used on Windows to automatically detect whether a new console window was opened or if your application was started from inside an existing console. The trick is to find out the cursor position in your console at the very beginning of your program. If the cursor position is (0,0), it is highly likely that a new console window was spawned. The following code shows how this can be accomplished:
#include <conio.h> #include <iostream> #include <windows.h> using namespace std; static void pause() { cout << "Press any key to continue..." << endl; // On Windows, use _getch() starting with VC++ 2005. // On *nix, you probably can use getch(). _getch(); } int main() { CONSOLE_SCREEN_BUFFER_INFO csbi = {0}; HANDLE hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (GetConsoleScreenBufferInfo(hStdOutput, &csbi)) { // Check whether the cursor position is (0,0) if (csbi.dwCursorPosition.X == 0 && csbi.dwCursorPosition.Y == 0) { // By using atexit, the pause() function will be called // automatically when the program exits. atexit(pause); } } // <Your application code goes here> // This example will just print something to the console cout << "This is the output of your application." << endl; return 0; }
Note that in some rare cases, this will not work correctly. For example, when you start the ConsoleWithPause application as follows:
c:> cls & ConsoleWithPause
This command will first clear the console and then launch your application. In this case, the cursor will be at (0,0) and your application will think that a new console was spawned and will wait for a key press before exiting.