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

时间:2011-12-03 18:44:38

标签: c# pinvoke dllimport cer

希望这对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);

但是,according to MSDN,当HandleType参数为SQL_HANDLE_ENV时,InputHandle参数必须为空指针,否则为非空指针。

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

2 个答案:

答案 0 :(得分:4)

SafeHandle是一个类,因此您应该能够传递null而不是实际的SafeHandle。空引用在P / Invoke中被编组为空指针。

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

答案 1 :(得分:1)

The answer by 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静态成员。