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.