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 + -
显示快捷键?