在VC++中混用C++异常和结构化异常

 在初学VC的时候,总以为try()catch(...)可以抓到所有的异常. 在开发之前开发的一个服务器程序中,才发现服务器经常莫名其妙的宕机了.一直觉得很诡异.

   直到后来看了很多资料才明白结构化异常跟C++异常是两套东西,不统一。有些异常try.catch不一定能不抓到. 要将两种异常共同使用.下面的代码可以达到目的. 使用下面异常类,可以使程序更稳定.(注意:编译选项里面要记得打开 结构化异常开关. compile with: /EHa)

// 把结构化异常转化为C++异常 struct SException { EXCEPTION_RECORD er; CONTEXT context; SException(PEXCEPTION_POINTERS pep) { er = *(pep->ExceptionRecord); context = *(pep->ContextRecord); } operator DWORD() { return er.ExceptionCode; } static void MapSEtoCE() { _set_se_translator( TranslateSEToCE ); } static void __cdecl TranslateSEToCE( UINT dwEC, PEXCEPTION_POINTERS pep ) { throw SException(pep); } }; void main() { SException::MapSEtoCE(); try { int* p = 0; int a = *p; } catch( SException& e ) { if ( (DWORD)e == EXCEPTION_ACCESS_VIOLATION ) { printf( "Access violation" ); } } }

 

另外可以调用MS提供的函数SetUnhandledExceptionFilter, 这是程序异常未处理的最后一到防线.可以在回调函数中写出DUMP文件,然后通过PDB文件来调试看到宕机的源代码段.

LONG __stdcall MyCrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx) { #ifdef _M_IX86 if (pEx->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { // be sure that we have enought space... static char MyStack[1024*128]; // it assumes that DS and SS are the same!!! (this is the case for Win32) // change the stack only if the selectors are the same (this is the case for Win32) //__asm push offset MyStack[1024*128]; //__asm pop esp; __asm mov eax,offset MyStack[1024*128]; __asm mov esp,eax; } #endif bool bFailed = true; HANDLE hFile; hFile = CreateFile(szMiniDumpFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION stMDEI; stMDEI.ThreadId = GetCurrentThreadId(); stMDEI.ExceptionPointers = pEx; stMDEI.ClientPointers = TRUE; // try to create an miniDump: if (s_pMDWD( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &stMDEI, NULL, NULL )) { bFailed = false; // suceeded } CloseHandle(hFile); } if (bFailed) { return EXCEPTION_CONTINUE_SEARCH; } if (bMsgbox) { string strMsg = "Run failed, Please Copy the "; strMsg += szMiniDumpFileName; strMsg += " file to us!"; ::MessageBox(NULL, strMsg.c_str(), TEXT("Error"), 0); } // or return one of the following: // - EXCEPTION_CONTINUE_SEARCH // - EXCEPTION_CONTINUE_EXECUTION // - EXCEPTION_EXECUTE_HANDLER return EXCEPTION_EXECUTE_HANDLER; // this will trigger the "normal" OS error-dialog } #ifndef _M_IX86 #error "The following code only works for x86!" #endif LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { return NULL; } BOOL PreventSetUnhandledExceptionFilter() { HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); if (hKernel32 == NULL) return FALSE; void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); if(pOrgEntry == NULL) return FALSE; unsigned char newJump[ 100 ]; DWORD dwOrgEntryAddr = (DWORD) pOrgEntry; dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far void *pNewFunc = &MyDummySetUnhandledExceptionFilter; DWORD dwNewEntryAddr = (DWORD) pNewFunc; DWORD dwRelativeAddr = dwNewEntryAddr-dwOrgEntryAddr; newJump[ 0 ] = 0xE9; // JMP absolute memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc)); SIZE_T bytesWritten; BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); return bRet; } void InitMiniDumpWriter() { if (s_hDbgHelpMod != NULL) return; // Initialize the member, so we do not load the dll after the exception has occured // which might be not possible anymore... s_hDbgHelpMod = LoadLibrary(_T("dbghelp.dll")); if (s_hDbgHelpMod != NULL) s_pMDWD = (tMDWD) GetProcAddress(s_hDbgHelpMod, "MiniDumpWriteDump"); // Register Unhandled Exception-Filter: LPTOP_LEVEL_EXCEPTION_FILTER p = SetUnhandledExceptionFilter(MyCrashHandlerExceptionFilter); BOOL bRet = PreventSetUnhandledExceptionFilter(); // Additional call "PreventSetUnhandledExceptionFilter"... // See also: "SetUnhandledExceptionFilter" and VC8 (and later) // http://blog.kalmbachnet.de/?postid=75 }

你可能感兴趣的:(VC代码)