none
Marshalling of a c++ struct which contains pointers to another c++ struct RRS feed

  • Question

  • I have an issue concerning the correct marshalling of c++ structs into c#. These are defined as follows:

    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;   

    I tried to accomplish with the subsequent code in c#, but it does not work for now:

    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
        }    

    I get an error CS0021: Cannot apply indexing with [] to an expression of type 'EnvelopeCalculatorWrapper.Coordinates' when I try to access

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

    as an array in c# in the manner:

    calc.envelope.PointsAft[i].longitude

    Does anybody know how to do it!

    Thanks in advance!

    Cheers, Stefan




    • Moved by Leo Liu - MSFT Tuesday, March 20, 2012 6:28 AM Moved for better support. (From:Visual C# General)
    • Edited by luckymanStefan Tuesday, March 20, 2012 4:03 PM
    Monday, March 19, 2012 3:24 PM

Answers

All replies

  • Which struct above do you susppect is the error? There are just too many struct above. Somehow I seriously think not everything is relevant.

    chanmm


    chanmm

    Tuesday, March 20, 2012 12:50 AM
  • Which struct above do you susppect is the error? There are just too many struct above. Somehow I seriously think not everything is relevant.

    chanmm


    chanmm


    @chanmm: Sorry, there was a problem with the editor, I filled in the C++ structs twice!

    But my P/Invoke related problem still remains, unfortunately!

    Tuesday, March 20, 2012 7:59 AM
  • Now I have changed the EnvelopeStruct class from above, i.e., added a constructor to it and omitted all the marshal attributes:

    [StructLayout(LayoutKind.Sequential)]
        //public struct EnvelopeStruct   
        public class EnvelopeStruct
        {
            public GeometryForms GeometryAft;
            public GeometryForms GeometryBow;
            public GeometryForms GeometryCurve;
            public GeometryForms Geometry3DAboveWL;
            public GeometryForms Geometry3DUnderWL;
            
            public EnvelopeStruct(GeometryForms geo1, GeometryForms geo2, GeometryForms geo3, GeometryForms geo4, GeometryForms geo5)
            {
                GeometryAft = geo1;
                GeometryBow = geo2;
                GeometryCurve = geo3;
                Geometry3DAboveWL = geo4;
                Geometry3DUnderWL = geo5;
    
                this.PointsAft = new Coordinates[5];
                
                this.PointsBow = new Coordinates[360];           
                this.PointsCurve = new Coordinates[5];//180
                this.Points3DAboveWL = new Coordinates[5];           
                this.Points3DUnderWL = new Coordinates[4];//4
            }
            
            public Coordinates[] PointsAft;        
            public Coordinates[] PointsBow;
            public Coordinates[] PointsCurve;        
            public Coordinates[] Points3DAboveWL;        
            public Coordinates[] Points3DUnderWL;
        }

    While debugging through the code I get a NullReferenceException when trying to access

    calc.envelope.PointsAft[i].longitude

    where envelope is of type EnvelopeStruct.




    Tuesday, March 20, 2012 4:11 PM
  • Have yoy tried to new a PonitsAft? something like below:

    calc.envelope.PointsAft[i] = new calc.envelope.PointsAft();
    calc.envelope.PointsAft[i].longitude


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, March 21, 2012 6:07 AM
    Moderator
  • Hi luckymanStefan,

    Have you resolved this issue? Any update about it please?

    And I will mark my reply as an answer, If you feel it didn't help, please unmark it and try to show more information about this case. We will try our best to help you.


    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, March 27, 2012 2:52 AM
    Moderator
  • Hi, Rocky Yue,

    I had  to use IntPtr[] as replacement for the pointer arrays:
    public IntPtr[] PointsAft;
    
    public IntPtr[] PointsBow;
    
    public IntPtr[] PointsCurve;
    
    public IntPtr[] Points3DAboveWL;
    
    public IntPtr[] Points3DUnderWL;

    Confer to the tutorial Marshalling Complicated Structures using PInvoke.

    And with the method Marshal.PtrToStructure you can get the content behind the pointer.

    • Marked as answer by luckymanStefan Wednesday, March 28, 2012 7:16 AM
    • Edited by luckymanStefan Wednesday, March 28, 2012 7:19 AM nice formatting
    Wednesday, March 28, 2012 7:16 AM
  • Thanks for sharing the solution.

    Best Regards,
    Rocky Yue[MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, March 28, 2012 7:18 AM
    Moderator