在非托管 API 中统一处理错误代码 [英] Uniformly handling error codes in an unmanaged API

查看:31
本文介绍了在非托管 API 中统一处理错误代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一个相当大的非托管 API 编写一个包装器.几乎每个导入的方法在失败时都会返回一个常见的错误代码.现在,我正在这样做:

I'm writing a wrapper around a fairly large unmanaged API. Almost every imported method returns a common error code when it fails. For now, I'm doing this:

ErrorCode result = Api.Method();
if (result != ErrorCode.SUCCESS) {
    throw Helper.ErrorToException(result);
}

这很好用.问题是,我有太多的非托管方法调用,这变得非常令人沮丧和重复.所以,我尝试切换到这个:

This works fine. The problem is, I have so many unmanaged method calls that this gets extremely frustrating and repetitive. So, I tried switching to this:

public static void ApiCall(Func<ErrorCode> apiMethod) {
    ErrorCode result = apiMethod();
    if (result != ErrorCode.SUCCESS) {
        throw Helper.ErrorToException(result);
    }
}

这让我可以将所有这些呼叫减少到一行:

Which allows me to cut down all of those calls to one line:

Helper.ApiCall(() => Api.Method());

然而,这有两个直接的问题.首先,如果我的非托管方法使用 out 参数,我必须首先初始化局部变量,因为方法调用实际上是在委托中.我希望能够简单地声明一个 out 目的地而不初始化它.

There are two immediate problems with this, however. First, if my unmanaged method makes use of out parameters, I have to initialize the local variables first because the method call is actually in a delegate. I would like to be able to simply declare a out destination without initializing it.

第二,如果抛出异常,我真的不知道它是从哪里来的.调试器跳转到 ApiCall 方法,堆栈跟踪只显示包含对 ApiCall 调用的方法,而不是委托本身.由于我可以在一个方法中调用多个 API,这使得调试变得困难.

Second, if an exception is thrown, I really have no idea where it came from. The debugger jumps into the ApiCall method and the stack trace only shows the method that contains the call to ApiCall rather than the delegate itself. Since I could have many API calls in a single method, this makes debugging difficult.

然后我考虑使用 PostSharp 用错误代码检查来包装所有非托管调用,但我不确定如何使用 extern 方法来完成.如果它最终只是为它们中的每一个创建一个包装器方法,那么我将遇到与 ApiCall 方法相同的异常问题,对吗?另外,如果它只存在于编译的程序集中,调试器如何知道如何在我的代码中向我显示抛出异常的位置?

I then thought about using PostSharp to wrap all of the unmanaged calls with the error code check, but I'm not sure how that would be done with extern methods. If it ends up simply creating a wrapper method for each of them, then I would have the same exception problem as with the ApiCall method, right? Plus, how would the debugger know how to show me the site of the thrown exception in my code if it only exists in the compiled assembly?

接下来,我尝试实现一个自定义封送拆收器,它会拦截 API 调用的返回值并检查那里的错误代码.不幸的是,您不能应用自定义封送拆收器来返回值.但我认为如果有效,那将是一个非常干净的解决方案.

Next, I tried implementing a custom marshaler that would intercept the return value of the API calls and check the error code there. Unfortunately, you can't apply a custom marshaler to return values. But I think that would have been a really clean solution it if had worked.

[return:
    MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ApiMethod))]
public static extern ErrorCode Method();

现在我完全没有想法了.我还有什么其他方法可以处理这个问题?

Now I'm completely out of ideas. What are some other ways that I could handle this?

推荐答案

遵循 ErrorHandler 类来自 Visual Studio 2010 SDK.它存在于早期版本中,但新版本具有 CallWithCOMConvention(Action),这可能会被证明是有价值的,具体取决于您的 API 如何与其他托管代码交互.

Follow ErrorHandler class from the Visual Studio 2010 SDK. It existed in earlier versions, but the new one has CallWithCOMConvention(Action), which may prove valuable depending on how your API interacts with other managed code.

在可用的方法中,我建议实施以下方法:

Of the available methods, I recommend implementing the following:

  • 成功(int)
    (Failed() 就是 !Succeeded(),所以你可以跳过它)

  • Succeeded(int)
    (Failed() is just !Succeeded(), so you can skip it)

ThrowOnFailure(int)
(为您的返回代码抛出一个适当的异常)

ThrowOnFailure(int)
(Throws a proper exception for your return code)

CallWith_MyErrorCode_Convention(Action)CallWith_MyErrorCode_Convention(Func)
(类似于 CallWithCOMConvention,但对于您的错误代码)

CallWith_MyErrorCode_Convention(Action) and CallWith_MyErrorCode_Convention(Func<int>)
(like CallWithCOMConvention, but for your error codes)

IsCriticalException(Exception)
(由 CallWith_MyErrorCode_Convention 使用)

这篇关于在非托管 API 中统一处理错误代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