Wie kann ein SaferHandle in einer P/Invoke -Signatur verwendet werden, die in bestimmten Fällen einen Nullzeiger erfordert?
Frage
Hoffentlich ist dies für SO nicht zu dunkel, aber betrachten Sie die folgende P/Invoke -Signatur:
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
OdbcHandleType HandleType,
IntPtr InputHandle,
ref IntPtr OutputHandlePtr);
Ich möchte diese Signatur für die Verwendung von SafeHandles wie folgt neu gestalten:
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
OdbcHandleType HandleType,
MySafeHandle InputHandle,
ref MySafeHandle OutputHandlePtr);
Jedoch, Laut MSDN, Das Inputhandle-Argument muss ein Nullzeiger sein, wenn das Handletyp-Argument sql_handle_env und sonst ein Nicht-Null-Zeiger ist.
Wie erfasse ich diese Semantik in einer einzigen P/Invoke -Signatur? Bitte geben Sie eine Beispielanruf-Site in Ihre Antwort an. Meine aktuelle Lösung ist es, zwei Signaturen zu verwenden.
Lösung
SafeHandle
ist eine Klasse, also sollten Sie in der Lage sein, passieren zu können null
eher als eine tatsächliche SafeHandle
. Eine Nullreferenz wird als Nullzeiger in P/Invoke marschiert.
SafeHandle handle = new SafeHandle();
OdbcResult result= SQLAllocHandle(OdbcHandleType.SQL_HANDLE_ENV, null, ref handle);
Andere Tipps
Die Antwort von SHF301 geht vorbei null
für das Eingabebuch InputHandle
. Dies funktioniert nicht bei den meisten APIs (vielleicht tut es irgendwie für das spezifische Problem des OP, da sie die Antwort akzeptiert haben).
Ich benutze dieses Muster:
[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);
}
}
Es bedeutet, dass ich dies tun kann, um einen Nullgriff zu bestehen:
SomeApi(RegionHandle.Null);
Es ist ähnlich, wie es eine gibt IntPtr.Zero
Statisches Mitglied.