Passer un pointeur sur tableau de structure [Résolu]

olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 10 févr. 2008 à 23:00 - Dernière réponse : Lutinore
Messages postés
3248
Date d'inscription
lundi 25 avril 2005
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 ?

 
Afficher la suite 

Votre réponse

11 réponses

Meilleure réponse
Lutinore
Messages postés
3248
Date d'inscription
lundi 25 avril 2005
Dernière intervention
27 octobre 2012
- 10 févr. 2008 à 23:57
3
Merci
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.
    }
}

Merci Lutinore 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 94 internautes ce mois-ci

Commenter la réponse de Lutinore
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 11 févr. 2008 à 08:08
0
Merci
Merci,

Je vais essayer de digerer ca et le mettre en pratique

a suivre ...
Commenter la réponse de olibara
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 11 févr. 2008 à 08:53
0
Merci
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
Commenter la réponse de olibara
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 11 févr. 2008 à 08:59
0
Merci
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);
Commenter la réponse de olibara
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 11 févr. 2008 à 09:23
0
Merci
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
Commenter la réponse de olibara
Lutinore
Messages postés
3248
Date d'inscription
lundi 25 avril 2005
Dernière intervention
27 octobre 2012
- 11 févr. 2008 à 13:35
0
Merci
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 ^^ )
Commenter la réponse de Lutinore
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 11 févr. 2008 à 14:29
0
Merci
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)
Commenter la réponse de olibara
cs_marielle1
Messages postés
8
Date d'inscription
mardi 13 janvier 2004
Dernière intervention
10 juillet 2008
- 6 mai 2008 à 11:38
0
Merci
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+
Commenter la réponse de cs_marielle1
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 6 mai 2008 à 12:03
0
Merci
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.
Commenter la réponse de olibara
olibara
Messages postés
670
Date d'inscription
dimanche 16 décembre 2007
Dernière intervention
11 mars 2010
- 6 mai 2008 à 12:35
0
Merci
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;
    }
Commenter la réponse de olibara
Lutinore
Messages postés
3248
Date d'inscription
lundi 25 avril 2005
Dernière intervention
27 octobre 2012
- 9 mai 2008 à 08:21
0
Merci
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..
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.