c#结构体数组转IntPtr 接收c++dll 函数返回值报错问题

cvsntjava 2018-05-22 12:00:05
这是c++的函数定义:

这是一个检测图片中关键目标的函数
int HXDetect(BYTE* pImage,TargetPos* pfps);

这是结构体的定义:

typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;

struct FaceAngle
{
int yaw;
int pitch;
int roll;
float confidence;
};

struct TargetPos
{
RECT rcFace;
POINT ptLeftEye;
FaceAngle fAngle;
int nQuality;
BYTE pFacialData[512];
TargetPos()
{
memset(&rcFace,0,sizeof(RECT));
memset(&ptLeftEye,0,sizeof(POINT));
memset(&fAngle,0,sizeof(FaceAngle));
nQuality=0;
memset(pFacialData, 0, 512);

}
};

这是调用的代码:
TargetPos ptfp[10];
HXDetect(im.data,ptfp);
//im.data是图片的rgb24 buffer,ptfp是用来接收函数检测到目标的信息
==============================================================================
以上c++代码结束:

下面是我封装的c#的结构体和调用函数
检测接口的调用函数:
[DllImport(DLLName, EntryPoint = "HXDetect")]
public static extern int HXDetect(IntPtr pImage,IntPtr pos);

c#转换的结构体:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet = System.Runtime.InteropServices.CharSet.Ansi,
Pack =1)]
public struct TargetPos
{
public RECT rcFace;
public POINT ptLeftEye;
public FaceAngle fAngle;
int nQuality;
byte[] pFacialData;
public void init()
{
rcFace = new RECT();
ptLeftEye = new POINT();
fAngle = new FaceAngle();
nQuality = 0;
pFacialData = new byte[512];
}
};

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct POINT
{
public int x;
public int y;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct FaceAngle
{
int yaw;
int pitch;
int roll;
float confidence;
};

c#调用检测函数的代码:
void detect(){
int arraySize = 10;
TargetPos[] PosArray = new TargetPos[arraySize];
for (int i = 0; i < PosArray.Length; i++)
{
var facePos = PosArray[i];
facePos.init();
}
IntPtr facePtr = MarshalArray(PosArray);
int faceNum = HXDetect(bmpDataPtr, facePtr);
}


unsafe private static IntPtr MarshalArray(TargetPos[] bodies)
{
int iSizeOfOneBodyPos = Marshal.SizeOf(typeof(TargetPos));
int iTotalSize = iSizeOfOneBodyPos * bodies.Length;
IntPtr pUnmanagedBodies = Marshal.AllocHGlobal(iTotalSize);
byte* pbyUnmanagedBodies = (byte*)(pUnmanagedBodies.ToPointer());

for (int i = 0; i < bodies.Length; i++, pbyUnmanagedBodies += (iSizeOfOneBodyPos))
{
IntPtr pOneBodyPos = new IntPtr(pbyUnmanagedBodies);
Marshal.StructureToPtr(bodies[i], pOneBodyPos, false);
}

return pUnmanagedBodies;
}


c++的函数可以正常运行,c#调用的时候会报以下错误:

“System.AccessViolationException”类型的未经处理的异常在 mscorlib.dll 中发生

其他信息: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。


怀疑是TargetPos这个结构体的定义和内存空间的申请代码有问题,往有经验的朋友能够帮忙解答,

很惭愧,一点微小的积分奉上不成敬意。
...全文
1322 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Saleayas 2018-05-25
  • 打赏
  • 举报
回复
如果你需要封送数组,那么数组的大小呢?
Saleayas 2018-05-22
  • 打赏
  • 举报
回复
使用 MarshalAs 特性描述结构中的数组。 比如: [ MarshalAs( UnmanagedType.ByValArray, SizeConst=512 )] 来描述 byte XXX[512] 这样的数组。 使用 ref/out 使得 struct 变成引用,或者直接定义为 class 。 不要使用使用 IntPtr 自己来传递数据。 C++ 的导出函数参数其实需要 IN/OUT 说明的。
cvsntjava 2018-05-22
  • 打赏
  • 举报
回复
public struct THFI_FacePos { public RECT rcFace; public POINT ptLeftEye; public POINT ptRightEye; public POINT ptMouth; public POINT ptNose; public FaceAngle fAngle; int nQuality; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] byte[] pFacialData; }; [DllImport(DLLName, EntryPoint = "HXDetect")] public static extern int HXDetect(IntPtr pImage,[In,Out] TargetPos[] posArray); 我现在这么写还是会报错,RECT,POINT这些参数需要用MarshalAs描述吗?
#region 导入API函数 [DllImport("avicap32.dll")]//包含了执行视频捕获的函数,它给AVI文件I/O和视频、音频设备驱动程序提供一个高级接口 public static extern IntPtr capCreateCaptureWindow(string lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hwndParent, int nID); /************参数说明************* * * 函数:capCreateCaptureWindow * * lpszWindowName:标识窗口的名称 * dwStyle:标识窗口风格 * x、y:标识窗口的左上角坐标 * nWidth、nHeight:标识窗口的宽度和高度 * hWnd:标识父窗口句柄 * nID:标识窗口ID * * 返回值:视频捕捉窗口句柄。 * ********************************/ [DllImport("AVICAP32.dll", CharSet = CharSet.Unicode)] public static extern bool capGetDriverDescription(int wDriverIndex, StringBuilder lpszName, int cbName, StringBuilder lpszVer, int cbVer); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, bool wParam, int lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, int lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, short wParam, FrameEventHandler lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref BITMAPINFO lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPDRIVERCAPS lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPTUREPARMS lParam); [DllImport("User32.dll")] public static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref CAPSTATUS lParam); [DllImport("User32.dll")] public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags); [DllImport("avicap32.dll")] public static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize); #endregion

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