Pause Before Exiting a Console Application

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.



About the Author

Marc Gregoire

Marc graduated from the Catholic University Leuven, Belgium, with a degree in "Burgerlijk ingenieur in de computer wetenschappen" (equivalent to Master of Science in Engineering in Computer Science) in 2003. In 2004 he got the cum laude degree of Master In Artificial Intelligence at the same university. In 2005 he started working for a big software consultancy company. His main expertise is C/C++ and specifically Microsoft VC++ and the MFC framework. Next to C/C++, he also likes C# and uses PHP for creating webpages. Besides his main interest for Windows development, he also has experience in developing C++ programs running 24x7 on Linux platforms and in developing critical 2G,3G software running on Solaris for big telecom operators.

Comments

  • Finally a good approach.

    Posted by TheCPUWizard on 02/19/2009 07:20am

    It is refreshing to see a solid approach to this issue. Far to many people take the "hard coded" approach which renders their programs totally unusable in many environments.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hurricane Sandy was one of the most destructive natural disasters that the United States has ever experienced. Read this success story to learn how Datto protected its partners and their customers with proactive business continuity planning, heroic employee efforts, and the right mix of technology and support. With storm surges over 12 feet, winds that exceeded 90 mph, and a diameter spanning more than 900 miles, Sandy resulted in power outages to approximately 7.5 million people, and caused an estimated $50 …

  • Ever-increasing workloads and the challenge of containing costs leave companies conflicted by the need for increased processing capacity while limiting physical expansion. Migration to HP's new generation of increased-density rack-and-blade servers can address growing demands for compute capacity while reducing costly sprawl. Sponsored by: HP and Intel® Xeon® processors Intel, the Intel logo, and Xeon Inside are trademarks of Intel Corporation in the U.S. and/or other countries. HP is the sponsor …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds