Passer un pointeur sur tableau de structure

Résolu
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 - 10 févr. 2008 à 23:00
Lutinore Messages postés 3245 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 - 9 mai 2008 à 08:21
Bonjour

Depuis C# j'aimerais appeller une Dll ecrite en C

J'ai plusieurs fonctions dont certaines utilisent un pointeur sur tableau de structure, comment dois-je déclarer ces structure et en C# et declarer la fonction 

Est ce que ceci est bon ?

    public struct PntF
    {
      public double X;
      public double Y;
    };


    [DllImport("bcta.Dll")]
    static extern int bctaOpen(IntPtr handle, string a, int b);
    [DllImport("bcta.Dll")]
    static extern int bctaGetTrack(IntPtr hBcta, ref PntF Pnt, int count);

   PntF []Pnt;

Est-il possible de definir un tableau de longueur fixée ?

 
A voir également:

11 réponses

Lutinore Messages postés 3245 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 févr. 2008 à 23:57
Salut, le marshalling par défaut vers le code unsafe va fixer ton tableau en mémoire si le prototype managé de la fonction prend un tableau en paramètre mais pour les types non blittables ça peut être couteux en terme de performance. Il est possible de fixer un tableau en mémoire pour le protéger du GC avec l'instruction fixed ou la structure GCHandle.




[ StructLayout( LayoutKind.Sequential ) ]
private struct MyStruct
{
    public unsafe fixed int MyArray[ 4 ]; // tableau inline.
}


private static unsafe void Main( string[ ] args )
{
    MyStruct[ ] tab = new MyStruct[ 4 ]; // tableau sur le tas managé.


    fixed( MyStruct* p = tab )
    {
        // Ici le tableau est fixé et ne sera pas déplacé par le GC.
    }
}
3
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
11 févr. 2008 à 08:08
Merci,

Je vais essayer de digerer ca et le mettre en pratique

a suivre ...
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
11 févr. 2008 à 08:53
Bonjour encore

J'ai hesité a ouvrir un nouveau sujet, mais la question reste liée a l'utilisation de pointeur et l'appel de dll

   [DllImport("bcta.Dll")]
    static extern int bctaOpen(IntPtr handle, string a, int b);

bctaOpen voit handle comme void ** et l'alloue (calloc en C)

Comment dois-je prototyper ma fonction en C# et declarer handle ?
Tel que je l'ai fait je me fais jeter et je peux comprendre car Handle est un pointeur et non un pointeur de pointeur ??

Merci de l'aide précieuse
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
11 févr. 2008 à 08:59
Merci

Je vais me répondre a moi meme comme ca je peux aider les autres

Je devais faire :

  [DllImport("bcta.Dll")]
    static extern int bctaOpen(ref IntPtr handle, string a, int b);

ensuite

IntPtr handle = (IntPtr) 0;
string path;
int count;
bctaOpen(ref IntPtr handle, path , count);
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
11 févr. 2008 à 09:23
Bonjour

Je suis con ou mal réveillé mais j'ai encore rien compris
Pas toujours évident le C# quand on est imprégné d'habitudes en C

Toujours mon probleme de declarer et assigner un tableau de structure

1- Je declare une fonction de ma dll qui utilise un tableau de structures PntF dont le count est donné (count)
    [DllImport("bcta.Dll")]
    static extern int bctaGetTrack(IntPtr hBcta, ref PntF Pnt, int count);

2- Je declare la structure
   public struct PntF
    {
      public double X;
      public double Y;
    };
3- Je declare le tableau
   PntF []Pnt;

4- ICI je suis perdu Comment dois je allouer ce tableau qui n'a toujours pas de dimension ??
En C j'aurais fait Pnt[2]; ou un calloc
0
Lutinore Messages postés 3245 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
11 févr. 2008 à 13:35
ref IntPtr pour le double pointeur, c'est bon, tu as trouvé tout seul.

..

3 ) Déclaration du tableau.

PntF[ ] pnt;

4 ) Allocation sur le tas managé. ( ou Marshal.AllocHGlobal pour alloué de l'espace sur le tas non-managé comme en C ).

pnt = new PnF[ 10 ]; // allocation de sizeof( PnF ) * 10

5 ) En C# il y a un garbage collector qui déplace les objets en mémoire, donc il faut fixer le tableau en mémoire avant de le passer à la dll, avec l'instruction fixed ou avec un GCHandle.. Si ton prototype managé, (celui avec dllimport ) prend un tableau en argument à la place d'un pointeur ou d'un ref, dans ce cas le marshaling par défaut va fixer le tableau le temps de l'appel de la fonction. ( c'est ce que j'ai déja écris dans le 1er message ^^ )
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
11 févr. 2008 à 14:29
Merci

