posts - 225, comments - 62, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

程序异常控制

Posted on 2012-01-04 00:01 魔のkyo 阅读(1024) 评论(2)  编辑 收藏 引用 所属分类: Programming

有时我们希望在程序崩溃时保存一些信息来帮助调试,尤其是在Release版程序

这时我们可以使用SetUnhandledExceptionFilter函数,MSDN对函数的描述是这样的

SetUnhandledExceptionFilter

The SetUnhandledExceptionFilter function enables an application to supersede the top-level exception handler of each thread and process.

After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);
Parameters
lpTopLevelExceptionFilter
[in] Pointer to a top-level exception filter function that will be called whenever the UnhandledExceptionFilter function gets control, and the process is not being debugged. A value of NULL for this parameter specifies default handling within UnhandledExceptionFilter.

The filter function has syntax similar to that of UnhandledExceptionFilter: It takes a single parameter of type LPEXCEPTION_POINTERS, has a WINAPI calling convention, and returns a value of type LONG. The filter function should return one of the following values.

Value
Meaning

EXCEPTION_EXECUTE_HANDLER
0x1
Return from UnhandledExceptionFilter and execute the associated exception handler. This usually results in process termination.

EXCEPTION_CONTINUE_EXECUTION
0xffffffff
Return from UnhandledExceptionFilter and continue execution from the point of the exception. Note that the filter function is free to modify the continuation state by modifying the exception information supplied through its LPEXCEPTION_POINTERS parameter.

EXCEPTION_CONTINUE_SEARCH
0x0
Proceed with normal execution of UnhandledExceptionFilter. That means obeying the SetErrorMode flags, or invoking the Application Error pop-up message box.

Return Values

The SetUnhandledExceptionFilter function returns the address of the previous exception filter established with the function. A NULL return value means that there is no current top-level exception handler.

Remarks

Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

The exception handler specified by lpTopLevelExceptionFilter is executed in the context of the thread that caused the fault. This can affect the exception handler's ability to recover from certain exceptions, such as an invalid stack.

上面的红字是我做的重点标注,通过注册的回调函数的返回值我们可以控制是否弹出程序崩溃的对话框。

EXCEPTION_EXECUTE_HANDLER 表示结束程序但不弹出崩溃对话框。从宏的拼写上可以认为我处理了这个异常
EXCEPTION_CONTINUE_EXECUTION 表示错误已经被修复,继续执行,这是一个不应该被使用的返回值,因为一个设计良好的程序不会把错误处理放在这个步骤中。
EXCEPTION_CONTINUE_SEARCH 表示结束程序并弹出一个崩溃对话框。从宏的拼写上可以认为我没有处理这个异常,请继续搜索其他的handler

事实上只能有一个回调函数被同时注册,因此如果我们想让所有注册过的回调函数都能执行到的话需要接收SetUnhandledExceptionFilter 的返回值,即the address of the previous exception filter并在回调函数中调用,像这样

LPTOP_LEVEL_EXCEPTION_FILTER g_preFilter;
LONG WINAPI func( PEXCEPTION_POINTERS pExceptionInfo )
{
    //...

    if(g_preFilter)
        return g_preFilter(pExceptionInfo);
    else
        return EXCEPTION_CONTINUE_SEARCH;
}

int main ()
{
    g_preFilter = SetUnhandledExceptionFilter(func);
    ///...
    return 0;
}

我们也可以做成,只在preFilter执行返回EXCEPTION_CONTINUE_SEARCH的时候才处理这个异常

LPTOP_LEVEL_EXCEPTION_FILTER g_preFilter;
LONG WINAPI func( PEXCEPTION_POINTERS pExceptionInfo )
{
    LONG res;
    if(g_preFilter==NULL || (res = g_preFilter(pExceptionInfo)) == EXCEPTION_CONTINUE_SEARCH)
    {
        //...
        return EXCEPTION_CONTINUE_SEARCH;
    }
    else
    {
        return res;
    }
}

int main ()
{
    g_preFilter = SetUnhandledExceptionFilter(func);
    ///...
    return 0;
}

这要根据实际的应用情况决定。

关于如何保留下当时的调用堆栈等信息是个复杂的主题,不过已经有前辈做过这件事了。

附件中包含一个异常处理机制,会在程序崩溃时生成一份报告文件和一份DUMP文件。

WheatyExceptionReport.rar

Feedback

# re: 程序异常控制  回复  更多评论   

2015-05-02 17:12 by 张少爷
你们一个函数了解的够透彻的啊,本尊受教了.
只有注册用户登录后才能发表评论。