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

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

问题描述

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

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

这工作正常。问题是,我有这么多非管理的方法调用,这是非常令人沮丧和重复的。所以,我尝试切换到这个:

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

哪个可以将所有这些调用一行:

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

然而,有两个立即的问题。首先,如果我的非托管方法使用 out 参数,我必须首先初始化局部变量,因为方法调用实际上在委托中。我想要简单地声明一个 out 目的地,而不进行初始化。



其次,如果一个例外是扔了,我真的不知道它来自哪里。调试器跳入 ApiCall 方法,堆栈跟踪仅显示包含调用 ApiCall 的方法,而不是委托自己因为我可以在一个方法中有很多API调用,所以调试困难。



然后我想到使用PostSharp将所有非托管调用包含错误代码检查,但我不知道如何使用 extern 方法完成。如果最终只是为每个人创建一个包装方法,那么我将会遇到与 ApiCall 方法相同的异常问题,对吧?另外,如果调试器只存在于编译程序集中,那么调试器如何知道如何在我的代码中显示抛出异常的站点?



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

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

现在我完全没有想法。还有其他一些方法可以解决这个问题?

解决方案

按照 ErrorHandler 从Visual Studio 2010 SDK它存在于早期版本中,但新版本具有 CallWithCOMConvention(Action) ,根据API与其他托管代码的互动情况,这可能很有价值。



在可用的方法中,我建议您执行以下操作:




  • 成功(int)

    Failed()只是!成功(),所以你可以


  • ThrowOnFailure(int)

    (抛出正确的异常对于您的退货代码)


  • CallWith_MyErrorCode_Convention(Action) CallWith_MyErrorCode_Convention(Func< ; int>)

    (如 CallWithCOMConvention ,但对于您的错误代码)


  • IsCriticalException(异常)

    (由$ code使用CallWith_MyErrorCode_Convention )



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());

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.

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.

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?

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?

解决方案

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:

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

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

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

  • IsCriticalException(Exception)
    (used by CallWith_MyErrorCode_Convention)

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

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