構造化例外処理 ~ 例外情報の取得
例外 (SEH) が発生した際、例外フィルタにて GetExceptionInformation を用いて、その例外の情報を取得することが可能です。 GetExceptionInformation は例外フィルタでしか参照することはできません。
LPEXCEPTION_POINTERS GetExceptionInformation(void);
GetExceptionInformation は EXCEPTION_POINTERS へのポインタを返します。
EXCEPTION_POINTERS の定義は次です。
typedef struct _EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
すなわち、EXCEPTION_RECORD へのポインタと CONTEXT へのポインタを保持します。
EXCEPTION_RECORD の定義は次です。
typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD;
CONTEXT の定義はターゲットの環境によって変わります。基本的にレジスタの情報などを持ちます。 WinNT.h ヘッダを参照してください。
また、例外コードのみであれば GetExceptionCode を使って参照可能です。 これは例外フィルタ及び例外ハンドラ内で呼ぶことができます。
DWORD GetExceptionCode(void);
動作実験
では実際に動かして使ってみましょう。
下のコードでは __try ブロックにてわざと AV (Access Violation) を発生させています。 そして、MyFilter という名前の例外フィルタにて GetExceptionInformation を渡し、MyFilter では例外の情報を少しかいつまんでダンプしています。 例外ハンドラでは GetExceptionCode を用いて、確かに例外コードが取得できることを確認しています。
#include <windows.h> #include <stdio.h> INT MyFilter( PEXCEPTION_POINTERS pep ) { PEXCEPTION_RECORD per = pep->ExceptionRecord; PCONTEXT pctx = pep->ContextRecord; printf( "-- Exception Record --\n" ); printf( "Exception Code: %08X\n", per->ExceptionCode ); printf( "Exception Address: %08X\n", per->ExceptionAddress ); printf( "-- Context --\n" ); printf( "EIP %08X\tEBP %08X\n", pctx->Eip, pctx->Ebp ); printf( "EAX %08X\tEBX %08X\tECX %08X\n", pctx->Eax, pctx->Ebx, pctx->Ecx ); return EXCEPTION_EXECUTE_HANDLER; } int main(int argc, char* argv[]) { __try { strcat( NULL, NULL ); } __except ( MyFilter( GetExceptionInformation() ) ) { printf("__except\n"); printf( "Exception Code: %X\n", GetExceptionCode() ); } return 0; }
この実行結果は以下のようになりました。
> seh2.exe -- Exception Record -- Exception Code: C0000005 Exception Address: 004012B0 -- Context -- EIP 004012B0 EBP 0012FF40 EAX 0012FF30 EBX 7FFDF000 ECX 00000000 __except Exception Code: C0000005
C0000005 は AV の例外コードです。