sehsoft.c

来自「一本已经绝版的好书」· C语言 代码 · 共 333 行

C
333
字号
/************************************************************
Module name: SEHSoft.C
Notices: Copyright (c) 1995-1997 Jeffrey Richter
************************************************************/


#include "..\CmnHdr.H"                  /* See Appendix C. */
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdio.h>            // For sprintf
#include <stdlib.h>           // For rand
#include "Resource.H"


/////////////////////////////////////////////////////////////


#define NUMELEMENTS     (50)

// Declare each array element to be 4 KB.
typedef struct {
   BYTE bReserved[4 * 1024];
} ELEMENT, *LPELEMENT;

// Useful macro for creating our own software exception codes
#define MAKESOFTWAREEXCEPTION(Severity, Facility, Exception) \
   ((DWORD) ( \
   /* Severity code */     (Severity       ) |     \
   /* MS(0) or Cust(1) */  (1         << 29) |     \
   /* Reserved(0) */       (0         << 28) |     \
   /* Facility code */     (Facility  << 16) |     \
   /* Exception code */    (Exception <<  0)))

// Our very own software exception. This exception is raised
// when an element of the array needs to be initialized
// to all zeros.
#define SE_ZERO_ELEM   \
   MAKESOFTWAREEXCEPTION(ERROR_SEVERITY_ERROR, \
      FACILITY_NULL, 1)


/////////////////////////////////////////////////////////////


void CommitMemory(HWND hwndLog, LPEXCEPTION_POINTERS lpEP,
   LPBYTE lpbAttemptedAddr) {

   BOOL fAttemptedWrite;
   TCHAR szBuf[100];

   // Find out whether a memory read or write was tried.
   fAttemptedWrite = (BOOL)
      lpEP->ExceptionRecord->ExceptionInformation[0];

   // Add an entry to the Execution Log list box.
   _stprintf(szBuf,
      __TEXT("---> Committing memory (%s attempted)"),
      fAttemptedWrite ? __TEXT("write") : __TEXT("read"));
   ListBox_AddString(hwndLog, szBuf);

   // The attempted memory access did occur while the
   // program was accessing an element in our array.
   // Let's try to commit memory to an individual element
   // of the reserved array's address space.
   VirtualAlloc(lpbAttemptedAddr, sizeof(ELEMENT), 
      MEM_COMMIT, PAGE_READWRITE);

   if (!fAttemptedWrite) {
      // The program is trying to read an array element
      // that has never been created. We'll raise our very
      // own software exception so that this array element
      // will be zeroed before it is accessed.
      RaiseException(SE_ZERO_ELEM, 0, 1,
         (LPDWORD) &lpbAttemptedAddr);
   }
}


/////////////////////////////////////////////////////////////


int ExpFilter (LPEXCEPTION_POINTERS lpEP, LPBYTE lpbArray,
   LONG lNumBytesInArray, HWND hwndLog) {

   LPBYTE lpbAttemptedAddr = NULL;

   // Get the exception code explaining
   // why the filter is executing.
   DWORD dwExceptionCode = lpEP->ExceptionRecord->ExceptionCode;

   // Assume that this filter will NOT handle the exception
   // and will let the system continue scanning
   // for other filters.
   int nFilterResult = EXCEPTION_CONTINUE_SEARCH;

   __try {
      // Declare an EXCEPTION_RECORD structure that is local 
      // to this __try frame. This variable is used in the 
      // __except block below.
      EXCEPTION_RECORD SavedExceptRec;

      // We must first determine whether the exception is
      // occurring because of a memory access to our array of
      // elements. This filter and handler do not process
      // any other types of exceptions.

      if (dwExceptionCode != EXCEPTION_ACCESS_VIOLATION) {
         // If the exception is not a memory access violation,
         // the exception did not occur because of an array
         // element access. The system should continue its
         // search for another exception filter.
         nFilterResult = EXCEPTION_CONTINUE_SEARCH;
         __leave;
      }

      if (lpbArray == NULL) {
         // The exception occurred before the program
         // tried to reserve the address space, or else the
         // array's address space was unsuccessfully reserved.
         nFilterResult = EXCEPTION_CONTINUE_SEARCH;
         __leave;
      }

      // Get the address of the attempted memory access.
      lpbAttemptedAddr = (LPBYTE)
         lpEP->ExceptionRecord->ExceptionInformation[1];

      if ((lpbAttemptedAddr < lpbArray) ||
         ((lpbArray + lNumBytesInArray) < lpbAttemptedAddr)) {
         // Address attempted is BELOW the beginning of the
         // array's reserved space or is ABOVE the end of the
         // array's reserved space. We'll let some other
         // filter handle this exception.
         nFilterResult = EXCEPTION_CONTINUE_SEARCH;
         __leave;
      }

      // *** The exception is to be handled by this filter.

      __try {
         // Call the function that commits memory to the
         // accessed array element. This function will raise
         // a software exception if read access was attempted.
         // In this case, we want to zero the contents of the
         // array element before the read continues.
         CommitMemory(hwndLog, lpEP, lpbAttemptedAddr);
      }

      // We want to handle the exception only if it is our
      // very own software exception telling us to zero the
      // contents of the array element. If this is the case, we
      // need to save the additional information given to us
      // with the SE_ZERO_ELEM exception code so that the
      // handler knows which array element to zero.
      __except ((GetExceptionCode() == SE_ZERO_ELEM) ?
         (SavedExceptRec = 
         *((GetExceptionInformation())->ExceptionRecord),
         EXCEPTION_EXECUTE_HANDLER) :
         EXCEPTION_CONTINUE_SEARCH) {

         // Get the address of the array element to zero.
         LPELEMENT lpArrayElementToZero = (LPELEMENT)
            SavedExceptRec.ExceptionInformation[0];

         // Zero the array element before reading from it.
         chINITSTRUCT(*lpArrayElementToZero, FALSE);

         ListBox_AddString(hwndLog,
            __TEXT("---> Zeroed array element"));
      }

      // Memory is committed now; let's restart the
      // instruction that caused the exception in the first
      // place. This time, it will succeed and not cause
      // another exception.
      nFilterResult = EXCEPTION_CONTINUE_EXECUTION;
   }

   __finally {
   }

   // Now that memory is committed, we can continue execution
   // on the instruction that generated the exception in
   // the first place.
   return(nFilterResult);
}


