Issues with trying to port LEPCC from GitHub to C# - DllImport issues / access violation

47 Views Asked by At

I am trying to port a C++ library with a C calling convention to C#.

The project is at https://github.com/Esri/lepcc

I am trying to port the sample C++ application and use the .DLL from the Lepcc C++ project.

I am getting an access violation (memory corrupt) when the application ends but the data in the variable ptVec is correct and matches the C++ sample application so I am partly there.

I have tracked down the issue to this C++ function in the sample code which when called causes the access violation.

vector<Point3D> ptVec(nPts);
errCode = (ErrCode)lepcc_decodeXYZ(ctx, &ptr, (int)(len - pos), &nPts, (double*)(&ptVec[0]));

The C++ method declaration looks like this

lepcc_status lepcc_decodeXYZ(lepcc_ContextHdl _ctx, const unsigned char** ppByte, int bufferSize,
 unsigned int* nPtsInOut, double* xyzBuffOut)

In C# I have translated the call to the following (may or may not be correct)

[DllImport(LepccDll, CallingConvention = CallingConvention.Cdecl)]
public static extern lepcc_status lepcc_decodeXYZ(IntPtr ctx, ref IntPtr ppByte, int bufferSize,
 ref uint nPtsInOut, double[] xyzBuffOut);

and my C# calling implementation

var slpkBytes = System.IO.File.ReadAllBytes(fnIn);
long slpkLength = new FileInfo(fnIn).Length;
IntPtr ctx = LepccInterop.lepcc_createContext();
GCHandle slpkBytesPinned = GCHandle.Alloc(slpkBytes, GCHandleType.Pinned);
IntPtr ptr = slpkBytesPinned.AddrOfPinnedObject() + pos;

double[] ptVec = new double[(int)nPts * 3];
errCode = (ErrorCode)LepccInterop.lepcc_decodeXYZ(ctx, ref ptr, (int)(slpkLength - pos), ref nPts, ptVec);

slpkBytesPinned.Free();
LepccInterop.lepcc_deleteContext(ctx);           

Does my DllImport look correct? I am out of my depth here.

2

There are 2 best solutions below

1
chris crowe On

I found the following through a lot of trial and error.

in C++ api the deleteContext method was declared like this

void lepcc_deleteContext(lepcc_ContextHdl* ctx)
{
    delete reinterpret_cast<CtxImpl*>(*ctx);
    *ctx = nullptr;
}

and used like this

lepcc_ContextHdl ctx = lepcc_createContext();
lepcc_deleteContext(&ctx);

But in c# I declared it like this

[DllImport(LepccDll, CallingConvention = callingConvension)]
public static extern void lepcc_deleteContext(IntPtr ctx);

and called like this

  LepccInterop.lepcc_deleteContext(ctx);

These are not the same - in c++ we pass the address of the ctx, but in c# I pass an IntPtr

The fix for me was to call it with a ref

LepccInterop.lepcc_deleteContext(ref ctx);
0
sync On

double* xyzBuffOut should marshaling to IntPtr,and invoke Marahl.AllocHGlobal(xxx) to alloc unmanaged memory

if you use new double[(int)nPts * 3],it is managed memory.