Grace a tes explication et mes nombreux essais intemediares j'ai pu avancer

A propos de GC
J'avais fais un test positif mais SANS fixer le tableau

Ca a marché mais je suppose que le risque existait de voir mon tableau déplacé avannt son exploitation complete par la DLL

(par chance, la DLL recopie ce tableau tout de suite a l'appel pour son usage personnel)
0
cs_marielle1 Messages postés 8 Date d'inscription mardi 13 janvier 2004 Statut Membre Dernière intervention 10 juillet 2008
6 mai 2008 à 11:38
Je suis content de voir qu'il y'a des gens qui ont galérés sur les dll's et les passages de pointeur....
J'ai compris ce que vous aviez fait mais de mon côté je galère car je dois passer un tableau à 2 dimensions....

 je dois utiliser  cette fonction dans ma dll:
int MSTX_EXPORT S00X_ReadPageC240(BOOL readc240, unsigned char blocknb, unsigned char firstpage, unsigned char nbpages, unsigned char pages[][S00X_ANTICOLL_ARRAY], unsigned char *cmdstatus);

dans mon code en C#, je l'ai déclarée de cette manière:
[DllImport("MedioSTX.dll")]
static extern unsafe int S00X_ReadPageC240(bool readc240, char blocknb, char firstpage, char nbpages, char** pages, char* cmdstatus);

depuis ma fonction je l'appelle de cette façon:
char[][] pages= new char[4][];
for (int i = 0; i < 4; i++)
       pages[i] = new char[8];
char cmdstatus = '0';
fixed( char** pBuffer = pages[0] )
 {
         S00X_ReadPageC240(true, (char)0, (char)0, (char)1, pBuffer, &cmdstatus);
  }

Si quelqu'un pouvait m'expliquer comment je peux passer mon char[][] pages dans la dll pour qu'elle l'initialise.

Merci d'avance pour votre aide...
A+
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
6 mai 2008 à 12:03
A mon avis, t'est mal barré !
Qui a écrit ta DLL ?


Comment cette DLL peut elle connaitre la dimension que tu donne à pages ?
en particulier S00X_ANTICOLL_ARRAY ?

Dans ce genre de situation, soit tu cree une fonction d'init de la DLL qui prepare ses buffer et une fonction close qui les libere
Soit tu passe a la DLL toute l'information nécessaire pour pour qu'elle sache ou elle peurt chatouiller la memoire.

Si j'ai bien lu et compris, ni l'un ni l'autre ne sont fait ici.
0
olibara Messages postés 666 Date d'inscription dimanche 16 décembre 2007 Statut Membre Dernière intervention 11 mars 2010 6
6 mai 2008 à 12:35
Voici un petit exemple ou je traite un tableau de pointeur de string, mais tu remarquera l'open et le close de la dll

    [DllImport("bcta.Dll")]
    static public extern int bctaOpen(ref IntPtr hBcta, string a, char b);


    [DllImport("bcta.Dll")]
    static public unsafe extern int bctaGetName(IntPtr hBcta, UInt32 nAttID, out IntPtr** StrPtr);
   
   
        // **********************************************************************************************
    unsafe static public string [] RoadNameById(int IdRue)
    {
      char ch = (char)1;
      IntPtr hBcta = (IntPtr)0;
      UInt32 attrId = (UInt32)IdRue;
      int count;


      IntPtr** StrPtr;
      Routing.bctaOpen(ref hBcta, Environ.RoutingDataPath, ch);
      attrId |= 0x800000;


      count = bctaGetName(hBcta, attrId,out StrPtr);
      if (count <= 0)
      {
        return null;
      }
      string[]aa = new string[count];
      for (int i = 0; i < count; i++)
      {
        aa[i] = Marshal.PtrToStringAnsi((IntPtr)StrPtr[i]);
        aa[i]=aa[i].Substring(3);
      }
      Routing.bctaClose(hBcta);
      return aa;
    }
0
Lutinore Messages postés 3245 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
9 mai 2008 à 08:21
Marielle1,

char = 1 octet en C/C++ et 2 octets en C#, il faut modifier la déclaration de la fonction et remplacer les "char" par des "byte".

Il faut trouver dans le header C de ta fonction la valeur de S00X_ANTICOLL_ARRAY.

Créer un tableau managé avec le nombre de colonnes égale à S00X_ANTICOLL_ARRAY.

Pour le reste sans la documentation de ta fonction c'est pas facile.. je pense que "nbpages" est le nombre de rangée ( row ) à intitialiser coté C# avant de passer le tableau..
0
Rejoignez-nous