编组SafeHandle的unsigned short

时间:2012-07-04 14:14:43

标签: .net .net-4.0 interop marshalling

我正在与我需要获取的第三方库进行通信,并发布非托管资源。经过一些阅读后,我得出的结论是,管理资源引用的最佳和“正确”方式是SafeHandleCriticalHandle对象。

我的问题出现了,因为第三方库返回的句柄是无符号短数字值而不是指针。如果我在返回的句柄上指定MarshalAsAttribute,我会得到MarshalDirectiveException(CriticalHandles不能设置MarshalAs属性,也不能在数组中使用。)

以下是我考虑过的事情:

  • 以数字格式标记句柄,并通过CriticalHandle方法将其包装在Criticalhandle.SetHandle中。如果在获取引用和封装引用之间引发异常,这可能会泄漏句柄。
  • Marshal并以数字格式存储句柄。包含类型实现CriticalFinalizerObject。如果在获取引用和封装引用之间引发异常,这可能会泄漏句柄。
  • 将句柄标记为SafeHandle作为IntPtr(让最重要的2个字节填充准垃圾)。每次我需要使用DangerousGetHandle调用本机方法时,将SafeHandle转换为简短(丢弃最重要的2个字节的垃圾)。这样可以防止手柄发生任何潜在的泄漏,但是非常麻烦,并且使用蛮力来解决错误的解决方案。

我该如何处理这些'手柄'?

2 个答案:

答案 0 :(得分:2)

我认为正确的做法是实现类似于SafeHandle的自己的包装器(并从CriticalFinalizerObject派生。)然后将调用包装到P / Invoke方法中,该方法在{ {3}}以确保托管句柄包装器已正确初始化。

注意:我之前没有使用CER,所以如果没有验证,我只能希望此代码为您提供一个起点。

[DllImport("blah.dll")]
private static extern ushort CreateMySpecialHandle();

public static SafeSpecial Handle Foo()
{
    SafeSpecialHandle safeHandle = new SafeSpecialHandle();
    System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
    }
    finally
    {
        ushort rawHandle = CreateMySpecialHandle();
        safeHandle.SetHandle(rawHandle);
    }

    if (safeHandle.IsInvalid)
    {
        // throw exception here, or other error handling
    }

    return safeHandle;
}

答案 1 :(得分:1)

正如@HansPassant在对我的问题的评论中提到的那样:

  

如果您的本机代码是32位,则可以使SafeHandle正常工作。简短   参数总是在C或C ++函数调用中被提升为int。该   IntPtr不会混淆它。 - Hans Passant 7月4日15:10

因此可以将C / C ++无符号短整数直接编组为SafeHandle的导数。