Comment un SafeHandle peut être utilisé dans une signature P / Invoke qui nécessite un pointeur NULL dans certains cas?
Question
Espérons que cela ne soit pas trop obscur pour le SO, mais considère ce qui suit la signature P / Invoke:
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
OdbcHandleType HandleType,
IntPtr InputHandle,
ref IntPtr OutputHandlePtr);
Je voudrais redessiner cette signature à SafeHandles d'utilisation, comme suit:
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
OdbcHandleType HandleType,
MySafeHandle InputHandle,
ref MySafeHandle OutputHandlePtr);
Cependant, selon MSDN , l'argument InputHandle doit être un pointeur null lorsque l'argument HandleType est SQL_HANDLE_ENV et un pointeur non nul par ailleurs.
Comment capturer cette sémantique dans un seul P / Invoke signature? S'il vous plaît inclure un appel-site par exemple dans votre réponse. Ma solution actuelle est d'utiliser deux signatures.
La solution
SafeHandle
est une classe de sorte que vous devriez être en mesure de passer null
plutôt que d'une réelle SafeHandle
. Une référence nulle est assemblée comme un pointeur null P / Invoke.
SafeHandle handle = new SafeHandle();
OdbcResult result= SQLAllocHandle(OdbcHandleType.SQL_HANDLE_ENV, null, ref handle);
Autres conseils
La réponse par shf301 passe null
pour l'argument d'entrée InputHandle
. Cela ne fonctionne pas sur la plupart des API (peut-être le fait d'une certaine manière pour le problème spécifique de l'OP, étant donné qu'ils ont accepté la réponse).
J'utilise ce modèle:
[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);
}
}
Cela signifie que je peux le faire pour passer une poignée nulle:
SomeApi(RegionHandle.Null);
Il est similaire à la façon dont il est un membre statique IntPtr.Zero
.