C#到非托管C ++

时间:2009-07-17 06:42:38

标签: c# c++ marshalling

我在C#代码中创建了2个结构:

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

和:

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

            public RollInformationCSharp[] tabRoll; 
        } 

在C#代码中,我调用了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); 

在C ++中,我还有2个结构:

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

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

该函数也声明如下:

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

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

在调试模式下,就在调用DLL之前,C#中的两个结构都是正确的(multiRollInfo和rollInfo) 。 在C ++中,rollInfo很好。但是多卷信息有5个元素,但是值是错误的。

有什么问题? 我怎么能纠正这个?

非常感谢你的帮助

3 个答案:

答案 0 :(得分:3)

您的实现将其视为声明了以下C ++结构(请注意额外的*)。因此,C#代码中的元素是引用类型(class),这意味着它们的本机表示是一个指针。

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

要解决此问题,您需要将RollInformationCSharp班级设为struct。同时,您必须为DLL_FlesCalculation参数的ref制作托管签名的第3个参数。

答案 1 :(得分:0)

如果我明白:  在C ++中,只有一个修改:

struct MultiRollInformation
{
    int nbRoll;
    RollInformation** tabRoll;
};
在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;
    }

DLL中的函数调用:

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

当我在C#中调用此函数时,我在第3个参数上添加了参考值。

在C ++中,函数的签名不会改变:

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

有了这个,它会在调用DLL_FlesCalculation时崩溃。

答案 2 :(得分:0)

从技术上讲,原始问题的声明是正确的,因为MultiRollCSharp.tabRoll是内存中数组的引用(指针)。 BTW,您将RollInformationCSharp和MultiRollCSharp声明为类,错误?或输入错误?

但是marshaller无法处理如此复杂的情况。所以你有两种方法,首先将数组嵌入结构本身:

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

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

如果您从C#编组到C ++(数组长度已知),这必须正常工作,但如果您尝试向后编组,则会失败,因为在这种情况下,marshaller的tabRoll数组长度是未知的。

第二个选项是用实际指针(IntPtr)替换C#中的tabRoll并相应地运行(使用Marshal.AllocHGlobal分配内存,依此类推)。在这种情况下,您的c ++结构保持不变。这是更复杂的方法,但也更灵活,通常你可以使用IntPtrs做任何事情。

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