views:

660

answers:

3

I have created 2 structures in my C# code :

[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; 
         };

and :

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

            public RollInformationCSharp[] tabRoll; 
        }

In the C# code, i invoke a function of 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);

In C++, I have also 2 structures :

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

and

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

The function is also declared as follow :

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);

Example to fill the structure in 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; 
            }

In debug mode, just before the call to the DLL, the both structures in C# are right (multiRollInfo and rollInfo) . In C++, the rollInfo is good. But the the multiroll info has 5 elements but there values are wrong .

What is wrong? How can I correct this?

thank you very much for your help

+3  A: 

Your implementation treats it like the following C++ struct was declared (note the extra *). As is, the elements in the C# code are of a reference type (class), which means their native representation is a pointer.

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

To solve this, you'll need to make the RollInformationCSharp class a struct. At the same time you'll have to make the 3rd parameter of the managed signature for DLL_FlesCalculation of a ref parameter.

280Z28
A: 

If I understand : in C++, only one modification :

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

in 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;
    }

the function from the DLL to call :

  [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);

When I call this function in C#, I add the ref on the 3rd parameter.

In C++, the signature of the function don't change :

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);

with this, it crashes when DLL_FlesCalculation is called.

A: 

Well, technically your declarations from original question is correct, because MultiRollCSharp.tabRoll is a reference (a pointer) to array in memory. BTW, you declared RollInformationCSharp and MultiRollCSharp as class, mistake? or typing error?

But marshaller cannot handle such complex situations. So you have two ways, first embed array into structure itself:

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

and

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

This must work correctly if you marshal from C# to C++ (array length is known), but fails if you try to marshal backward, because length of tabRoll array is unknown for marshaller in this case.

Second option is to replace tabRoll in C# with actual pointer (IntPtr) and behave accordingly (alloc memory using Marshal.AllocHGlobal, and so on). In this case your c++ structure remains untouched. This is more complex approach but also more flexible, in general you can do everything using IntPtrs.

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