2010-12-16 4 views
3

Mein struct in C starten ++ ist die folgendeIch versuche, eine Struktur von C auf C# Marschall, nicht sicher, wo

/* this structure contains the xfoil output parameters vs angle of attack */ 
    typedef struct xfoil_outputdata_struct 
    { 
    double *pAlfa; 
    double *pCL; 
    double *pCM; 
    double *pCDi; 
    double *pCDo; 
    double *pCPmax; 
    long nEntries; 
    } XFOIL_OUTPUT_DATA; 

    /* Here are the function prototypes for XFoil */ 
    __declspec(dllexport) XFOIL_OUTPUT_DATA *xfoilResults(); /* get output from xfoil */ 

I XFoilResults verwenden diese Struktur wieder in C#

Mein ziehen DLL Imports Anweisung ist die folgende:

[DllImport("xfoilapi.dll")] 
     public static extern void xfoilResults(); 

Ist das korrekt? Ich habe keine Kontrolle über den C++ Code. Ich muss nur in der Lage sein, die Struktur in C# zu ziehen. Die C# struct ich bisher habe, ist die folgende

[StructLayout(LayoutKind.Sequential)] 
    public struct xfoilResults 
    { 
    IntPtr pAlfa; 
     IntPtr pCL; 
     IntPtr pCM; 
     IntPtr pCDi; 
     IntPtr pCDo; 
     IntPtr pCPmax; 
    long nEntries; 
    } 

Wie kann ich diese C# Struktur mit den Daten aus dem C++ Code zu füllen?

+0

verwenden Was ist das Einsatzszenario? Wenn Sie sich eine extra DLL-Datei in Ihrer Anwendung leisten können, wird die Verwendung von C++/CLI für dieses Zeug Ihr Leben viel angenehmer machen. Sie kann die C++ - Struct-Definition direkt über #include verwenden, die C++ - Syntax zum Herausziehen der Daten verwenden und sie in eine Reihe von 'System :: Generic :: Collections :: List ' oder .NET-Array-Objekten ('cli :: Array ') für die weitere Verwendung von C#. –

Antwort

2

StructLayout muss in einer Klasse sein.

Dies sollte den Trick:

[DllImport("xfoilapi.dll")] 
public static extern IntPtr GetXfoilResults(); 

[StructLayout(LayoutKind.Sequential)] 
public class XfoilResults 
{ 
    IntPtr pAlfa; 
    IntPtr pCL; 
    IntPtr pCM; 
    IntPtr pCDi; 
    IntPtr pCDo; 
    IntPtr pCPmax; 
    int nEntries; // thanks to guys for reminding me long is 4 bytes 
} 

XfoilResults xf == new XfoilResults(); 
Marshal.PtrToStructure(GetXfoilResults(), xf); 
+2

Sollte es nicht int nEntries sein, da ein 'long' in C++ 32 Bits ist? – Marlon

+0

Sie haben absolut recht! Ich habe es geändert. – Aliostad

+0

Nur pingelig. StructLayout muss nicht in einer Klasse sein. Es kann auf einer Struktur sein. (Überprüfen Sie die AttributeTargets davon.) Der Unterschied zwischen den beiden ist die Art, wie Sie PtrToStructure aufrufen, weil die in Ihrem Beispiel verwendete Überladung xf ändert, die im Fall einer Struktur als Wert übergeben wird. Eine andere Überladung ermöglicht es Ihnen, eine neue Struktur zu erstellen und zurückzugeben. (Wie in meiner Antwort). –

2

Erstens sollte der Rückgabetyp importierten Funktion entweder IntPtr oder [MarshalAs(UnmanagedType.LPStruct)] xfoilResults_t sein.

Eine zweite wichtige Anmerkung ist, dass, wenn xfoilResults() die Daten in dieser Struktur zuweist und auffüllt, sollte irgendwo eine zweite Funktion sein, um diesen Speicher zu bereinigen. Sie müssen das auch importieren - und es bei Bedarf aufrufen, sonst entstehen Speicherlecks.

Wenn Sie dies geht manuell Marschall (dh der Import gibt ein IntPtr), sollten Sie in der Lage sein

IntPtr retval = xfoilResults(); 
var results = (xfoilResults_t)Marshal.PtrToStructure(
             retVal, 
             typeof(xfoilResults_t)); 

//Do the following for each IntPtr field 
double[] pCL = new double[results.nEntries]; 
Marshal.Copy(results.pCL, pCL, 0, results.nEntries); 

//Don't forget to call whichever function is cleaning up the unmanaged memory.