sehexcpt.c

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

C
260
字号
/************************************************************
Module name: SEHExcpt.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;


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


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

   BOOL fAttemptedWrite;
   TCHAR szBuf[100];

   // Find out whether a memory access 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);
}


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


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 {
      // 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 doesn't come from 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 either before the program
         // tried to reserve the address space or 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;
      }

      // This filter will handle the exception.

      CommitMemory(hwndLog, lpEP, lpbAttemptedAddr);

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

   __finally {
   }

   // Now that memory is committed, we can continue execution
   // at 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;
   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;

         // Try 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 in the except block.

   }  // __except
}


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


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

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

   // 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_SEHEXCPT),
      NULL, Dlg_Proc);

   return(0);
}


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

⌨️ 快捷键说明

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