windows核心编程---异常处理程序与软件异常

CPU抛出的异常是硬件异常,操作系统和应用程序抛出的异常是软件异常。

硬件或软件异常被抛出时,可用:

__try
{
}
__except(exception filter// 异常过滤程序)
{
// 异常处理程序
}

一个__try后,只需跟一个__except或__finally(终止处理程序)。

-异常过滤程序,异常处理程序
异常过滤程序,异常处理程序
主要有系统实现。

只在__try块中发生异常,才会转入__except,__try块未发生异常,不会进入__except块。

异常过滤表达式的值必定为以下三个标识符之一:
EXCEPTION_EXECUTE_HANDLER// 执行__except块中代码
EXCEPTION_CONTINUE_SEARCH// 到上一层__try中寻找异常处理方法
EXCEPTION_CONTINUE_EXECUTION// 忽略异常,继续执行

-EXCEPTION_EXECUTE_HANDLE
执行异常处理块中代码。
执行__except代码块,执行结束,继续往下从__except块后执行。

void FuncOStimpy1()
{
// 1
__try
{
// 2
FuncORen1();
}

__except(/6/EXCEPTION_EXECUTE_HANDLER)
{
// 8
MessageBox(...);
}
// 9
}

void FuncORen1()
{
DWORD dwTemp = 0;
// 3
__try
{
// 4
WaitForSingleObject(g_hSem, INFINITE);
// 5
g_dwProtectedData = 5 / dwTemp;
}
__finally
{
// 7 
// 若在这里直接return,异常处理的89不会被执行。相当于本函数正常返回。try/except下多级try/finally类似。
ReleaseSemaphore(g_hSem, 1, NULL);
}
}

-EXCEPTION_CONTINUE_EXECUTION

TCHAR g_szBuffer[100];
void FunclinRoosevelt1()
{
int x = 0;
TCHAR *pchBuffer = NULL;
__try
{
*pchBuffer = TEXT('J');
x = 5 / x;
}

__except(/*异常过滤程序,返回值必须为3个异常常量中一个*/OilFilter1(&pchBuffer))
{
MessageBox(
NULL,
TEXT("An exception occurred"),
NULL,
MB_OK);
}

MessageBox(
NULL,
TEXT("Function completed"),
NULL,
MB_OK
);
}

LONG OilFilter1(TCHAR **ppchBuffer)
{
if(*ppchBuffer == NULL)
{
*ppchBuffer = g_szBuffer;
// 将控制流跳转到导致异常的那条指令,并尝试重新执行这条指令
return EXCEPTION_CONTINUE_EXECUTION;
}
// 让系统执行except代码块
return EXCEPTION_EXECUTE_HANDLER;
}

-EXCEPTION_CONTINUE_SEARCH
继续往上层try搜索except.

-GetExceptionCode

__try
{
x=0;
y=4 / x;
...
}
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO)? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{

}

// 表明刚刚发生的异常的类型
DWORD GetExceptionCode();

// 内存相关异常
EXCEPTION_ACCESS_VIOLATION 写一个错误的虚拟地址
EXCEPTION_DATATYPE_MISALIGNMENT 线程试图从没有提供自动对齐机制的硬件里读入没有对齐的数据。
EXCEPTION_ARRAY_BOUNDS_EXCEEDED 线程在支持边界检查的硬件上访问越界的数组元素。
EXCEPTION_IN_PAGE_ERROR 文件系统或设备取得读取错误而引起的页错误。
EXCEPTION_GUARD_PAGE 线程试图访问具备PAGE_GUARD属性内存页。
EXCEPTION_STACK_OVERFLOW 线程用光栈空间
EXCECPTION_ILLEGAL_INSTRUCTION 非法指令
EXCEPTION_PRIV_INSTRUCTION 试图执行当前机器模式下不允许的操作

// 与异常本身相关的异常
EXCEPTION_INVALID_DISPOSITION 异常过滤返回3个常量以外值
EXCEPTION_NONCONTINUABLE_EXCEPTION 异常过滤返回继续执行,但实际这类异常不能继续

// 与调试相关异常
EXCEPTION_BREAKPOINT 执行到断点
EXCEPTION_SINGLE_STEP 单步
EXCEPTION_INVALID_HANDLE 传入无效句柄给一函数

