Come gestisco i parametri null o facoltativi della struct dll in C #

Come faccio a gestire gli argomenti struct facoltativi nei metodi dll chiamati da C # usando pinvoke? Ad esempio, il parametro lpSecurityAttributes deve essere passato null quando assente.

Il modo corretto di passare struct ‘s sembra utilizzare ref , ma non può avere parametri opzionali, o prendere null in generale.

Quali sono i modi per raggiungere questo objective?

Hai alcune opzioni

1) Usa una class invece di una struct

Penso che questo metodo sia il più facile. Dichiara semplicemente la struct come una class :

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

e quindi dichiara il tuo metodo:

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

Se il parametro facoltativo sembra essere l’ultimo, è ansible utilizzare CStruct cStruct = null come parametro. Questo ti permette di escluderlo invece di passare null esplicito. Puoi anche scrivere un metodo wrapper che lo utilizza e garantisce che i parametri opzionali arrivino per ultimi.

2) Usa IntPtr e IntPtr.Zero

Usa una struct :

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

e dichiara il tuo metodo come:

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

Nel caso non null , effettuare il marshalling della struct su un puntatore e chiamare il metodo:

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

Nel caso null , chiama il metodo con IntPtr.Zero :

 DLLFunction(IntPtr.Zero, ...); 

Di nuovo, puoi rendere questo parametro opzionale se questo è l’ultimo della lista (o usi un wrapper per renderlo tale). A tale scopo, utilizzare IntPtr cStruct = default(IntPtr) come parametro. (Come default(IntPtr) crea un IntPtr.Zero .)

3) Sovraccaricare il metodo per evitare il marshalling

Usa una struct come in 2) .

Dichiara semplicemente un’opzione per il caso non null :

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

e un altro per il caso null :

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

Il primo metodo verrà chiamato automaticamente quando si passa una struct e il secondo quando si passa a IntPtr.Zero . Se si dichiara la versione IntPtr con un parametro facoltativo (come mostrato nella parte inferiore di 2) sopra), lo chiamerà automaticamente quando si esclude il parametro cStruct .

4) Puntatori grezzi che utilizzano unsafe

Usa una struct come in 2) e dichiara il tuo metodo (nota la parola chiave unsafe ):

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

Nel caso non null , si passa &myCStruct e semplicemente null nel caso null . Come in 1) , se questo parametro opzionale è l’ultimo, è ansible dichiarare il parametro come CStruct* cStruct = null per passare automaticamente null quando cStruct è escluso.

Grazie a @dialer per aver suggerito questo metodo.