Renvoi de structure dans une dll c++ [Résolu]

cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 6 juil. 2006 à 17:41 - Dernière réponse : Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention
- 8 sept. 2006 à 04:34
D'abord bonjour a tous.

Ensuite... j'ai un probleme (eh oui c'est pour ca que j'écris ce message)

Voila je dois ecrire un programme en C#.NET qui utilise une DLL écrite en C++. J'ai trouvé qu'il fallait utiliser P/Invoke.
Ca marche bien sauf dans le cas d'une fonction ou plutot de plusieurs fonctions qui me retourne une structure contenant un tableau d'autre structure.  Quand j'essaye d'executer cette methode, j'ai une erreur du type :
La signature du type de cette méthode n'est pas compatible avec PInvoke.

Pour un peu plus de détail, la fonction de ma DLL me retourne une structure du type :
struct listeTruc{
int nombre;
struct truc tab[];
}
J'ai donc défini ces 2 structures dans mon prog en .NET

Mais ca marche pas. Je pense que c'est parce qu'il s'agit d'un type un peu trop compliqué pour p/Invoke, mais je n'en suis pas sure.
Si vous pouviez me le confirmer...
Et si j'ai raison, et meme si j'ai tord, connaissez-vous une solution a mon probleme?

Cassiopee
Afficher la suite 

Votre réponse

9 réponses

Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 6 juil. 2006 à 19:28
+3
Utile
Salut, plusieurs pistes ici :

http://www.csharpfr.com/infomsg_SOUS-AVEC-DLLIMPORT_747879.aspx
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Lutinore
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 13 juil. 2006 à 04:28
+3
Utile
Pour passer un tableau de structure :

[ StructLayout( LayoutKind.Sequential ) ]
private struct MyStruct
{
    int x;
    int y;
}


[ DllImport( "myLib.dll" ) ]
private static extern int MyFunc( [ In ] MyStruct[ ] myTab );

Ca c'est le marshalling par défaut, remplace [ In ] par [ In, Out ] pour avoir un tableau marshaller en entrée et en sortie. Mais n'oublie pas que si le tableau est alloué dans le code C il ne sera pas récupéré par le Garbage Collector.

// Un exemple ( C# ) :

// Implémente le code C pour qu'il renvoie la taille nécessaire si le tableau est null.
int size = MyFunc( null );

// On alloue le tableau managé à la bonne taille.
MyStruct[ ] tab = new MyStruct[ size ];

// On remplit le tableau
// le prototype doit être [ In, Out ]
MyFunc( tab );
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Lutinore
cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 7 juil. 2006 à 09:55
0
Utile
Merci pour le lien.
J'ai réussi à faire ce que je voulais. Ou presque...
Disons que j'arrive a passer dans ma structure principale un tableau de sous-structure. Par contre je suis obligé de définir la taille du tableau de sous-structure. Est qu'il y a un moyen de ne pas fixer cette taille?
Commenter la réponse de cs_cassiopee
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 8 juil. 2006 à 03:25
0
Utile
C'est un peu le problème qui c'est passé dans le lien précédent, et j'ai toujours pas de certitudes et toujours pas trouvé d'exemples sur le net. Si on ne connait pas le nombre d'éléments ça implique d'utiliser un pointeur pour le tableau de structures ( ou IntPtr ) mais si le tableau est alloué en C/C++ , comment le libérer en C#, il n y a pas d'opérateur delete en C#. ( si il est alloué avec CoTaskMemAlloc ont peut le libérer avec Marshal.FreeCoTaskMem du coté du code managé. )
Faudrait envisager un moyen de demander le nombres d'éléments au code C/C++ ( genre : getSize( ) ) puis allouer en C# un tableau de taille nécessaire, le fixer en mémoire ( mot clé : fixed ) puis le passer en IntPtr dans la structure. Comme le tableau à été alloué du coté du code managé il sera récupéré par le garbage collector.
Commenter la réponse de Lutinore
cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 12 juil. 2006 à 15:33
0
Utile
Re-bonjour,

Voila, j'ai un autre pb.

J'ai dans ma DLL, j'ai une fonction qui prend en paramètre un pointeur sur un tableau de structure. J'avoue que j'ai du mal avec le marshalling. quelqu'un pourrait t'il m'aidé sur ce sujet.

Ma fonction a une signature (non managée) du type : void maFonction(struct test * )
Quelle doit-etre la signature de cette meme fonction en code managé? J'ai essayé avec un IntPtr mais j'arrive pas à récupérer les différents éléments de mon tableau. Si quelqu'un avait un exemple de code ca m'aiderai beaucoup.

Merci par avance
Commenter la réponse de cs_cassiopee
cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 12 juil. 2006 à 15:53
0
Utile
Juste une autre petite question. Est ce que ca serait plus facile si ma fonction dans la DLL retournait un pointeur sur le tableau de structure, ou le tableau lui-meme.

C'est a dire, si le prototype de la fonction est du style :
struct test maFonction()
ou struct test * maFonction().

Quelle-est la différence entre ces trois cas. Quelle solution me conseillez-vous?
Commenter la réponse de cs_cassiopee
cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 13 juil. 2006 à 14:39
0
Utile
Merci beaucoup pour ton aide.
Ca fonctionne comme je voulais... c'est génial.
Commenter la réponse de cs_cassiopee
cs_cassiopee 8 Messages postés vendredi 11 janvier 2002Date d'inscription 11 octobre 2006 Dernière intervention - 6 sept. 2006 à 15:12
0
Utile
Eh oui, c'est encore moi... j'ai un autre petit soucis qui m'est apparu. Voila, en fait, j'ai dans une structure que je dois marshaller un tableau de chaine de caratères. Est-ce que c'est possible de marshaller ca?

Je m'explique. En C++ j'ai  :

typedef struct FIELDSTRUCTURE
{
    char id[SIZE_ID];
    char label[SIZE_LABEL];
    char dataType[SIZE_DATATYPE];
    int position;
    int update;
    char parentFieldId[MAX_PARENT][SIZE_ID];
}FIELDSTRUCTURE;

En C# pour marshaller les premiere varaible de la strucutre, y a pas de pb mais pour le parentFieldId, j'ai un soucis.
Je sais marshaller un tableau :
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
Je sais marshaller une chaine de caractère :
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
Mais les deux en meme temps je sais pas.

D'abord, est-ce que c'est possible?
Commenter la réponse de cs_cassiopee
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 8 sept. 2006 à 04:34
0
Utile
Dans une structure je ne sais pas, peut être..

Mais je prefère passer par du code unsafe comme ça je sais ce qui se passe en mémoire.

Il faut déja allouer une structure de même taille que le code C, donc avec un tableau inline, pas un pointeur vers un tableau.

[ StructLayout( LayoutKind.Sequential ) ]
public unsafe struct FieldStruct
{
    // id, label etc..


    // Tableau de bytes car char égale 2 bytes
    // pour les tableaux fixes, peu importe
    // le CharSet de la structure.
    public fixed sbyte parentFieldId[ MAX_PARENT * SIZE_ID ];
}

Et pour le récupérer sous forme de tableau de chaines :

unsafe
{
    sbyte* p = myStruct.parentFieldId;


    string[ ] tab = new string[ MAX_PARENT ];


    for ( int i = 0; i < MAX_PARENT; i++ )
        tab[ i ] = new string( p + ( i * SIZE_ID ) );
}
Commenter la réponse de Lutinore

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.