2009-07-17 8 views
0

J'ai créé 2 structures dans mon code C#:C# à C non géré ++

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
     public class RollInformationCSharp 
     { 
      [MarshalAs(UnmanagedType.R8)] 
      public double rollDiameter; 

      [MarshalAs(UnmanagedType.R8)] 
      public double initialRoughness; 

      [MarshalAs(UnmanagedType.R8)] 
      public double finalRoughness; 

      [MarshalAs(UnmanagedType.R8)] 
      public double accumulateCombination; 

      [MarshalAs(UnmanagedType.R8)] 
      public double critialRollLength; 

      [MarshalAs(UnmanagedType.R8)] 
      public double rolledLength; 

      [MarshalAs(UnmanagedType.R8)] 
      public double percentageLifeRoll; 

      [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 256)] 
      public string rollName; 
     }; 

et:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
     public class MultiRollCSharp 
     { 
      [MarshalAs(UnmanagedType.I4)] 
      public int nbRoll; 

      public RollInformationCSharp[] tabRoll; 
     } 

Dans le code C#, j'invoque une fonction de C++ dll:

[DllImport("DLL_RaFTmodel.dll", CharSet = CharSet.Ansi)] 
     public static extern IntPtr DLL_FlesCalculation(MultiRollCSharp multiRollInfo, 
               CoilInformationCSharp coilInfo, 
               RollInformationCSharp rollInfo, 
               LimitsTypeCSharp LimitsSteel, 
               LimitsTypeCSharp LimitsRegulation, 
               LimitsTypeCSharp LimitsMachine, 
               FTInputsCsharp forceTensionInfo, 
               RaConstantsCSharp RaModelIn, 
               FTWeightCsharp FTmodelIn, 
               [In, MarshalAs(UnmanagedType.I4)] int strategy, 
               [In, MarshalAs(UnmanagedType.I4)] int rollLifeMaximization, 
               RaInputsCsharp RaDataIn, 
               char Version, 
               [In, MarshalAs(UnmanagedType.R4)] float errMax, 
               [Out, MarshalAs(UnmanagedType.I4)] out int error); 

En C++, j'ai aussi 2 structures:

struct RollInformation 
{ 
    double rollDiameter; 
    double initialRoughnessRoll; 
    double finalRoughnessRoll; 
    double accumulateCombination; 
    double percentageLifeRoll; 
    double criticalRollLength; 
    double rolledLength; 
    char rollName[256]; 
}; 

et

struct MultiRollInformation 
{ 
    int nbRoll; 
    RollInformation* tabRoll; 
}; 

La fonction est également déclarée comme suit:

extern EXPORTTOTEM_API 
MULTICURVETYPE* DLL_FlesCalculation(struct MultiRollInformation *multiRollInfo,          struct CoilInformation *coilInfo, 
      struct RollInformation *rollInfo, 
      struct LimitsType *LimitsSteel, 
      struct LimitsType *LimitsRegulation, 
      struct LimitsType *LimitsMachine, 
      struct FTInputs *forceTensionInfo, 
      struct RaConstants *constRaIn, 
      struct FTWeight *modelFTIn, 
      int strategy, 
      int rollLifeMaximization, 
      struct RaInputs *dataRaIn, 
         char Version, 
      float errMax, 
      int &error);  

Exemple pour remplir la structure en C#:

MultiRollCSharp multiRollInfo = new MultiRollCSharp(); 
      for(int i = 0; i < 5; i++) 
      { 
       RollInformationCSharp rollInfo1 = GetRollInformation(); 
       int taille = 0; 
       if (multiRollInfo.tabRoll != null) 
        taille = multiRollInfo.tabRoll.Length; 

       RollInformationCSharp[] tab = new RollInformationCSharp[taille +1]; 
       if (taille > 0) 
       { 
        multiRollInfo.tabRoll.CopyTo(tab, 0); 
       } 
       tab[tab.Length-1] = rollInfo1; 
       multiRollInfo.tabRoll = tab; 

       multiRollInfo.nbRoll += 1; 
      } 

En mode débogage, juste avant l'appel Pour la DLL, les deux structures en C# sont correctes (multiRollInfo et rollInfo) . En C++, rollInfo est bon. Mais l'info multiroll a 5 éléments mais les valeurs sont fausses.

Qu'est-ce qui ne va pas? Comment puis-je corriger cela?

je vous remercie beaucoup pour votre aide

Répondre

3

Votre mise en œuvre, il traite comme suit struct C++ a été déclaré (note extra *). En l'état, les éléments du code C# sont d'un type de référence (class), ce qui signifie que leur représentation native est un pointeur.

