2013-06-03 3 views
2

Je voudrais retourner un tableau d'une structure dans mon API C++ (dll). Je peux déjà retourner une structure et l'utiliser dans mon application de test C#.API C++ retourne un tableau d'une structure

struct CharacterInformation { 
    int id; 
    double x; 
    double y; 
    CharacterInformation(int ID, double X, double Y) : id(ID), x(X), y(Y) {} 
}; 

extern "C" EXPORT_API CharacterInformation GetCharacterPositions(void) { 
    //std::vector<Character> characters = simulator->getCharacters(); 
    //CharacterInformation characterInformationArray [] = { CharacterInformation(0, 1, 2) }; 
    //return characterInformationArray; 
    CharacterInformation characterInformation = CharacterInformation(0,1,2); 
    return characterInformation; 

} 

Comment puis-je transmettre la matrice dans cette fonction. Je dois faire un peu de gestion de la mémoire mais je ne sais pas ce que je dois faire.

Répondre

2

Je l'ai travailler avec cette solution simple:

C++

extern "C" EXPORT_API CharacterInformation* GetCharacterPositions(void) { 
    std::vector<Character> characters = simulator->getCharacters(); 
    CharacterInformation characterInformation; 
    CharacterInformation *characterInformationArray = new CharacterInformation[GetCharactersCount()]; 
    for(int i = 0; i < GetCharactersCount(); i++) { 
    characterInformation.id = characters[i].getID(); 
    characterInformation.x = characters[i].getPosition().x; 
    characterInformation.y = characters[i].getPosition().y; 
    characterInformationArray[i] = characterInformation; 
    } 
    return characterInformationArray; 
} 

C#

[DllImport("API.dll", CallingConvention = CallingConvention.Cdecl)] 
private static extern IntPtr GetCharacterPositions(); 

IntPtr characterPositions = GetCharacterPositions(); 
for (int i = 0; i < GetCharactersCount(); ++i) 
{ 
    var data = new IntPtr(characterPositions.ToInt64() + structSize * i); 
    var characterInformation = (CharacterInformation)Marshal.PtrToStructure(data, typeof(CharacterInformation)); 
    Console.WriteLine("Character with ID: " + characterInformation.id + " X: " + characterInformation.x + " Y: " + characterInformation.y); 
} 
3

Vous ne pouvez pas renvoyer un tableau d'une fonction comme vous le pensez, mais vous pouvez renvoyer un pointeur sur le tableau. Vous devrez également renvoyer la longueur du tableau afin que vous puissiez correctement marshaler les données au type C# approprié. Cela nécessite une légère modification de la signature de la fonction pour renvoyer à la place les informations via les paramètres transmis à la fonction.

extern "C" EXPORT_API bool GetCharacterPositions(CharacterInformation** data, int *length) 
{ 
    CharacterInformation *characterInformationArray = new CharacterInformation[arraysize]; 

    // initialize contents of array. 

    // ... snip ... 

    *length = arraysize; 
    *data = characterInformationArray; 

    return true; 
} 

Dans ce cas, vous devrez ajouter un constructeur par défaut à utiliser CharacterInformation et initialisation à deux phases (à savoir une fonction Init()). Sachez que vous ne devez pas renvoyer un pointeur ou une référence à une variable locale non statique car le contenu de la variable sera détruit lorsqu'il sort de la portée (c'est-à-dire lorsque la fonction revient).

Pour rassembler les données, vous pouvez essayer quelque chose comme ce qui suit. Ceci n'est pas testé mais devrait vous pousser dans la bonne direction.

[DllImport("Dllname.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.I1)] 
public static extern bool GetCharacterPositions(out IntPtr arrayPtr, out int size); 

public static List<CharacterInformation> GetCharacterPositions() 
{ 
    var arrayValue = IntPtr.Zero; 
    var size = 0; 
    var list = new List<CharacterInformation>(); 

    if (!GetCharacterPositions(out arrayValue, out size)) 
    { 
    return list; 
    } 

    var dataEntrySize = Marshal.SizeOf(typeof(CharacterInformation)); 
    for (var i = 0; i < size; i++) 
    { 
    var cur = (CharacterInformation)Marshal.PtrToStructure(arrayValue, typeof(CharacterInformation)); 
    list.Add(cur); 
    arrayValue = new IntPtr(arrayValue.ToInt32() + dataEntrySize); 
    } 

    return list; 
} 

Vous devrez ajouter un appel supplémentaire afin de supprimer correctement les données en C++, sinon vous finirez avec une fuite de mémoire.

+0

Oke merci, mais comment puis-je convertir ce pointeur un tableau en C#. Je l'ai essayé avec Marshal.PtrToStructure mais cela ne fonctionnera pas pour un tableau. Et je pense que j'ai besoin de connaître la taille du tableau avant d'appeler GetCharacterPositions(), ai-je raison? – ZxCvBnM

1

Vous pouvez également allouer un tableau avant que l'appel ne fonctionne et transmette le tampon et sa taille. Votre fonction C remplira le tableau dans ce cas.

extern "C" EXPORT_API void GetCharacterPositions(CharacterInformation *pArr, int size) 
{ 
    for (int i = 0; i < size; ++ i) 
    { 
     //fill pArr[i] 
    } 

} 
+0

J'ai également essayé votre solution mais quand j'appelle cela en C# toutes les valeurs d'élément sont 0. C'est la déclaration de fonction en C#: [DllImport ("API.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void GetCharacterPositions (CharacterInformation [] characterInformationArray, taille int); – ZxCvBnM

+0

Votre fonction C accepte un tableau qui sera copié sur la pile et le contenu original ne sera pas modifié. Il ya un bon article sur MSDN parlant de passer des tableaux au code non managé - http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.80).aspx – Valery

-1

Vous pouvez considérer mon code. J'utilise la référence

#include<iostream> 

using namespace std; 

struct CharacterInformation { 
    int id; 
    double x; 
    double y; 
    CharacterInformation(int ID, double X, double Y) : id(ID), x(X), y(Y) {} 
}; 

extern "C" EXPORT_API void GetCharacterPositions(CharacterInformation &ci) { 
    CharacterInformation ciTmp(0,1,2); 
    ci.id = ciTmp.id; 
    ci.x = ciTmp.x; 
    ci.y = ciTmp.y; 
} 

int main() 
{ 
    CharacterInformation ci(0,0,0); 
    GetCharacterPositions(ci); 
    cout<<ci.id<<ci.x<<ci.y<<endl; 
    return 0; 
} 
+0

Mais cela doit fonctionner dans une application C# – ZxCvBnM

Questions connexes