在初学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
- }
本文介绍了如何在C++中通过try-catch结构捕获结构化异常(SEH)。当try-catch无法捕获所有异常时,作者提供了一个SException类,将结构化异常转换为C++异常。同时,文章提到了设置未处理异常过滤器(SetUnhandledExceptionFilter)以在程序异常未处理时生成DUMP文件,以便于后续调试。
737

被折叠的 条评论
为什么被折叠?



