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?

26
demandé sur Adam Haile 2008-10-09 21:27:02

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é.

24
répondu denny 2008-10-09 17:54:03

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;
}
13
répondu JaredPar 2012-07-31 16:41:19

L'Assistant D'Interop PInvoke peut vous aider. http://clrinterop.codeplex.com/releases/view/14120

3
répondu GregUzelac 2016-07-19 12:40:24

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.

2
répondu Constantin 2008-10-18 21:42:40

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;
}
2
répondu Zenexer 2017-05-23 12:33:28