[resolut]passage d'un tableau de structure à une DLL C

passage d'un tableau de structure à une DLL C [resolut] - C#/.NET managed - Programmation

Marsh Posté le 16-12-2020 à 10:43:11    

Hello,
 
 
J'ai un soucis que je ne comprends pas encore très bien.
Je débute en c#, ça fait 2 ans que je suis sur du dev en C.
 
J'ai une lib codé en C qui est exporté en DLL.
Une des fonctions de la DLL attends un pointer de structure. Le pointer est là car c'est un tableau à passer.
 
la structure est celle-ci:

Code :
  1. typedef struct
  2. {
  3.    char Channel_Name[32];
  4.    int Channel_Index;
  5.    double Channel_Range;
  6.    eTermination Channel_Configuration;
  7.    eUnit Channel_Unit;
  8.    stSensors Sensor_Description;
  9. }Type_Channels_Description;


 
le prototype de la fonction C est la suivante:

Code :
  1. int DLLEXPORT Drv_AIBoard_Config(int Module, Type_Channels_Description *Channels_Description, int Channel_Number)


 
ça marche très bien sur mes autres appli codés en C.
 
Maintenant j'ai une autre app que je fait en C#, mais je réutilise la DLL en C.
 
j'ai chargé la dll et le prototype coté c# comme ça:

Code :
  1. [DllImport("C:/Applications/bin/NationalInstruments_NVH.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
  2. public static extern int Drv_AIBoard_Config(int Module,  StructType_Channels_Description[] Channels_Description, int Channel_Number);


Au début j'avais ajouté le mot ref, mais au vus des printfs coté C j'avais une salade de pointer  [:jungledede]  
 
La structure coté c# est comme ça:

Code :
  1. [StructLayout(LayoutKind.Sequential)]
  2.     public unsafe struct StructType_Channels_Description
  3.     {
  4.         // public string Channel_Name; //marche pas a cause de  taille non définit et de mémoire non managé.
  5.         public fixed char Channel_Name[32];//32 bytes max !  
  6.         public int Channel_Index;
  7.         public double Channel_Range;
  8.         public Termination Channel_Configuration;
  9.         public Unit Channel_Unit;
  10.         public StructSensors Sensor_Description;
  11.     }


 
D'après msdn je suis obligé d'utiliser le unsafe pour fixer la taille de la chaine de caractère.
Par contre j'ai un doute sur le layout sequential au vus de mon soucis.
 
 
Du coup ça semble bien compiler et tout, sauf que  :o , quand je fait un printf coté C pour lire contenu, j'ai que le premier caractère de la chaine qui est bon, tout les autres champs de la struct sont à 0..   :pt1cable:  
 
Des idées?
 
 
 
ps: une astuce pour que le déboguer puisse aller dans ma dll c?
Le code en C est fait avec National Instrument Labwindows/CVI


Message édité par jungledede le 16-12-2020 à 14:45:15

---------------
Monde de merde | Restez curieux
Reply

Marsh Posté le 16-12-2020 à 10:43:11   

Reply

Marsh Posté le 16-12-2020 à 11:02:54    

Il ne faut pas faire des bricoles comme ajouter un [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
au dessus de ton string, et/ou spécifier CharSet dans le StructLayout ?

 

C'est juste des pistes à creuser, mais la solution exacte. Je n'ai pas souvent recours à des DLL en C donc je dois pondre moi même les appels.


Message édité par TotalRecall le 16-12-2020 à 11:04:02

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 16-12-2020 à 11:07:33    

au début j'avais trouver une page sur msdn qui faisait le lien entre les type de ptr et les équivalents c#, mais impossible de la retrouver, et pas mis en favoris xD
 
je vais voir ce que je trouve avec Marshal


---------------
Monde de merde | Restez curieux
Reply

Marsh Posté le 16-12-2020 à 11:12:46    

Pas UnmanagedType justement ? C'est l'énum qui contient les différents types.

 

Sinon pour éviter d'avoir à écrire à la main tout le code pour appeler des lib unmanaged, il y a des projets comme https://github.com/mono/CppSharp qui peuvent peut être (?) aider, si tu as beaucoup d'appels à faire. On en trouve d'autres aussi.


Message édité par TotalRecall le 16-12-2020 à 11:16:05

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 16-12-2020 à 11:53:37    

mouhah ça marche  [:bultom:1]  
 
merci à toi pour la piste.
 
Du coup la struct deviens :
 

Code :
  1. [StructLayout(LayoutKind.Sequential)]
  2.     public unsafe struct StructType_Channels_Description
  3.     {
  4.         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
  5.         public string Channel_Name;
  6.         public int Channel_Index;
  7.         public double Channel_Range;
  8.         public Termination Channel_Configuration;
  9.         public Unit Channel_Unit;
  10.         public StructSensors Sensor_Description;
  11.     }


 
et c'est maintenant biens plus simple pour remplir le champs name sans faire de copie de char à base de boucle for.
 
et coté déclaration du prototype de la DLL, j'ai ajouté un marshal mais qui spécifie que c'est un tableau.
 

Code :
  1. [DllImport("C:/Application/bin/NationalInstruments_NVH.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
  2. public static extern int Drv_AIBoard_Config(int Module, [MarshalAs(UnmanagedType.LPArray)] StructType_Channels_Description[] Channels_Description, int Channel_Number);


 
 
c'est bien le c#  [:aqualung]


---------------
Monde de merde | Restez curieux
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed