Как можно использовать SafeHandle в подписи P/Invoke, для которой в некоторых случаях требуется нулевой указатель?

Надеюсь, для 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, аргумент InputHandle должен быть нулевым указателем, если аргумент HandleType равен SQL_HANDLE_ENV, а в противном случае - ненулевой указатель.

Как мне захватить эту семантику в одной подписи P/Invoke? Пожалуйста, включите пример call-сайта в ваш ответ. Мое текущее решение - использовать две подписи.

2 ответа

Решение

SafeHandle это класс, так что вы должны быть в состоянии пройти null а не фактический SafeHandle, Пустая ссылка маршалируется как нулевой указатель в P/Invoke.

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

Ответ по shf301 проходит null для входного аргумента InputHandle, Это не работает на большинстве API (возможно, это как-то работает для конкретной проблемы ОП, учитывая, что они приняли ответ).

Я использую этот шаблон:

[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 статический член.

Другие вопросы по тегам