ENTERPRISE

Windows System Programming : Exception Handling - Treating Errors as Exceptions

4/27/2013 12:47:16 AM
The function terminates the process when the programmer indicates that the error is fatal. This approach, however, prevents an orderly shutdown, and it also prevents program continuation after recovering from an error. For example, the program may have created temporary files that should be deleted, or the program may simply proceed to do other work after abandoning the failed task. ReportError has other limitations, including the following.
  • A fatal error shuts down the entire process when only a single thread should terminate.

  • You may wish to continue program execution rather than terminate the process.

  • Synchronization resources , such as events or semaphores, will not be released in many circumstances.

Open handles will be closed by a terminating process, but not by a terminating thread. It is necessary to address this and other deficiencies.

The solution is to write a new function that invokes ReportError with a nonfatal code in order to generate the error message. Next, on a fatal error, it will raise an exception. Windows will use an exception handler from the calling try block, so the exception may not actually be fatal if the handler allows the program to recover and resume. Essentially, ReportException augments normal defensive programming techniques, previously limited to ReportError. Once a problem is detected, the exception handler allows the program to recover and continue after the error. Program 4-2 illustrates this capability.

Program 1 shows the function. It is in the same source module as ReportError, so the definitions and include files are omitted.

Program 1. ReportException: Exception Reporting Function
/* ReportError extension to generate a nonfatal user-exception code. */

VOID ReportException(LPCTSTR userMessage, DWORD exceptionCode)
{
   ReportError(userMessage, 0, TRUE);
   if (exceptionCode != 0) /* If fatal, raise an exception. */
      RaiseException(
         (0x0FFFFFFF & exceptionCode) | 0xE0000000, 0, 0, NULL);
   return;
}

ReportException is used in Program 2 and elsewhere.

Program 2. toupper: File Processing with Error and Exception Recovery
/* Convert one or more files, changing all letters to uppercase.
   The output file will be the same name as the input file, except
   a UC_ prefix will be attached to the file name. */

#include "Everything.h"

int _tmain(DWORD argc, LPTSTR argv[])
{
   HANDLE hIn = INVALID_HANDLE_VALUE, hOut = INVALID_HANDLE_VALUE;
   DWORD nXfer, iFile, j;
   CHAR outFileName[256] = "", *pBuffer = NULL;
   OVERLAPPED ov = { 0, 0, 0, 0, NULL};
   LARGE_INTEGER fSize;

   /* Process all files on the command line. */
   for (iFile = 1; iFile < argc; iFile++) __try { /* Exceptn block */
      /* All file handles are invalid, pBuffer == NULL, and
         outFileName is empty. This is assured by the handlers */
      if (_tcslen(argv[iFile]) > 250)
         ReportException(_T("The file name is too long."), 1);
      _stprintf(outFileName, "UC_%s", argv[iFile]);

      __try { /* Inner try-finally block */
         hIn  = CreateFile(argv[iFile], GENERIC_READ,
            0, NULL, OPEN_EXISTING, 0, NULL);
         if (hIn == INVALID_HANDLE_VALUE)
            ReportException(argv[iFile], 1);

         if (!GetFileSizeEx(hIn, &fSize) || fSize.HighPart > 0)
            ReportException(_T("This file is too large."), 1);

         hOut = CreateFile(outFileName,
            GENERIC_READ | GENERIC_WRITE,
            0, NULL, CREATE_NEW, 0, NULL);
         if (hOut == INVALID_HANDLE_VALUE)
            ReportException(outFileName, 1);

         /* Allocate memory for the file contents */
         pBuffer = malloc(fSize.LowPart);
         if (pBuffer == NULL)
            ReportException(_T("Memory allocation error"), 1);

         /* Read the data, convert it, and write to the output file */
         /* Free all resources on completion; process next file */

         if (!ReadFile(hIn, pBuffer, fSize.LowPart, &nXfer, NULL)
                   || (nXfer != fSize.LowPart))
                ReportException(_T("ReadFile error"), 1);

         for (j = 0; j < fSize.LowPart; j++) /* Convert data */
            if (isalpha(pBuffer[j])) pBuffer[j] =
               toupper(pBuffer[j]);

         if (!WriteFile(hOut, pBuffer, fSize.LowPart, &nXfer, NULL)
                   || (nXfer != fSize.LowPart))
                ReportException(_T("WriteFile error"), 1);

      } __finally { /* File handles are always closed */
         /* memory freed, and handles and pointer reinitialized. */
         if (pBuffer != NULL) free(pBuffer); pBuffer = NULL;
         if (hIn  != INVALID_HANDLE_VALUE) {
            CloseHandle(hIn);
            hIn  = INVALID_HANDLE_VALUE;
         }
         if (hOut != INVALID_HANDLE_VALUE) {
            CloseHandle(hOut);
            hOut = INVALID_HANDLE_VALUE;
         }
         _tcscpy(outFileName, _T(""));
      }
   } /* End of main file processing loop and try block. */
   /* This exception handler applies to the loop body */

   __except (EXCEPTION_EXECUTE_HANDLER) {
      _tprintf(_T("Error processing file %s\n"), argv[iFile]);
      DeleteFile(outFileName);
   }
   _tprintf(_T("All files converted, except as noted above\n"));
   return 0;
}

					  

The UNIX signal model is significantly different from SEH. Signals can be missed or ignored, and the flow is different. Nonetheless, there are points of comparison.

UNIX signal handling is largely supported through the C library, which is also available in a limited implementation under Windows. In many cases, Windows programs can use console control handlers, in place of signals.

Some signals correspond to Windows exceptions.

Here is the limited signal-to-exception correspondence:

  • SIGILL—EXCEPTION_PRIV_INSTRUCTION or EXCEPTION_ILLEGAL_INSTRUCTION

  • SIGSEGV—EXCEPTION_ACCESS_VIOLATION

  • SIGFPE—Seven distinct floating-point exceptions, such as EXCEPTION_FLT_DIVIDE_BY_ZERO

  • SIGUSR1 and SIGUSR2—User-defined exceptions

The C library raise function corresponds to RaiseException.

Windows will not generate SIGILL, SIGSEGV, or SIGTERM, although raise can generate one of them. Windows does not support SIGINT.

The UNIX kill function (kill is not in the Standard C library), which can send a signal to another process, is comparable to the Windows function GenerateConsoleCtrlEvent . In the limited case of SIGKILL, there is no corresponding exception, but Windows has TerminateProcess and TerminateThread, allowing one process (or thread) to “kill” another, although these functions should be used with care .

Other  
 
Video
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone