【问题标题】:How to catch unhandled exception in WinCE?如何在 WinCE 中捕获未处理的异常?
【发布时间】:2014-01-09 20:37:17
【问题描述】:

在桌面 Windows 中,我可以使用 windows.h 中的 SetUnhandledExceptionFilter 函数,但它在 WinCE 中不起作用。如何在 WinCE 中捕获未处理的异常?

注意:我使用的是 C++ 而不是 .NET。

【问题讨论】:

    标签: c++ exception-handling windows-ce


    【解决方案1】:

    到目前为止,我发现的唯一方法是将应用程序中每个线程的执行包装为:

    __try
    {
        // Call the thread start function here
    }
    __except(MyExceptionFilter(GetExceptionInformation())
    {
        // Handle the exception here
    }
    

    这听起来需要做很多工作,但如果你编写一个像这样为你包装线程的函数,那就相对容易了:

    typedef struct {
        void* startFct;
        void* args;
    } ThreadHookArgs;
    
    // "params" contains an heap-allocated instance of ThreadHookArgs
    // with the wrapped thread start function and its arguments.
    DWORD WINAPI wrapThread(LPVOID params) {
    
        ThreadHookArgs threadParams;
        memcpy(&args, params, sizeof(ThreadHookArgs));
    
        // Delete the parameters, now we have a copy of them
        delete params;
    
        __try {
            // Execute the thread start function
            return ((LPTHREAD_START_ROUTINE) threadParams.startFct) (threadParams.args);
        }
        __except(MyExceptionFilter(GetExceptionInformation())
        {
            // Handle the exception here
            return EXIT_FAILURE;
        }
    
    }
    

    然后编写你自己的线程创建函数来调用钩子而不是线程启动函数:

    // Drop-in replacement for CreateThread(), executes the given
    // start function in a SEH exception handler
    HANDLE MyCreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,
                           DWORD dwStackSize,
                           LPTHREAD_START_ROUTINE lpStartAddress,
                           LPVOID lpParameter,
                           DWORD dwCreationFlags,
                           LPDWORD lpThreadId)
    {
        HANDLE hThread;
        DWORD dwThreadId;
    
        LPTHREAD_START_ROUTINE startFct = lpStartAddress;
        LPVOID startParam = lpParameter;
    
        // Allocate the hook function arguments on the heap.
        // The function will delete them when it runs.
        ThreadHookArgs* hookArgs = new ThreadHookArgs;
        hookArgs->fct = lpStartAddress;
        hookArgs->args = lpParameter;
    
        // Set the start function of the created thread to
        // our exception handler hook function
        startFct = (LPTHREAD_START_ROUTINE) &wrapThread;
        startParam = hookArgs;
    
        // Start the hook function, which will in turn execute
        // the desired thread start function
        hThread = CreateThread( lpThreadAttributes,
                                dwStackSize,
                                startFct,
                                startParam,
                                dwCreationFlags,
                                &dwThreadId );
    
        return hThread;
    }
    

    请注意,如果您使用的是 Windows CE 6 及更高版本,这些版本具有矢量异常处理,这可能会更容易:

    http://msdn.microsoft.com/en-us/library/ee488606%28v=winembedded.60%29.aspx

    【讨论】:

    • 矢量异常处理不能解决这个问题,因为矢量异常过滤器是在调用任何特定于帧的过滤器之前调用的,而未处理的异常过滤器是在调用所有异常过滤器之后调用的。这很容易出错,因为它使许多关于哪个过滤器在其他过滤器之前被调用的假设无效。
    • 此解决方案的另一个问题。如果您不完全遵守 Windows CE ABI,则可能会跳过基于帧的异常过滤器,因为内核可能无法正确展开堆栈。请注意,即使程序不遵守 Windows CE ABI,仍然会调用向量异常过滤器。
    • 好点。实际上,我只使用向量异常处理来捕获 STATUS_CRASH_DUMP 并绕过在这种情况下获得的错误窗口,转储有关触发它的异常的日志;我也不知道 ABI 问题,到目前为止,该解决方案运行良好。可悲的是,似乎没有真正通用的方法来解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 2011-10-27
    • 2017-11-25
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    相关资源
    最近更新 更多