c# null interop pinvoke optional-parameters

¿Cómo manejo los parámetros de estructura dll opcionales o nulos en C#?



null interop (1)

¿Cómo trato con argumentos de struct opcionales en métodos dll llamados desde C # usando pinvoke? Por ejemplo, el parámetro lpSecurityAttributes aquí debe pasar null cuando está ausente.

La forma correcta de pasar struct parece estar usando ref , pero no puede tener parámetros opcionales, o tomar null en general.

¿Qué formas hay para lograr esto?


Tienes pocas opciones

1) Use una class lugar de una struct

Creo que este método es el más fácil. Simplemente declare la struct como una class :

[StructLayout(LayoutKind.Sequential)] public class CStruct { //member-list }

y luego declara tu método:

[DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(CStruct cStruct, ...);

Si su parámetro opcional es el último, puede usar CStruct cStruct = null como parámetro. Esto le permite excluirlo en lugar de pasar null explícitamente. También puede escribir un método de envoltura que use esto y garantice que los parámetros opcionales sean los últimos.

2) Use IntPtr e IntPtr.Zero

Usa una struct :

[StructLayout(LayoutKind.Sequential)] public struct CStruct { //member-list }

y declara tu método como:

[DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(IntPtr cStruct, ...);

En el caso no null , reúna la estructura en un puntero y llame al método:

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CStruct))); try{ Marshal.StructureToPtr(myCStruct, ptr, false); DLLFunction(ptr, ...); } finally { Marshal.FreeHGlobal(ptr); }

En el caso null , llame al método con IntPtr.Zero :

DLLFunction(IntPtr.Zero, ...);

Una vez más, puede hacer que este parámetro sea opcional si resulta ser el último de la lista (o si usa un contenedor para hacerlo). Haga esto utilizando IntPtr cStruct = default(IntPtr) como parámetro. (De default(IntPtr) crea un IntPtr.Zero ).

3) Sobrecargue su método para evitar la clasificación

Use una struct como en 2) .

Simplemente declare una opción para el caso no null :

[DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(ref cStruct, ...);

y otro para el caso null :

[DllImport("mydll.dll", OptionName = optionValue, ...)] static extern int DLLFunction(IntPtr cStruct, ...);

El primer método se llamará automáticamente al pasar una struct , y el segundo al pasar IntPtr.Zero . Si declara la versión IntPtr con un parámetro opcional (como se muestra en la parte inferior de 2) arriba), lo llamará automáticamente cuando excluya el parámetro cStruct .

4) Punteros crudos usando unsafe

Use una estructura como en 2) y declare su método (observe la palabra clave unsafe ):

[DllImport("mydll.dll", OptionName = optionValue, ...)] static unsafe extern int DLLFunction(CStruct* cStruct, ...);

En el caso no null , pasa &myCStruct , y simplemente null en el caso null . Como en 1) , si este parámetro opcional es el último, puede declarar el parámetro como CStruct* cStruct = null para pasar automáticamente null cuando se excluye cStruct .

Gracias a @dialer por sugerir este método.