<< Return to Main Index

< Return to Class Index

class CGXLongOperation

When executing large commands which take a long time, it is good practice in Windows programming to notify the user about the progress of the operation and to give the user the option to abort and even rollback the operation.

The CGXLongOperation class implements a mechanism exactly for this purpose and goes even one step further. It allows you to implement the mechanism in any method where it might be needed and ensures that, if the operation can be executed in a short time, no further overhead is added which could slow down the execution speed. CGXLongOperation will start its mechanism delayed, that is, only when the operation runs for a specific number of ticks.

CGXLongOperation maintains an operation level. Every time you create a CGXLongOperation object in your code, the operation level will be increased. If the destructor for the object is called, the operation level will be decreased. This makes it possible to nest operations.

The following example gives some basic steps showing how you can use CGXLongOperation in your code:

void operation1()
{
   // At first, create a CGXLongOperation object
   CGXLongOperation theOp;

   // Assign a status text. This text will be displayed only
   // if the operation takes longer than a specific amount of
   // ticks.
   theOp.SetStatusText("Operation1...", FALSE);

   // In many operations you have a loop. In this loop, you
   // should call NeedMessages frequently. NeedMessages will
   // return TRUE if the operation runs for a specific amount
   // of ticks. Furthermore, you could add TRY/CATCH statements.
   // They make it easy to cleanup when the user wants to abort
   // the operation.
   TRY
   {                             
      BOOL bAbort = FALSE;

       while (bStatementsToProcess)
       {
            // Statements to be processed
            // ...

         // check, if user pressed ESC to cancel
         if (theOp.NeedMessages())
         {
            // if theOp.NeedMessage is TRUE the first time,
            // theOp.DoMessages will display a wait cursor
            theOp.SetPercentDone(nPercentDone);
            theOp.DoMessages(bAbort);

            if (bAbort)
               AfxThrowUserException();
         }
      }

      // operation executed successfully
      // cleanup
   }
   CATCH(CUserException, e)
   {
      if (theOp.GetRollbackConfirmedState())
      {
         // user did select "Retry" in Abort-dialog box
         // So, try to undo already done changes and
         // cleanup
      }
      if (theOp.GetAbortConfirmedState())
      {
         // user did select "Abort" in the Abort-dialog box
         // So, abort the operation and
         // cleanup
      }
   }
   END_CATCH
}

You can call this method from another method:

void Execute()
{
   CGXLongOperation theOp;
   theOp.SetStatusText("Executing ...", FALSE);

   // following call will lock the current operation level.
   // This means that when calling operation1(), this method
   // cannot change the status text. The call to
   //   theOp.SetStatusText("Operation1...", FALSE);
   // will have no effect.

   theOp.SetLockedState(TRUE);
   
   TRY
   {                             
      BOOL bAbort = FALSE;

       while (bStatementsToProcess)
       {
          Operation1();
             // if user aborted Operation1(), also
             // this method will be aborted.

         // check, if user pressed ESC to cancel
         if (theOp.NeedMessages())
         {
            theOp.SetPercentDone(nPercentDone);
            theOp.DoMessages(bAbort);

            if (bAbort)
               AfxThrowUserException();
         }
      }

      // operation executed successfully
      // cleanup
   }
   CATCH(CUserException, e)
   {
      if (theOp.GetRollbackConfirmedState())
      {
         // user did select "Retry" in Abort-dialog box
         // So, try to undo already done changes and
         // cleanup
      }
      if (theOp.GetAbortConfirmedState())
      {
         // user did select "Abort" in the Abort-dialog box
         // So, abort the operation and
         // cleanup
      }
   }
   END_CATCH
}

You can change the number of ticks necessary until NeedMessages will return TRUE (and a wait cursor is displayed) by calling SetTicksFirstTime and SetTicksContinued for subsequent calls. If you pass LONG_MAX to SetTicksFirstTime, the CGXLongOperation mechanism will be completely disabled.

Note: You must not instantiate CGXLongOperation as global object.

#include <gxall.h>

CGXLongOperation

Class Members