Question

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 suis invoquée pour obtenir un tableau de trois de ces structures:

void GetData(LPRData *data);

En C ++, je voudrais simplement faire 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 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 d'octets brut de la taille de 3 LPRData et de le transférer dans un prototype de fonction comme celui-ci:

GetData (octet [] données);

Mais dans ce cas, j'obtiendrai les "données". chaîne de la toute première structure LPRData, mais rien après, y compris le "prob" tableau du même LPRData.

Avez-vous des idées sur la manière de gérer cela correctement?

Était-ce utile?

La solution

J'essaierais d'ajouter des 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 j’ai utilisé PInvoke, donc je suis rouillé.

Autres conseils

Une astuce lorsque vous utilisez des pointeurs consiste à 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 d'interopérabilité PInvoke peut vous aider. http://clrinterop.codeplex.com/releases/view/14120

Avez-vous marqué le paramètre GetData avec OutAttribute ?

  

Combinaison de InAttribute et   OutAttribute est particulièrement utile   lorsqu'il est appliqué à des tableaux et formaté,   types non-blittable. Les appelants voient le   modifie un appel fait à ces types   uniquement lorsque vous appliquez les deux attributs.

Un sujet similaire a été abordé dans cette question et dans celle de les conclusions ont été que le paramètre nommé CharSet doit être défini sur CharSet.Ansi . Sinon, nous créerions 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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top