2013-07-10 13 views
6

Ich habeWie bekomme ich IntPtr zu einer Struktur?

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

Rect ist eine Methode mit der Signatur bekam eine Struktur, aber ich brauche auch der Anrufer weitergeben null (oder IntPtr.Zero) mit dem Verfahren zu ermöglichen.

Ich möchte dann mit der Unterschrift auf eine DLL abgehen

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

Ich hatte gehofft, ich etwas wie das folgende tun könnte:

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

Aber ich kann die Struktur nicht gegossen so wie das. Gibt es eine andere Möglichkeit, wie ich eine IntPtr daraus bekommen kann?


Es Alternative 4 Überlastungen zu schaffen:

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

die bekommen könnte noch unordentlicher, wenn ich jemals mehr als 2 struct Zeiger übergeben muss.


kam ich mit einer Lösung, aber ich habe einige Fragen zu diesem Thema:

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

Hätte ich ref Rect verwendet würde ich nicht gehabt haben Speicher für die Struktur zuzuordnen - was bedeutet, dass anders machen als das tut?


Ich habe etwas experimentiert. Die ref Rect Lösung läuft ungefähr in der gleichen Geschwindigkeit wie Umwandlung Rect in IntPtr Generierung einer IntPtr für eine Rect, die mich vermuten lässt, dass C# etwas sehr ähnliches unter der Haube tut, wenn Sie Refs verwenden. Sobald ich es zu einer Rect? mache und die bedingte Logik der Methode hinzufüge, läuft es bis zu 50% langsamer ... also wäre die Route mit 4 Überladungen wahrscheinlich die schnellste. Wir sprechen jedoch 100-150ms für 100K-Iterationen, was bedeutet, dass die Methode selbst sehr billig ist, weshalb die Konditionalitäten wahrscheinlich einen so bemerkenswerten Einfluss haben. Daher bleibe ich bei meiner benutzerdefinierten StructToPtr Lösung, da es die einfachste Lösung ist.

+0

Ihr Titel ist schlecht formuliert. Sie können eine Struktur nicht in IntPtr konvertieren. Sie können jedoch einen Zeiger auf eine Struktur erhalten. –

+0

@ JimMischel: True. Ich habe nicht darüber nachgedacht, es tatsächlich "umzuwandeln", ich dachte an etwas in der Art einer Besetzung; in C können Sie ein '&' vor eine Variable schlagen, um ihre Adresse zu erhalten. – mpen

Antwort

7

Sie möchten Marshal.StructureToPtr verwenden.

Sie müssen auch Speicher für die Struktur zuweisen und freigeben.

Ein guter Blog zum Thema finden sich hier bei http://www.developerfusion.com/article/84519/mastering-structs-in-c/

+0

Es erfordert 3 Parameter. Es scheint, ich muss Speicher dafür vorreservieren. – mpen

+0

Ja, tut mir leid. Ich habe die Antwort editiert und auf einen Blog hingewiesen. –

+0

Hat etwas mehr gesucht und ich denke, eine bessere Lösung finden Sie unter http://stackoverflow.com/questions/1049623/how-to-pass-a-nullable-type-to-ap-invoked-function –

-2

zu finden ist, was ich habe, ich bin eine API von einem M $ DLL und der Prototyp ist wie folgt:

HRESULT C_API(LPCWSTR name, PSTRUCT_WHATEVER *ppStruct); 

Die Struktur wird als solche definiert:

typedef struct whatever { 
    LPCWSTR x; 
    LPCWSTR y; 
} 

In C# ich bin folgendes definieren:

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

es zu benutzen:

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

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

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

An diesem Punkt mystring = "Dies ist ein String";