¿Cómo se puede usar un SafeHandle en una firma P/Invoke que requiere un puntero nulo en ciertos casos?

StackOverflow https://stackoverflow.com/questions/8370016

  •  27-10-2019
  •  | 
  •  

Pregunta

Esperemos que esto no sea demasiado oscuro para así, pero considere la siguiente firma P/Invoke:

[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
    OdbcHandleType HandleType,
    IntPtr InputHandle,
    ref IntPtr OutputHandlePtr);

Me gustaría rediseñar esta firma para usar SafeHandles, de la siguiente manera:

[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
internal static extern OdbcResult SQLAllocHandle(
    OdbcHandleType HandleType,
    MySafeHandle InputHandle,
    ref MySafeHandle OutputHandlePtr);

Sin embargo, Según MSDN, el argumento de inPuthandle debe ser un puntero nulo cuando el argumento del handletype es sql_handle_env y un puntero no nulo de otra manera.

¿Cómo captura esos semánticos en una sola firma P/Invoke? Incluya un ejemplo de sitio de llamada en su respuesta. Mi solución actual es usar dos firmas.

¿Fue útil?

Solución

SafeHandle es una clase, por lo que deberías poder pasar null en lugar de un real SafeHandle. Una referencia nula se somete a un puntero nulo en P/Invoke.

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

Otros consejos

La respuesta de shf301 pases null Para el argumento de entrada InputHandle. Esto no funciona en la mayoría de las API (tal vez de alguna manera lo hace para el problema específico del OP, dado que aceptaron la respuesta).

Yo uso este patrón:

[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);
    }
}

Significa que puedo hacer esto para pasar un mango nulo:

SomeApi(RegionHandle.Null);

Es similar a cómo hay un IntPtr.Zero Miembro estático.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top