c# 调用C++ 结构体指针的问题: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏

c++结构体:typedefstruct_vehicles_info{intidx;/**车牌号码*/charvehicle_name[32];/**rtsp信息*/ch... c++ 结构体:
typedef struct _vehicles_info
{
int idx;
/*
* 车牌号码
*/
char vehicle_name[32];
/*
* rtsp信息
*/
char vehicle_rtsp[256];
//0 offline, 1 online
Byte status;
}VehicleInfo;
方法:int GetVehiclesInfo(VehicleInfo *pVehicle, int size);

转为C#方法后的代码如下:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe struct VehicleInfo
{
public int idx;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string vehicle_name;//车牌号码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string vehicle_rtsp;//rtsp信息
public byte bstatus;//0 offline, 1 online
};
方法:
[DllImport("UserClient.dll", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int GetVehiclesInfo(IntPtr[] p, int size);

调用代码如下:
IntPtr[] record = new IntPtr[isize]; //申请内存空间
record[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BwsPtzManager.VehicleInfo)) * isize);
int realcount = BwsPtzManager.GetVehiclesInfo(record, isize);
for (int i = 0; i < realcount; i++)
{
BwsPtzManager.VehicleInfo vehinfo = new BwsPtzManager.VehicleInfo();

vehinfo = (BwsPtzManager.VehicleInfo)Marshal.PtrToStructure((IntPtr)((UInt32)record[i]), typeof(BwsPtzManager.VehicleInfo));
Marshal.FreeHGlobal(record[i]);
}
问题来了:代码运行到 vehinfo = (BwsPtzManager.VehicleInfo)Marshal.PtrToStructure((IntPtr)((UInt32)record[i]), typeof(BwsPtzManager.VehicleInfo)); 这里的时候,总是报 “尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的错误,求大神指点。已经折腾的快挂了。总找不到原因。
另附c++代码如下:
VehicleInfo *pVehicle = (VehicleInfo*)malloc(sizeof(VehicleInfo)*count) ;
memset(pVehicle, 0x00, sizeof(VehicleInfo)*count);
int realcount = GetVehiclesInfo(pVehicle, count);
printf("%d\n", realcount);
for(int i = 0; i < realcount; i++)
{
printf("%s,%s,%d\n", pVehicle[i].vehicle_name,pVehicle[i].vehicle_rtsp,pVehicle[i].status );
}
运行一切正常,没任何问题。神救救我吧
展开
 我来答
wangnasa
推荐于2016-10-24 · TA获得超过776个赞
知道小有建树答主
回答量:732
采纳率:100%
帮助的人:637万
展开全部

我用你的代码验证了一下我的猜测。

有两处错误

1 c++的dll 方法:int GetVehiclesInfo(VehicleInfo *pVehicle, int size);

参数是指针数组 应该使用 VehicleInfo **pVehicle

所以应该为int GetVehiclesInfo(VehicleInfo **pVehicle, int size);

DLL中的方法 为了测试加了一个MessageBoxA

VEC_API int GetVehiclesInfo(VehicleInfo **pVehicle, int size)

{

for(int i =0;i<size;i++)

{

pVehicle[i]->vehicle_name[0]='H';

pVehicle[i]->vehicle_name[1]='A';

pVehicle[i]->vehicle_name[2]='U';

pVehicle[i]->vehicle_name[3]='0';

pVehicle[i]->vehicle_name[4]='9';

pVehicle[i]->vehicle_name[5]='8';

pVehicle[i]->idx=1;

pVehicle[i]->vehicle_rtsp[0]='1';

pVehicle[i]->vehicle_rtsp[1]='2';

}

string s(pVehicle[0]->vehicle_rtsp);

MessageBoxA(NULL,pVehicle[0]->vehicle_name,"pVehicle[0]的车牌号码是",0); 

return 0;

}


2 c#

record[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BwsPtzManager.VehicleInfo)) * isize);


像这样分配地址是不对的 ,这样只是给record[0] 分配了  record[size] 长度地址空间

而并没有给 record[1]~ record[size-1]分配空间

所以应该为

 IntPtr[] record = new IntPtr[isize]; //申请内存空间

 for (int i = 0; i < isize; i++)

 {

       record[i] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VehicleInfo)));

 } 

按钮事件:

 private void button1_Click(object sender, EventArgs e)

        {

            int isize=5;

            IntPtr[] record = new IntPtr[isize]; //申请内存空间

            for (int i = 0; i < isize; i++)

            {

                record[i] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VehicleInfo)));

            }

            int realcount = GetVehiclesInfo(record, isize);

            for (int i = 0; i < realcount; i++)

            {

                VehicleInfo vehinfo = new VehicleInfo();

                vehinfo = (VehicleInfo)Marshal.PtrToStructure((IntPtr)((UInt32)record[i]), typeof(VehicleInfo));

                Marshal.FreeHGlobal(record[i]);

            }

        }

        [DllImport("vec.dll", CallingConvention = CallingConvention.Cdecl)]

        public unsafe static extern int GetVehiclesInfo(  IntPtr[] p, int size); 

追问
首先很感谢您的回答,很详细.我还有个疑问
int GetVehiclesInfo(VehicleInfo *pVehicle, int size);
这个接口既然有问题的话,C++代码调用为何没有问题呢?因为这个接口不是我写的,所以要让别人改接口,必须证明他这个写法确实是错的.
追答
因为C#传的是指针数组 ,而C++的调用是传的指针分配空间的首地址。所以不是他这样写不正确,是想让C++和C#都能用,就只能用指针数组。
guodxu
2012-09-07
知道答主
回答量:31
采纳率:0%
帮助的人:14.8万
展开全部
你只申请了record[0]的空间,1~isize的空间没有申请,使用使为默认值(null)肯定出问题了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式