Exception handling 如何处理导致异常的WinRT异常?

Exception handling 如何处理导致异常的WinRT异常?,exception-handling,windows-runtime,hresult,Exception Handling,Windows Runtime,Hresult,如果Windows运行时类型引发COM错误,则.NET似乎经常(或总是?)将此错误包装到异常实例中。错误消息包括COM HRESULT错误代码。例如,当将新的加密API与AES-CBC一起使用时,错误的缓冲区长度会导致出现异常,消息为“提供的用户缓冲区对于请求的操作无效。(来自HRESULT的异常:0x800706F8)” 那么,我们应该如何处理这些例外情况呢?我们是否应该阅读异常中的HRESULT代码来了解这是一种什么样的异常?在classic.NET中,我会得到一个加密异常,可以用来区分加密

如果Windows运行时类型引发COM错误,则.NET似乎经常(或总是?)将此错误包装到
异常
实例中。错误消息包括COM HRESULT错误代码。例如,当将新的加密API与AES-CBC一起使用时,错误的缓冲区长度会导致出现异常,消息为“提供的用户缓冲区对于请求的操作无效。(
来自HRESULT的异常:0x800706F8
)”

那么,我们应该如何处理这些例外情况呢?我们是否应该阅读异常中的
HRESULT
代码来了解这是一种什么样的异常?在classic.NET中,我会得到一个
加密异常
,可以用来区分加密错误和其他错误

另一件我不明白的事情是,微软的代码质量规则规定,永远不应该抛出异常,而应该始终抛出派生类型。原因是,不应强迫任何人捕获一般的
异常
,该异常也会捕获更致命的异常,如
OutOfMemoryException
。另一条规则说,一个人永远不应该在图书馆里发现异常。如果我们被迫在Windows应用商店应用程序或WinRT库中捕获
异常
,我们如何遵循这些策略


顺便说一下:。我假设捕获
异常
不再是坏代码。

可以捕获
异常
,通过打开HRESULT来处理特定错误,如果错误是“意外的”,则重新抛出
异常

try
{
    // ...
}
catch (Exception ex)
{
    switch (ex->HResult)
    {
    case E_INVALID_USER_BUFFER: // 0x800706f8
        // handle invalid buffer case...
        break;
    default:
        // Unexpected exception; re-throw:
        throw;
    }
}
static void HandleKnownExceptions(Action f)
{
    try
    {
        f();
    }
    catch (Exception ex)
    {
        // Detect expected HRESULTs and throw the more-specific exception
        // type for each.
    }
}
(我注意到,提供无效缓冲区听起来更像是一个逻辑错误,而不是运行时错误,所以我想知道是否真的应该捕获这个特定的异常。)

或者,更通用的解决方案是编写一个函数或一组函数来处理已知HRESULT的异常,并重新抛出更具体的异常。比如说,

try
{
    // ...
}
catch (Exception ex)
{
    switch (ex->HResult)
    {
    case E_INVALID_USER_BUFFER: // 0x800706f8
        // handle invalid buffer case...
        break;
    default:
        // Unexpected exception; re-throw:
        throw;
    }
}
static void HandleKnownExceptions(Action f)
{
    try
    {
        f();
    }
    catch (Exception ex)
    {
        // Detect expected HRESULTs and throw the more-specific exception
        // type for each.
    }
}

这两种方法在C++和C语言中都同样适用。


请注意,
异常
不一定是由平台或其他组件直接引发的。在Windows运行时ABI层,没有例外:所有错误都由HRESULT跨ABI边界报告。CLR将少数已知的HRESULT转换为更具体的异常类型,但无法执行一般转换。

对于链接的博客条目,列出的许多“致命”异常无法被托管代码捕获。值得注意的是,
StackOverflowException
,尽管我相当肯定AVs也不能被捕获(当然,两者都可以在本机代码中捕获,但这样做是危险的)。还要注意的是,有些看似致命的异常事实上可能并非如此。例如,当特定缓冲区中的空间耗尽时,许多COM组件返回
E_OUTOFMEMORY
。此HRESULT将被转换为OutOfMemoryException,但这并不意味着进程已耗尽其全部地址空间。这似乎是将非托管世界与托管世界混合的结果,可悲的是(至少他们可以声明类ComException:Exception。谢谢James。这是我捕获无效缓冲区HRESULT的方法。我觉得有点奇怪,.NET程序员现在必须处理HRESULT。当试图解密无效数据时,很容易得到无效缓冲区,这些无效数据可能已经过处理或只是被裁剪过。我认为ink表示,几乎不可能检查加密数据的正确长度,因为这取决于所使用的算法和密钥。要找出所使用的块大小已经很难了。捕获无效缓冲区错误对于确保以用户友好的方式处理无效数据至关重要。啊,我的错误。我误解了缓冲区是什么无效。您是对的,处理此类错误是一个好主意:-)