Как можно использовать 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
статический член.