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

本文关键字:Invoke SafeHandle 何使用 情况下 空指针 | 更新日期: 2023-09-27 18:16:29

希望这对SO来说不是太晦涩,但是考虑以下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参数必须为空指针,否则为非空指针。

如何在单个p/Invoke签名中捕获这些语义?请在你的回答中包括一个呼叫地点的例子。我目前的解决方案是使用两个签名。

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

SafeHandle是一个类,所以你应该能够通过null而不是实际的SafeHandle。空引用在P/Invoke中被封送为空指针。

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

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静态成员很像