J'ai la structure suivante en C++:
#define MAXCHARS 15
typedef struct
{
char data[MAXCHARS];
int prob[MAXCHARS];
} LPRData;
Et une fonction dans laquelle je p/invoque pour obtenir un tableau de 3 de ces structures:
void GetData(LPRData *data);
En C++, je ferais simplement quelque chose comme ceci:
LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );
Et cela fonctionnerait très bien, mais en C #, je n'arrive pas à le faire fonctionner. J'ai créé une structure C # 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 d'entre eux (et tous leurs sous-tableaux) et le passe dans ceci:
GetData(LPRData[] data);
Il revient avec succès, mais les données du tableau LPRData n'ont pas changé.
J'ai même essayé de créer un tableau d'octets bruts de la taille de 3 LPRData et de le transmettre à un prototype de fonction comme celui-ci:
GetData (octet [] données);
Mais dans ce cas, j'obtiendrai la chaîne "data" de la toute première structure LPRData, mais rien après, y compris le tableau "prob" du même LPRData.
Des idées sur la façon de gérer correctement cela?
J'essaierais d'ajouter quelques attributs à votre déclinaison de structure
[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;
}
* Remarque TotalBytesInStruct n'est pas destiné à représenter une variable
JaredPar a également raison de dire que l'utilisation de la classe IntPtr pourrait être utile, mais cela fait un certain temps que je n'ai pas utilisé PInvoke, je suis donc rouillé.
Une astuce lorsque vous traitez avec des pointeurs est d'utiliser simplement un IntPtr. Vous pouvez ensuite utiliser Marshal.PtrToStructure sur le pointeur et incrémenter en fonction de 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 PInvoke Interop peut vous aider. http://clrinterop.codeplex.com/releases/view/1412
Avez-vous marqué le paramètre GetData avec OutAttribute ?
La combinaison de InAttribute et OutAttribute est particulièrement utile lorsqu'elle est appliquée à des tableaux et à des types formatés non blittables. Les appelants ne voient les modifications apportées par un appelé à ces types que 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 défini sur CharSet.Ansi
. Sinon, nous ferions un wchar_t
array au lieu d'un char
array. 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;
}