我正在尝试将具有 C 调用约定的 C++ 库移植到 c#
该项目位于 https://github.com/Esri/lepcc
我正在尝试移植示例 C++ 应用程序并使用 Lepcc C++ 项目中的 .DLL。
当应用程序结束时,我遇到访问冲突(内存损坏),但变量 ptVec 中的数据是正确的并且与 C++ 示例应用程序匹配,因此我部分存在。
我已经在示例代码中找到了此 C++ 函数的问题,该函数在调用时会导致访问冲突。
vector<Point3D> ptVec(nPts);
errCode = (ErrCode)lepcc_decodeXYZ(ctx, &ptr, (int)(len - pos), &nPts, (double*)(&ptVec[0]));
C++ 方法声明如下所示
lepcc_status lepcc_decodeXYZ(lepcc_ContextHdl _ctx, const unsigned char** ppByte, int bufferSize,
unsigned int* nPtsInOut, double* xyzBuffOut)
在 c# 中,我已将调用翻译为以下内容(可能正确,也可能不正确)
[DllImport(LepccDll, CallingConvention = CallingConvention.Cdecl)]
public static extern lepcc_status lepcc_decodeXYZ(IntPtr ctx, ref IntPtr ppByte, int bufferSize,
ref uint nPtsInOut, double[] xyzBuffOut);
和我的 C# 调用实现
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);
我的 DllImport 看起来正确吗?我已经超出了我的深度。
我通过大量的试验和错误发现了以下内容。
在 C++ api 中,deleteContext 方法是这样声明的
void lepcc_deleteContext(lepcc_ContextHdl* ctx)
{
delete reinterpret_cast<CtxImpl*>(*ctx);
*ctx = nullptr;
}
并像这样使用
lepcc_ContextHdl ctx = lepcc_createContext();
lepcc_deleteContext(&ctx);
但是在c#中
[DllImport(LepccDll, CallingConvention = callingConvension)]
public static extern void lepcc_deleteContext(IntPtr ctx);
并这样称呼
LepccInterop.lepcc_deleteContext(ctx);
这些不一样 - 在 C++ 中我们传递 ctx 的地址,但在 C# 中我传递 IntPtr
所以在 c# 中我应该调用这样的 C++ 方法(注意没有 *)
void lepcc_deleteContext(lepcc_ContextHdl ctx)
{
delete reinterpret_cast<CtxImpl*>(ctx);
//*ctx = nullptr;
}
然后它就可以工作了,没有例外。我不知道如何处理 C# 中的 * 到 ctx
我无法使用以下
lepcc_deleteContext(&ctx);