Marshalling of a c++ struct which contains pointers to another c++ struct



  • Hi all!

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

    The EnvelopeStruct is filled correctly in the unmanaged c++ part, but values are not marshalled back to C#, unfortunately.

    I am using a P/Invoke

    [DllImport(PATH)]
            static private extern bool CallSetEnvelope(IntPtr pEnvelopeCalculatorObject, EnvelopeStruct envelope);
    

    which calls a wrapper method

    extern DECLSPEC bool CallSetEnvelope(EnvelopeCalculator* pObject, PEnvelopeStruct envelope)
    {
    	if(pObject != NULL)
    	{
    		return pObject->setEnvelope(envelope);
    	}
    
    	return NULL;
    }
    

    This workaround became necessary as the C++ functions are encapsulated in a class.

    Hope I was clear enough ...



  • Hello,

    I think, you have to take IntPtr as replacement for the pointers:

    public IntPtr PointsAft;        
    public IntPtr PointsBow;
    public IntPtr PointsCurve;        
    public IntPtr Points3DAboveWL;        
    public IntPtr Points3DUnderWL;
    

    s. for example Marshalling Complicated Structures using PInvoke

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


Anmelden zum Antworten