/////////////////////////////////////////////////////////////


void Dlg_ReserveArrayAndAccessIt (HWND hwndLog,
   int nNumAccesses) {

   LPELEMENT lpArray = NULL;
   ELEMENT Element;
   TCHAR szBuf[100];
   int nElementNum = 0;
   const LONG lNumBytesInArray = sizeof(ELEMENT) *
      NUMELEMENTS;

   // Clear the Execution Log list box.
   ListBox_ResetContent(hwndLog);
   ListBox_AddString(hwndLog, __TEXT("Execution started"));

   __try {
      // Reserve an address space large enough to
      // hold NUMELEMENTS number of ELEMENTs.
      lpArray = VirtualAlloc(NULL, lNumBytesInArray,
         MEM_RESERVE, PAGE_NOACCESS);

      while (nNumAccesses--) {
         // Get the index of a random element to access.
         nElementNum = rand() % NUMELEMENTS;

         // Give us a 50 percent chance of reading and a
         // 50 percent chance of writing.
         if ((rand() % 2) == 0) {
            // Attempt a read access.
            _stprintf(szBuf, __TEXT("Reading index: %d"),
               nElementNum);
            ListBox_AddString(hwndLog, szBuf);

            // The exception will occur on this line.
            Element = lpArray[nElementNum];

         } else {

            // Attempt a write access.
            _stprintf(szBuf, __TEXT("Writing index: %d"),
               nElementNum);
            ListBox_AddString(hwndLog, szBuf);

            // The exception will occur on this line.
            lpArray[nElementNum] = Element;
         }

      }  // while

      // We have finished the execution.
      ListBox_AddString(hwndLog, __TEXT("Execution ended"));

      // Decommit and free the array of ELEMENTs.
      VirtualFree(lpArray, 0, MEM_RELEASE);
   }  // __try

   __except (
      ExpFilter(GetExceptionInformation(), (LPBYTE) lpArray,
         lNumBytesInArray, hwndLog)) {

      // Because the filter never returns
      // EXCEPTION_EXECUTE_HANDLER, there is
      // nothing to do here.

   }  // __except
}


/////////////////////////////////////////////////////////////


BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus,
   LPARAM lParam) {

   // Associate an icon with the dialog box.
   chSETDLGICONS(hwnd, IDI_SEHSOFT, IDI_SEHSOFT);

   // Default the number of accesses to 100.
   SetDlgItemInt(hwnd, IDC_NUMACCESSES, 100, FALSE);
   return(TRUE);
}


/////////////////////////////////////////////////////////////


void Dlg_OnCommand (HWND hwnd, int id,
   HWND hwndCtl, UINT codeNotify) {

   int  nNumAccesses;
   BOOL fTranslated;

   switch (id) {
      case IDOK:
         nNumAccesses = GetDlgItemInt(hwnd, IDC_NUMACCESSES,
               &fTranslated, FALSE);

         if (fTranslated) {
            Dlg_ReserveArrayAndAccessIt(
               GetDlgItem(hwnd, IDC_LOG), nNumAccesses);
         } else {
            chMB(__TEXT("Invalid number of accesses."));
         }
         break;

      case IDCANCEL:
         EndDialog(hwnd, id);
         break;
   }
}


/////////////////////////////////////////////////////////////


BOOL CALLBACK Dlg_Proc (HWND hwnd, UINT uMsg,
   WPARAM wParam, LPARAM lParam) {

   switch (uMsg) {
      chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
      chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
   }
   return(FALSE);
}


/////////////////////////////////////////////////////////////


int WINAPI _tWinMain (HINSTANCE hinstExe,
   HINSTANCE hinstPrev, LPTSTR pszCmdLine, int nCmdShow) {

   chWARNIFUNICODEUNDERWIN95();
   DialogBox(hinstExe, MAKEINTRESOURCE(IDD_SEHSOFT),
      NULL, Dlg_Proc);

   return(0);
}


//////////////////////// End Of File ////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?