1. Windows SEH 與 C++ Exception
1) Windows SEH 結構化異常
結構化異常是Windows 操作系統提供的與語言無關的異常處理機制, SHE使用Win32API中的RaiseException()函數來拋出異常,在VC中使用關鍵字__try和關鍵字__except來捕獲,並用宏 函數GetExceptionCode和GetExceptionInfo來獲取捕獲的異常由什麼原因產生,和產生異常時環境狀態。__finally關 鍵字保證無論是否發生異常,finally代碼段都會被執行。
SHE使用示例代碼
int ECode;
__try
{
__try
{
RaiseException(1,
// 拋出異常碼爲1的SEH異常
0,
0, NULL);
// 沒有參數
}
__finally
{
printf("2 ");
// 不管是否有異常,必定會執行的代碼
}
}
__except (ECode=GetExceptionCode())
{
printf("發生異常,Code=%d/n",ECode);
// 捕獲異常後執行的代碼 ;
}
輸出結果:
2 發生異常, Code=1
2) C++Exception
C++標準也提供了一種異常處理機制,通過使用try,catch,throw關鍵字來表達,在C++異常可以通過throw函數來拋出簡單變量,複雜變量與異常對象,與Windows異常相比,異常對象可以給開發者提供更多的信息。
try
{
//正常代碼
。。。
throw CExcetion();
。。。
}
catch (CException* e)
{
//處理異常代碼
}
3) SEH 到 C++異常的轉換
在同一個程序中,如果使用WIN32API它會拋出SHE,使用C++庫函數,它們又會拋出C++異常,Win32API和C++函數混和使用時如果使用兩種異常捕獲機制時,使用起來會影響程序的可讀性,因此C++運行庫提供了 _set_se_translator 函數,在SHE異常發生時通過回調方式來轉換SEH異常爲C++異常。在此提供一個轉換的宏來實現轉換。
轉換宏的代碼:
#define INSTALL_SEHCONVERT() ExceptionConvert ecExceptionConvert
class SEHException
{
private :
unsigned int nSE;
public :
SEHException() {}
SEHException( unsigned int n ) : nSE( n ) {}
~SEHException() {}
unsigned int getSeNumber() { return nSE; }
};
class ExceptionConvert
{
public :
ExceptionConvert(){OldFanc = _set_se_translator(trans_func); }
~ExceptionConvert(){_set_se_translator(OldFanc); }
private :
static void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
throw SEHException(u);
}
_se_translator_function OldFanc;
};
使用上面 INSTALL_SEHCONVERT 宏後就可以使用如下代碼來捕獲SHE異常了
INSTALL_SEHCONVERT();
Try
{
…
}
catch(SEHException &seh){
…
}
2. 同步異常與異步異常
1) VC的C++ Exception 採用兩種模式捕獲異常:同步模式和異步模式。VC的工程的調試版本缺省使用異步模式,工程的發佈版本缺省使用同步模式。在同步模式下,VC的編譯器假定代 碼中只有在顯示使用throw和調用函數的時候纔會引發異常,因此,在同步模式下,VC編譯出的代碼比較小,但在這種模式下,try-catch對不能捕 獲內存訪問異常與算術除零異常等。在異步模式下,VC的編譯器爲try塊內的每一條語句生成異常捕獲代碼,在這種情況下,他能夠捕獲全部的異常,還能保證 棧上對象在解棧中正確釋放。爲了要在發行版本中也能夠捕獲全部異常就需要打開異步模式,但代價是程序編譯出代碼變大,運行速度變慢。
2)編譯選項:
同步模式的編譯選項爲/EHs或者/GX(等同於/EHsc)
異步模式的編譯選項爲/EHa
3. 多線程下的異常捕獲
在創建線程並運行線程的函數中把創建線程的代碼放在try塊中並不會捕獲到線程函數中發生的異常,線程函數中發生的異常只能在線程函數中捕獲。並且每一個線程都需要自己的SHE轉換宏。轉換宏可以放在線程函數的開始部分
4.參考MSDN庫