// 与整型相关的异常
EXCEPTION_INT_DIVIDE_BY_ZERO 线程试图在整数除法运算中以0做除数
EXCEPTION_INT_OVERFLOW 整型运算结果超出范围

// 与浮点类型相关的异常
EXCEPTION_FLT_DENORMAL_OPERAND 浮点运算中一个运算数是不能作为标准浮点数的小数。
EXCEPTION_FLT_DIVIDE_BY_ZERO 线程试图在浮点除法中以0做除数
EXCEPTION_FLT_INEXACT_RESULT 浮点运算结果不能精确地表示为十进制小数
EXCEPTION_FLT_INVALID_OPERATION 其它浮点数异常
EXCEPTION_FLT_OVERFLOW 浮点运算指数部分超出该类型允许的最大值
EXCEPTION_FLT_STACK_CHECK 浮点运算造成栈上溢出或下溢出
EXCEPTION_FLT_UNDERFLOW 浮点运算指数部分小于该类型允许的最小值

GetExceptionCode只能用在异常过滤程序里(仅限与__except后的括号里),或异常处理程序里。

异常代码遵循WinError.h中有关错误代码的规则

-GetExceptionInformation
一个异常发生时,系统将向发生异常的线程的栈中压入3个结构,
// 包含关于抛出异常的信息
EXCEPTION_RECORD,
// 与异常和CPU相关的信息
CONTEXT,
// 含两个指针,指向前两个结构
EXCEPTION_POINTERS。

PEXCEPTION_POINTERS GetExceptionInformation();

这个函数只能在异常过滤程序中调用,因为上述3个结构只在系统计算异常过滤程序时才有效。
仅仅限与_except后的括号里。

typedef struct _EXCEPTION_RECORD
{
// 异常码
DWORD ExceptionCode;
// 异常标志
DWORD ExceptionFlags;
// 异常链
struct _EXCEPTION_RECORD *ExceptionRecord;
// 导致异常的CPU指令地址
PVOID ExceptionAddress;
// 异常相关参数个数
DWORD NumberParameters;
// 描述异常的附加数组
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}EXCEPTION_RECORD;

对异常EXCEPTION_ACCESS_VIOLATION,
ExceptionInformation[0]:
0,读取不能访问的数据
1,写入不能访问的数据
8,执行不能访问的代码

__try
{
...
}

__except(ExpFltr(GetExceptionInformation()))
{
...
}

LONG ExpFltr(LPEXCEPTION_POINTERS pep)
{
TCHAR szBuf[300], *p;
PEXCEPTION_RECORD pER = pep->ExceptionRecord;
DWORD dwExceptionCode = pER->ExceptionCode;

StringCchPrintf(
szBuf,
_countof(szBuf),
TEXT("Code = %x, Address = %p"),
dwExceptionCode,
pER->ExceptionAddress
);

p = _tcschr(szBuf, TEXT('0'));

switch(dwExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
    {
        StringCchPrintf(
        p,
        _countof(szBuf),
        TEXT("\n--> Attempt to %s data at address %p"),
        pER->ExceptionInformation[0] ?
        TEXT("write") : TEXT("read"),
        pER->ExceptionInformation[1]
        );
    }
    break;
default:
    break;
}

MessageBox(
NULL,
szBuf,
TEXT("Exception"),
MB_OK | MB_ICONEXCLAMATION
);

return EXCEPTION_CONTINUE_SEARCH;
}

-软件异常
也可在应用代码抛出异常

// 抛出一个软件异常
VOID RaiseException(
// 要抛出异常标识符。
// 如果定义自己的异常标识符,要遵循windows错误代码定义的标准格式。
DWORD dwExceptionCode,
// 标志:
// 0
// EXCEPTION_NONCONTINUABLE,此时异常过滤程序不能返回EXCEPTION_CONTINUE_EXECUTION.
// 此时,过滤程序若返回EXCEPTION_CONTINUE_EXECUTION,会引发EXCEPTION_NONCONTINUABLE_EXCEPTION
DWORD dwExceptionFlags,
// 异常附件信息
DWORD nNumberOfArguments,
// 异常附件信息
CONST ULONG_PTR *pArguments
);

你可能感兴趣的:(System-Windows)