How can a SafeHandle be used in a P/Invoke signature that requires a null pointer in certain cases?

StackOverflow https://stackoverflow.com/questions/8370016

  •  27-10-2019
  •  | 
  •  

Hopefully this isn't too obscure for SO, but consider the following P/Invoke signature:

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

I'd like to redesign this signature to use SafeHandles, as follows:

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

However, according to MSDN, the InputHandle argument must be a null pointer when the HandleType argument is SQL_HANDLE_ENV and a non-null pointer otherwise.

How do I capture those semantics in a single P/Invoke signature? Please include an example call-site in your answer. My current solution is to use two signatures.

有帮助吗?

解决方案

SafeHandle is a class so you should be able to pass null rather than an actual SafeHandle. A null reference is marshaled as a null pointer in P/Invoke.

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

其他提示

The answer by shf301 passes null for the input argument InputHandle. This doesn't work on most APIs (maybe it somehow does for the OP's specific problem, given that they accepted the answer).

I use this pattern:

[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);
    }
}

It means I can do this to pass a null handle:

SomeApi(RegionHandle.Null);

It's similar to how there's an IntPtr.Zero static member.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top