You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在HoloLens上捕获UWP编译原生代码抛出的SEH异常

问题

我尝试在HoloLens的C#函数中捕获由编译为UWP的C++原生代码抛出的SEH异常。开发环境为Visual Studio,通过Interface Definition (IDL)文件生成.winmd库,无需使用dll import或extern "C"即可与C#代码链接。

我已在VS中配置原生代码的"Enable C++ Exception"为"Yes with SEH Exceptions (/EHa)",但在HoloLens上运行应用时,仅index == 1的异常能被捕获,其余异常会导致应用崩溃。我希望能像在C++中用catch (...)或.NET 4.0之前版本那样捕获这些异常,请问为何无法实现?

原生C++代码

// h file
namespace NativeSEHException
{
   void Foo(int index);
}

// cpp file
#include "NativeSEHException.h"
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

void NativeSEHException::Foo(int index)
{
    static int i = index; // first call will be with index == 0
    if (index == 0)
        {
            std::cout << "throw std::exception\n";
            throw std::bad_exception();
            // This section works, since it's not an SEH exception
        }
        else if (index == 1)
        {
            std::cout << "divide by zero\n";
            int y = 8 / i;
            std::cout << y << '\n';
        }
        else if (index == 2)
        {
            std::cout << "Access nullptr\n";
            int* p = nullptr;
            int y = 8 + *p;
            std::cout << y << '\n';
        }
        else if (index == 3)
        {
            std::cout << "access empty cv::Mat\n";
            cv::Mat mat;
            std::cout << mat.at<float>(0, 3) << '\n';
        }
        else if (index == 4)
        {
            std::cout << "vector out of range access\n";
            std::vector<float> v;
            std::cout << v[500000] << '\n';
        }
}

C#代码

using System;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
using UnityEngine;

public class MyClass : MonoBehaviour
{
    [HandleProcessCorruptedStateExceptions]
    [SecurityCritical]
    public void ExceptionCatcher()
    {
        for (int i = 0; i < 5; i++)
        {
            try
            {
                NativeSEHException.Foo(i);
            }
            catch (SEHException e)
            {
                Debug.Log($"Caught a SEH exception: {e}");
            }
            catch (Exception e)
            {
                Debug.Log($"Caught a general Exception: {e}");
            }
            catch
            {
                Debug.Log($"Caught something else");
            }
        }
    }
}
解答

核心原因:UWP平台的安全限制与异常处理机制差异

  1. UWP进程保护机制拦截严重异常
    HoloLens运行的UWP应用有严格的进程完整性保护,空指针访问、内存越界这类SEH异常属于进程损坏状态异常(CSEs)。UWP默认会直接终止进程,不会允许托管代码捕获这类可能导致进程不稳定的异常——即使添加[HandleProcessCorruptedStateExceptions]和[SecurityCritical]也无效,这两个特性在UWP平台被限制,无法生效。

  2. /EHa的作用范围仅限C++内部
    配置的/EHa仅让C编译器能同时处理C异常和SEH异常,但该特性仅在C代码内部有效。当异常跨越C原生代码到C#托管代码的边界时,UWP运行时会拦截严重异常,禁止其传递到托管层。

  3. 不同异常的兼容性差异

  • index=0:抛出的std::bad_exception属于C++标准异常,是可序列化的托管兼容异常,能通过winmd边界传递到C#,因此可以被捕获。
  • index=1:除零错误是UWP中少数允许传递的SEH异常,属于特例,并非所有SEH异常都能通过。
  • index=2/3/4:空指针访问、OpenCV空Mat访问、vector越界触发的是STATUS_ACCESS_VIOLATION这类严重异常,UWP运行时会直接终止进程,不会让托管代码捕获。

可行解决方案

  1. 在C++层统一处理所有异常
    既然UWP不允许托管层捕获严重SEH异常,最可靠的方式是在C代码内部用catch (...)捕获所有异常,将异常信息转换为C/CX的Exception或自定义错误码后传递给C#:
#include <Windows.h>
#include <exception>
#include <stdexcept>
#include <platform.h>

void NativeSEHException::Foo(int index)
{
    try
    {
        static int i = index;
        // 原有逻辑代码
    }
    catch (const std::exception& e)
    {
        throw ref new Platform::Exception(E_FAIL, ref new Platform::String(e.what()));
    }
    catch (...)
    {
        DWORD errorCode = GetLastError();
        throw ref new Platform::Exception(errorCode, L"Native SEH exception occurred");
    }
}

这样C#就能通过捕获System.Exception接收所有异常信息。

  1. 从源头避免严重异常
    在C++代码中提前做参数校验与状态检查:
  • 访问指针前判空
  • vector访问前检查索引是否在有效范围内
  • OpenCV操作前检查Mat是否非空(mat.empty())
    从源头避免严重SEH异常的发生,比事后捕获更可靠。

内容的提问来源于stack exchange,提问作者Idan Cohen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 15:08:11