struct MultiRollInformation 
{ 
    int nbRoll; 
    RollInformation** tabRoll; 
}; 

Pour résoudre ce problème, vous aurez besoin de faire la classe RollInformationCSharp un struct. Dans le même temps, vous devrez faire le 3ème paramètre de la signature gérée pour DLL_FlesCalculation d'un paramètre ref.

0

Si je comprends: en C++, une seule modification:

struct MultiRollInformation 
{ 
    int nbRoll; 
    RollInformation** tabRoll; 
}; 

en C#:

public struct RollInformationCSharp 
    { 
     [MarshalAs(UnmanagedType.R8)] 
     public double rollDiameter; 
     public double initialRoughness; 
     public double finalRoughness; 
     public double accumulateCombination; 
     public double critialRollLength; 
     public double rolledLength; 
     public double percentageLifeRoll; 

     [MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 256)] 
     public string rollName; 
    }; 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public class MultiRollCSharp 
    { 
     [MarshalAs(UnmanagedType.I4)] 
     public int nbRoll; 

     public RollInformationCSharp[] tabRoll; 
    } 

la fonction de la DLL pour appeler:

[DllImport("DLL_RaFTmodel.dll", CharSet = CharSet.Ansi)] 
    public static extern IntPtr DLL_FlesCalculation(MultiRollCSharp multiRollInfo, 
        CoilInformationCSharp coilInfo, 
        ref RollInformationCSharp rollInfo, 
        LimitsTypeCSharp LimitsSteel, 
        LimitsTypeCSharp LimitsRegulation, 
        LimitsTypeCSharp LimitsMachine, 
        FTInputsCsharp forceTensionInfo, 
        RaConstantsCSharp RaModelIn, 
        FTWeightCsharp FTmodelIn, 
        [In, MarshalAs(UnmanagedType.I4)] int strategy, 
        [In, MarshalAs(UnmanagedType.I4)] int rollLifeMaximization, 
        RaInputsCsharp RaDataIn, 
        char Version, 
        [In, MarshalAs(UnmanagedType.R4)] float errMax, 
        [Out, MarshalAs(UnmanagedType.I4)] out int error); 

Quand je appelle cette fonction en C#, j'ajoute l'ref sur le 3ème paramètre.

En C++, la signature de la fonction ne change pas:

extern EXPORTTOTEM_API 
MULTICURVETYPE* DLL_FlesCalculation(struct MultiRollInformation *multiRollInfo, 
    struct CoilInformation *coilInfo, 
    struct RollInformation *rollInfo, 
    struct LimitsType *LimitsSteel, 
    struct LimitsType *LimitsRegulation, 
    struct LimitsType *LimitsMachine, 
    struct FTInputs *forceTensionInfo, 
    struct RaConstants *constRaIn, 
    struct FTWeight *modelFTIn, 
    int strategy, 
    int rollLifeMaximization, 
    struct RaInputs *dataRaIn, 
    char Version, 
    float errMax, 
    int &error); 

avec cela, il se bloque lorsque DLL_FlesCalculation est appelé.

0

Eh bien, techniquement, vos déclarations de la question d'origine sont correctes, car MultiRollCSharp.tabRoll est une référence (un pointeur) au tableau en mémoire.BTW, vous avez déclaré RollInformationCSharp et MultiRollCSharp en classe, erreur? ou erreur de frappe?

Mais marshaller ne peut pas gérer des situations aussi complexes. Donc, vous avez deux façons, premier réseau d'intégration dans la structure elle-même:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MultiRollCSharp 
{ 
    [MarshalAs(UnmanagedType.I4)] 
    public int nbRoll; 
    [MarshalAs(UnmanagedType.ByValArray)] 
    public RollInformationCSharp[] tabRoll; 
} 

et

struct MultiRollInformation 
{ 
    int nbRoll; 
    RollInformation tabRoll[]; 
}; 

Cela doit fonctionner correctement si vous, maréchal de C# à C++ (longueur du tableau est connu), mais échoue si vous essayez de remonter en arrière, car la longueur du tableau tabRoll est inconnue pour marshaller dans ce cas.

La deuxième option consiste à remplacer tabRoll en C# par le pointeur réel (IntPtr) et à se comporter en conséquence (allouer la mémoire en utilisant Marshal.AllocHGlobal, etc.). Dans ce cas, votre structure C++ reste intacte. C'est une approche plus complexe mais aussi plus flexible, en général vous pouvez tout faire en utilisant IntPtrs.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MultiRollCSharp 
{ 
    [MarshalAs(UnmanagedType.I4)] 
    public int nbRoll; 
    IntPtr tabRoll; 
} 
Questions connexes