在某些情况下需要一个空指针的P/Invoke签名中,如何使用SafeHandle?

8

希望这不会太难理解,以下是考虑P/Invoke签名的例子:

[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
    OdbcHandleType HandleType,
    IntPtr InputHandle,
    ref IntPtr OutputHandlePtr);

我希望重新设计这个签名,使用SafeHandles,如下所示:

[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
    OdbcHandleType HandleType,
    MySafeHandle InputHandle,
    ref MySafeHandle OutputHandlePtr);

然而,根据MSDN的说明,当HandleType参数为SQL_HANDLE_ENV时,InputHandle参数必须是空指针;否则,InputHandle参数必须是非空指针。

我该如何在一次P/Invoke调用中捕获这些语义?请在您的答案中包含一个示例调用站点。 我目前的解决方案是使用两个签名。

2个回答

3

SafeHandle 是一个类,因此您应该能够传递null而不是实际的SafeHandle。空引用会在P/Invoke中作为空指针进行转换。

SafeHandle handle = new SafeHandle();
OdbcResult result= SQLAllocHandle(OdbcHandleType.SQL_HANDLE_ENV, null, ref handle);

2
还可以声明一个 out SafeHandle 参数。 - Anton Tykhyy
5
这里无法工作,我从 System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success) 收到了一个“ArgumentNullException”异常。 - ordag
是的,@shf301,在P/Invoke调用中这不起作用。你试过了吗? - jnm2

2
shf301的回答中将null传递给了输入参数InputHandle。这在大多数API中是不起作用的(也许对于OP的特定问题,它会以某种方式起作用,因为他们接受了这个答案)。
我使用这个模式:
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public class RegionHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private RegionHandle() : base(true) {}

    public static readonly RegionHandle Null = new RegionHandle();

    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    override protected bool ReleaseHandle()
    {
        return Region.DeleteObject(handle);
    }
}

这意味着我可以通过传递一个空句柄来完成这个操作:
SomeApi(RegionHandle.Null);

这类似于存在一个IntPtr.Zero的静态成员。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接