2010-12-16 1 views
3

Mon struct en C++ est le suivantJe suis en train de rassembler un struct de C à C#, pas sûr où commencer

/* 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 */ 

J'utilise XFoilResults pour tirer cette structure arrière en C#

Mon L'instruction DLL Imports est la suivante:

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

Est-ce correct? Je n'ai aucun contrôle sur le code C++. J'ai juste besoin d'être capable de tirer la structure en C#. Le struct C# J'ai à ce jour est le suivant

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

Comment puis-je remplir cette structure C# avec les données à partir du code C++?

+0

Quel est le scénario de déploiement? Si vous pouvez vous permettre un fichier .dll supplémentaire dans votre application, l'utilisation de C++/CLI pour ce genre de choses rendra votre vie beaucoup plus agréable. Il peut utiliser la définition de structure C++ directement via #include, utiliser la syntaxe C++ pour extraire les données, et les placer dans une série d'objets de tableau System :: Generic :: Collections :: List 'ou .NET (' cli :: array ') pour une utilisation ultérieure de C#. –

Répondre

2

StructLayout doit être dans une classe.

Cela devrait faire l'affaire:

[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

Ne devrait-il pas être int nEntries, puisqu'un «long» en C++ est de 32 bits? – Marlon

+0

Vous avez absolument raison! Je l'ai changé. – Aliostad

+0

Juste nitpicking. StructLayout n'a pas besoin d'être sur une classe. Cela peut être sur une structure. (Vérifiez les AttributeTargets de celui-ci.) La différence entre les deux est la façon dont vous appelez PtrToStructure, car la surcharge utilisée dans votre exemple modifie xf, qui est passé par valeur dans le cas d'une structure. Une autre surcharge vous permet de créer et de renvoyer une nouvelle structure. (Comme dans ma réponse). –

2

Tout d'abord, le type de retour de votre fonction importée doit être soit IntPtr ou [MarshalAs(UnmanagedType.LPStruct)] xfoilResults_t.

Une deuxième remarque importante est que, si xfoilResults() alloue et remplit les données dans cette structure, il devrait y avoir une seconde fonction pour nettoyer cette mémoire. Vous devez également importer cela - et l'appeler si nécessaire, sinon vous vous retrouverez avec des fuites de mémoire.

Si vous allez maréchal manuellement (c.-à l'importation retourne un IntPtr), vous devriez pouvoir utiliser

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. 
Questions connexes