Marshal c++ struct array en C#
j'ai la structure suivante en C++:
#define MAXCHARS 15
typedef struct
{
char data[MAXCHARS];
int prob[MAXCHARS];
} LPRData;
et une fonction que j'invoque pour obtenir un tableau de 3 de ces structures:
void GetData(LPRData *data);
en C++ je ferais juste quelque chose comme ça:
LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );
Et cela fonctionne très bien, mais en C# je n'arrive pas à le faire fonctionner. J'ai créé un c# struct comme ceci:
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
Et si j'initialise un tableau de 3 de ces
GetData(LPRData[] data);
retourne avec succès, mais les données du tableau LPRData n'ont pas changé.
j'ai même essayé de créer un tableau brut d'octets de la taille de 3 LPRData et de passer que dans un prototype de fonction comme ceci:
GetData (byte[] data);
mais dans ce cas j'obtiendrai la chaîne "data" de la toute première structure LPRData, mais rien après, incluant le tableau" prob " de la même LPRData.
avez-vous une idée de la façon de bien gérer cela?
5 réponses
j'essaierais d'ajouter quelques attributs à votre déclinaison structurelle
[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable]
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}
* Note TotalBytesInStruct n'est pas destiné à représenter une variable
JaredPar est également correct que l'utilisation de la classe IntPtr pourrait être utile, mais il a été assez longtemps depuis que j'ai utilisé PInvoke donc je suis rouillé.
un truc quand on traite avec des pointeurs est d'utiliser un IntPtr. Vous pouvez alors utiliser Marshal.PtrToStructure sur le pointeur et incrément basé sur la taille de la structure pour obtenir vos résultats.
static extern void GetData([Out] out IntPtr ptr);
LPRData[] GetData()
{
IntPtr value;
LPRData[] array = new LPRData[3];
GetData(out value);
for (int i = 0; i < array.Length; i++)
{
array[i] = Marshal.PtrToStructure(value, typeof(LPRData));
value += Marshal.SizeOf(typeof(LPRData));
}
return array;
}
L'Assistant D'Interop PInvoke peut vous aider. http://clrinterop.codeplex.com/releases/view/14120
avez-vous noté le paramètre GetData avec OutAttribute ?
combinant L'InAttribute et L'OutAttribute est particulièrement utile lorsqu'il est appliqué aux tableaux et formaté, Non-blittable types. Les appelants voir la modifications apportées à ces types par un callee uniquement lorsque vous appliquez les deux attributs.
un sujet similaire a été discuté sur cette question , et l'une des conclusions était que le paramètre nommé CharSet
doit être réglé à CharSet.Ansi
. Sinon, nous ferions un tableau wchar_t
au lieu d'un tableau char
. Ainsi, le code correct serait le suivant:
[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LPRData
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}