我正在与我需要获取的第三方库进行通信,并发布非托管资源。经过一些阅读后,我得出的结论是,管理资源引用的最佳和“正确”方式是SafeHandle
或CriticalHandle
对象。
我的问题出现了,因为第三方库返回的句柄是无符号短数字值而不是指针。如果我在返回的句柄上指定MarshalAsAttribute
,我会得到MarshalDirectiveException
(CriticalHandles不能设置MarshalAs属性,也不能在数组中使用。)
以下是我考虑过的事情:
CriticalHandle
方法将其包装在Criticalhandle.SetHandle
中。如果在获取引用和封装引用之间引发异常,这可能会泄漏句柄。CriticalFinalizerObject
。如果在获取引用和封装引用之间引发异常,这可能会泄漏句柄。SafeHandle
作为IntPtr
(让最重要的2个字节填充准垃圾)。每次我需要使用DangerousGetHandle
调用本机方法时,将SafeHandle
转换为简短(丢弃最重要的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
的导数。