2013-07-10 13 views
6

Io ho un metodo con la firmaCome ottenere un IntPtr in una struct?

public int Copy(Texture texture, Rect? srcrect, Rect? dstrect) 

Rect è una struttura, ma ho bisogno di consentire al chiamante di passare null (o IntPtr.Zero) al metodo pure.

Voglio poi farlo passare a una DLL con la firma

[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_RenderCopy")] 
internal static extern int RenderCopy(IntPtr renderer, IntPtr texture, IntPtr srcrect, IntPtr dstrect); 

speravo avrei potuto fare qualcosa di simile al seguente:

return SDL.RenderCopy(_ptr, texture._ptr, srcrect.HasValue ? (IntPtr)srcrect.Value : IntPtr.Zero, dstrect.HasValue ? (IntPtr)dstrect.Value : IntPtr.Zero); 

Ma non riesco a lanciare lo struct come quello. C'è un altro modo in cui posso ottenere un IntPtr?


Ci

alternativa è quella di creare 4 sovraccarichi:

  • ref Rect, ref Rect
  • IntPtr, IntPtr
  • ref Rect, IntPtr
  • IntPtr, ref Rect

che potrebbe ottenere anche più caotico se ho mai bisogno di passare più di 2 puntatori di struttura.


mi si avvicinò con una soluzione, ma ho alcune domande su di esso:

public int Copy(Texture texture, Rect? srcrect=null, Rect? dstrect=null) 
{ 
    return SDL.RenderCopy(_ptr, texture._ptr, srcrect.HasValue ? StructToPtr(srcrect) : IntPtr.Zero, dstrect.HasValue ? StructToPtr(dstrect) : IntPtr.Zero); 
} 

private static IntPtr StructToPtr(object obj) 
{ 
    var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj)); 
    Marshal.StructureToPtr(obj, ptr, false); 
    return ptr; 
} 

se avessi usato ref Rect non avrei dovuto allocare memoria per la struct - cosa fare diversamente da questo?


Ho fatto qualche sperimentazione. La soluzione ref Rect corre più o meno alla stessa velocità di conversione di una Rect a un IntPtr generando un IntPtr per un Rect, che mi porta a sospettare che C# sta facendo qualcosa di molto simile sotto il cofano quando si utilizza rif. Non appena eseguo il comando Rect? e aggiungo la logica condizionale al metodo che esegue fino al 50% più lento ... quindi il percorso a 4 sovraccarichi sarebbe probabilmente il più veloce. Tuttavia, stiamo parlando di 100-150 ms per 100.000 iterazioni, il che significa che il metodo stesso è super economico, il che probabilmente è il motivo per cui i condizionali hanno un impatto così notevole. In quanto tale, mi sto attenendo alla mia soluzione personalizzata StructToPtr in quanto è la soluzione più semplice.

+0

Il tuo titolo non è valido. Non è possibile convertire una struttura in un IntPtr. È possibile, tuttavia, ottenere un puntatore a una struttura. –

+0

@ JimMischel: vero. Non stavo pensando di "convertirlo" realmente, stavo pensando a qualcosa sulla falsariga di un cast; in C puoi schiaffeggiare un '&' prima di una variabile per ottenere il suo indirizzo. – mpen

risposta

7

Si desidera utilizzare Marshal.StructureToPtr.

Sarà inoltre necessario allocare e deallocare la memoria per la struttura.

un buon blog su questo argomento sono disponibili all'indirizzo http://www.developerfusion.com/article/84519/mastering-structs-in-c/

+0

Richiede 3 parametri. Sembra che devo preallocare la memoria per questo. – mpen

+0

Sì, mi dispiace per quello. Ho modificato la risposta e ti ho indirizzato a un blog. –

+0

Ho fatto qualche ricerca in più e penso che una soluzione migliore possa essere trovata su http://stackoverflow.com/questions/1049623/how-to-pass-a-nullable-type-to-ap-invoked-function –

-2

Ecco quello che ho, sto usando un'API da un M $ DLL e il prototipo è come questo:

HRESULT C_API(LPCWSTR name, PSTRUCT_WHATEVER *ppStruct); 

Il struttura è definita come tale:

typedef struct whatever { 
    LPCWSTR x; 
    LPCWSTR y; 
} 

In C# sto definendo i seguenti:

[StructLayout(LayoutKind.Sequential)] 
public class WHATEVER { 
    public IntPtr x; 
    public IntPtr y; 
} 

[DllImport("msdll.dll", SetLastError=false, CharSet=CharSet.Unicode)] 
    public static extern long C_API(String name, out IntPtr ppStruct); 

usarlo:

IntPtr s;   
long HR = C_API("myname", out s); 

WHATEVER pInfo = (WHATEVER) Marshal.PtrToStructure(s, typeof(WHATEVER)); 

String mystring = Marshal.PtrToStringAuto(pInfo.x); 

A questo punto mystring = "questa è una stringa";

Problemi correlati