Ok, so i have some questions regarding the p/invoking of methods out of a dll:
Does this look right for dllimport if both DLLs exist in the same folder? I am using an example project to test with. Both projects work separately, now I just want to understand how i can call a method from managed to native.
class UstnNative { [DllImport("TextUpdateCpp.dll", CharSet = CharSet.Unicode)] private static extern int createALine(DPoint3d dPoint); public static void CreateLine() { createALine(new DPoint3d(0, 0, 0)); } }
Here's the cpp file method:
void createALine(DPoint3dCR basePt) { EditElementHandle eeh; DSegment3d seg; seg.Init(basePt, DPoint3d::From(basePt.x + g_1mu * 2, basePt.y + g_1mu)); ICurvePrimitivePtr pCurve = ICurvePrimitive::CreateLine(seg); DraftingElementSchema::ToElement(eeh, *pCurve, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL); eeh.AddToModel(); }
Can I pass in the DPoint3d from GeometryNET.DPoint3d to native Bentley.DPoint3D? Or do i need to use doubles and create a new point in native?
Hi Viktor,
Yes you can pass the DPoint directly as you are doing, it will be marshalled by the System.Runtime.InteropServices.Marshal, which will make a copy of the data to pass through.
You can also pass pointers to the data which will not create copies. (Without having to enable the unsafe compile flag on the C# side)
For instance if you had a C function to extract a Z value from a surface (receiving a point pointer and a surface Id):
int FnSurfaceZ(Dpoint3d* Pt, int I);
You can call it like this:
[DllImport("xxxx.dll", EntryPoint = "FnSurfaceZ", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] private static extern int FnSurfaceZ(IntPtr point3d, int surfaceId); public bool SurfaceZ(ref BCOM.Point3d point, int surfaceId) { //Allocate new unmanaged memory IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(point)); try { //copy the value of the reference point to the unmanaged memory Marshal.StructureToPtr(point, pointer, false); //Pass the pointer to MicroStation to pass to Terra Model int answer = FnSurfaceZ(pointer, surfaceId); //Copy the answer in unmanaged memory back to the reference point point = (BCOM.Point3d)Marshal.PtrToStructure(pointer, typeof(BCOM.Point3d)); //return true or false indicating the success of the operation return (answer == SUCCESS); } finally { //Free the unmanaged memory Marshal.FreeHGlobal(pointer); } }
This is explicitly creating the pointers.
You can also implicitly pass the pointers using:
[DllImport("xxxx.dll", EntryPoint = "FnSurfaceZ", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] private static extern int FnSurfaceZ(ref DPoint3d point3d, int surfaceId); public bool SurfaceZ(ref BCOM.Point3d point, int surfaceId) { int answer = FnSurfaceZ(ref point, surfaceId); //return true or false indicating the success of the operation return (answer == SUCCESS); }
This can however not be used for struct arrays.
I prefer the first mechanism because then passing points or arrays of points follows the same logic, and I have control over how it happens.
HTH,
Francois