¿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.