1

我正在与需要获取和释放非托管资源的第三方库进行通信。经过一番阅读,我得出结论,管理资源引用的最佳和“正确”方法是在 aSafeHandleCriticalHandleobject 中。

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

以下是我考虑过的事情:

  • 以数字格式编组句柄并CriticalHandle通过Criticalhandle.SetHandle方法将它们包装在 a 中。如果在获取引用和封装它之间引发异常,这可能会泄漏句柄。
  • 以数字格式编组和存储句柄。具有包含类型的实现CriticalFinalizerObject。如果在获取引用和封装它之间引发异常,这可能会泄漏句柄。
  • 将句柄编组为 a SafeHandleIntPtr让最重要的 2 个字节填充准垃圾)。每次DangerousGetHandle我需要调用带有SafeHandle. 这将防止手柄的任何潜在泄漏,但非常麻烦并且看起来使用蛮力使错误的解决方案起作用。

我应该如何处理这些“把手”?

4

2 回答 2

2

我认为正确的做法是实现您自己的包装器,类似于SafeHandle( 并派生自. 然后包装对 P/Invoke 方法的调用,该方法在受约束的执行区域CriticalFinalizerObject中创建句柄,以确保托管句柄包装器被正确初始化。

注意:我以前没有使用过 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;
}
于 2012-07-04T16:09:03.323 回答
1

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

如果您的本机代码是 32 位,您可以使 SafeHandle 工作。在 C 或 C++ 函数调用中,短参数总是被提升为 int。IntPtr 不会混淆它。– 汉斯帕桑特 7 月 4 日 15:10

因此,可以将 C/C++ unsigned short 直接编组为SafeHandle.

于 2012-07-18T14:49:53.547 回答