【问题标题】:Marshalling of a c++ struct which contains pointers to another c++ struct编组包含指向另一个 c++ 结构的指针的 c++ 结构
【发布时间】:2012-03-16 10:10:00
【问题描述】:

我有一个关于将 c++ 结构正确编组为 c# 的问题。这些定义如下:

extern "C"
{
    //Geometry forms that could be used for envelope calculation
    enum GeometryForms  {RECTANGLE, TRIANGLE, ELLIPSE, CIRCLESECTOR};

    //Structure for coordinates 3D
    typedef struct Coordinates
    {
        double  longitude;      //longitude of the point in dezimal deg
        double  latitude;       //latitude of the point in dezimal deg
        double  altitude;       //heigth of the point in metres
    } Coordinates, *PCoordinates;


    //Envelope Data Struct
    typedef struct EnvelopeStruct
    {
        GeometryForms   GeometryAft;        // Geometry form of the aft section
        GeometryForms   GeometryBow;        // Geometry form of the bow section
        GeometryForms   GeometryCurve;      // Geometry form during direction change
        GeometryForms   Geometry3DAboveWL;  // Geometry form 3D under the water level
        GeometryForms   Geometry3DUnderWL;  // Geometry form 3D above the water level
        Coordinates     *PointsAft;         // Coordinates of the part of the envelope of the aft section
        Coordinates     *PointsBow;         // Coordinates of the part of the envelope of the bow section
        Coordinates     *PointsCurve;       // Coordinates of the envelope during direction change
        Coordinates     *Points3DAboveWL;   // Coordinates of the envelope above water level
        Coordinates     *Points3DUnderWL;   // Coordinates of the envelope under water level
    }EnvelopeStruct, *PEnvelopeStruct;


    //Structure includes all parameters that are used for the envelope calculation
    typedef struct CalculationParametersStruct
    {
        double  pos_long;           //Position of the vessel, longitude in decimal degree
        double  pos_lat;            //Position of the vessel, latitude in decimal degree
        double  pos_alt;            //Position of the vessel, altitude in metres
        double  pos_long_future;    //Predicted longitude of the vessel in decimal degree
        double  pos_lat_future;     //Predicted latitude of the vessel in decimal degree
        double  pos_alt_future;     //Predicted altitude of the vessel in metres
        float   pos_future_time;    //Time or timeinterval between actual position and predicted position
        double  sigma_long;         //Accuracy of actual longitude
        double  sigma_lat;          //Accuracy of actual latitude
        double  sigma_alt;          //Accuracy of actual altitude
        double  PL_long;            //Integrity value (protection level) into longitude
        double  PL_lat;             //Integrity value (protection level) into latitude
        double  length;             //length of the vessel in metres
        double  beam;               //beam of the vessel in metres
        double  draft;              //draft of the vessel in metres
        double  max_t;              //maximum trim
        double  v;                  //velocity of the vessel
        double  course;             //vessels heading
        double  rate;               //Rate of Turn of the vessel
        double  angle;              //Rudder Angle of the vessel
        double  coef;               //Maneuvering Coefficient
        double  scale;              //Dangerous Cargo Scale
        double  scale_lon;          
        double  scale_lat;
        double  wave_lon;
        double  wave_lat;
        double  ENC_reliability;            
    }CalculationParametersStruct, *PCalculationParametersStruct;

我尝试用c#中的后续代码来完成,但暂时不起作用:

public enum GeometryForms { RECTANGLE, TRIANGLE, ELLIPSE, CIRCLESECTOR };

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class Coordinates
    {
        public double longitude;        //longitude of the point in decimal deg
        public double latitude;     //latitude of the point in decimal deg
        public double altitude;     //height of the point in metres
    }

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class EnvelopeStruct
    {
        public GeometryForms GeometryAft;       // Geometry form of the aft section
        public GeometryForms GeometryBow;       // Geometry form of the bow section
        public GeometryForms GeometryCurve;     // Geometry form during direction change
        public GeometryForms Geometry3DAboveWL; // Geometry form 3D under the water level
        public GeometryForms Geometry3DUnderWL; // Geometry form 3D above the water level
        [MarshalAs(UnmanagedType.LPStruct, SizeConst = 96)]
        public Coordinates PointsAft;           // Coordinates of the part of the envelope of the aft section
        [MarshalAs(UnmanagedType.LPStruct, SizeConst = 96)]
        public Coordinates PointsBow;           // Coordinates of the part of the envelope of the bow section
        [MarshalAs(UnmanagedType.LPStruct, SizeConst = 4320)]
        public Coordinates PointsCurve;     // Coordinates of the envelope during direction change
        [MarshalAs(UnmanagedType.LPStruct, SizeConst = 96)]
        public Coordinates Points3DAboveWL; // Coordinates of the envelope above water level
        [MarshalAs(UnmanagedType.LPStruct, SizeConst = 96)]
        public Coordinates Points3DUnderWL; // Coordinates of the envelope under water level
    }

    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class CalculationParametersStruct
    {
        public double pos_long;         //Position of the vessel, longitude in decimal degree
        public double pos_lat;          //Position of the vessel, latitude in decimal degree
        public double pos_alt;          //Position of the vessel, altitude in metres
        public double pos_long_future;  //Predicted longitude of the vessel in decimal degree
        public double pos_lat_future;       //Predicted latitude of the vessel in decimal degree
        public double pos_alt_future;       //Predicted altitude of the vessel in metres
        public float pos_future_time;   //Time or timeinterval between actual position and predicted position
        public double sigma_long;           //Accuracy of actual longitude
        public double sigma_lat;            //Accuracy of actual latitude
        public double sigma_alt;            //Accuracy of actual altitude
        public double PL_long;          //Integrity value (protection level) into longitude
        public double PL_lat;               //Integrity value (protection level) into latitude
        public double length;               //length of the vessel in metres
        public double beam;             //beam of the vessel in metres
        public double draft;                //draft of the vessel in metres
        public double max_t;                //maximum trim
        public double v;                    //velocity of the vessel
        public double course;               //vessels heading
        public double rate;             //Rate of Turn of the vessel
        public double angle;                //Rudder Angle of the vessel
        public double coef;             //Maneuvering Coefficient
        public double scale;                //Dangerous Cargo Scale
        public double scale_lon;
        public double scale_lat;
        public double wave_lon;
        public double wave_lat;
        public double ENC_reliability;
    }

当我尝试访问时,我收到 错误 CS0021:无法使用 [] 将索引应用于“EnvelopeCalculatorWrapper.Coordinates”类型的表达式

[MarshalAs(UnmanagedType.LPStruct, SizeConst = 96)]
            public Coordinates PointsAft;

在c#中作为数组的方式:

calc.envelope.PointsAft[i].longitude

有人知道怎么做吗!

提前致谢!

干杯,斯特凡

【问题讨论】:

    标签: c# pointers marshalling


    【解决方案1】:

    您忘记将其声明为数组。添加一个构造函数来初始化它们:

        [StructLayout(LayoutKind.Sequential)]
        public class EnvelopeStruct {
            public EnvelopeStruct() {
                this.PointsAft = new Coordinates[4];
                // etc..
            }
            public Coordinates[] PointsAft;
            // etc..
        }
    

    不要使用任何属性,默认封送处理是好的。

    【讨论】:

    • 似乎仍然存在一些错误,因为值没有从 c++(值设置正确)编组到 c#(值为空) - 我得到一个 NullReferenceException。不过你的回答还是有帮助的,谢谢。
    • 由于我之前的评论,我是否可能需要一些 [In, Out] 属性或 ref 关键字?
    【解决方案2】:

    不要使用 UnmanagedType.LPStruct,请参阅 this post

    编辑 如果您在结构中嵌入了固定大小的数组,则应遵循MSDN。很快,您应该将该字段声明为数组并将其指定为 UnmanagedType.ByValArray。您还必须指定尺寸。

    如果在结构中,你只有一个指向数组第一个元素的指针,你不需要任何自定义封送处理,默认行为是正确的(由@Hans Passant 发布)

    【讨论】:

    • 现在,我将其标记为:[MarshalAs(UnmanagedType.LPArray)] public Coordinates PointsAft;。但不幸的是,它不起作用。
    • 也将它们声明为数组,以便您可以使用 [] 访问 PointsAft
    • 你的意思是像[MarshalAs(UnmanagedType.LPArray)] public Coordinates[] PointsAft;?我是否必须指定数组的大小,例如SizeConst=100,或者有什么方法可以动态地做到这一点?
    • 对不起,对于您的情况,这是错误的 UnmanagedType,我更正了我的答案。
    • 不可能以动态方式完成这项任务?
    猜你喜欢
    • 2017-07-13
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 2016-08-28
    • 2013-04-18
    相关资源
    最近更新 更多