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