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

Надеюсь, для 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? Пожалуйста, включите пример колл-сайта в ваш ответ. Мое текущее решение - использовать две подписи.

Ответы [ 2 ]

4 голосов
/ 03 декабря 2011

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

SafeHandle handle = new SafeHandle();
OdbcResult result= SQLAllocHandle(OdbcHandleType.SQL_HANDLE_ENV, null, ref handle);
1 голос
/ 09 декабря 2013

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

...