c#调用C++动态链接库出现尝试读取或写入受保护的内存

馨宝宝 2018-04-08 10:09:08
c++定义的动态库:
// 功能描述:获取测量值。
// 输入参数:devID,设备编号;
// channel,通道号,从 1~32;
// pBuf Len, 数值缓冲区长度
// 输出参数:pbDevIsRunning,设备运行状态,TRUE:运行,FALSE:停止
// pTempVal,保存的采集值;
// pBufLen,实际的采集数值点的数目
// pChannelDistance,通道的是即距离,单位为m,该值为一个实际距离值的整数部分
// pChannelPoints,通道的实际点数,该值为实际的点数值。
//返 回 值:成功返回 1;失败返回负数; -1:获取失败
DR_API int GetVal (int devID, unsigned char channel, bool *pbDevIsRunning, int* pChannelDistance, int* pChannelPoints, double* pTempVal, int* pBufLen);


(功能描述:点击btnSetStartCollect后启动Timer,在Timer中循环调用GetVal获取测量值(pTempVal)。其中devID, channel已在调用其他函数后获取到,这里带入是有值的)
在c#中的调用:

public static int devID; //在调用函数后 存储设备号devID
public static bool DeviceSatus; //在调用函数后 存储bDevIsRunning

const int MAX_CHANNEL=4;
//导入DLL
[DllImport("DTSDS_Request.dll", EntryPoint = "GetVal", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int GetVal(int devID, byte channel, ref bool pbDevIsRunning, int[] pChannelDistance, int[] pChannelPoints, double[] pTempVal, ref int pBufLen);

private void Form1_Load(object sender, EventArgs e)
{
RecieveTimer.Enabled = false;
RecieveTimer.Interval = 1000;
}

private void btnSetStartCollect_Click(object sender, EventArgs e)
{
RecieveTimer.Enabled = true;
// 功能描述:控制设备启动采集或停止采集
// 输入参数:devID,设备编号;
// bStart,TRUE 启动采集,FALSE 停止采集;
// 返回值:成功返回TRUE;失败返回FALSE;
bool inf = DTS_SetStartCollect(devID, true);
labCurrentStatue.Text="返回值:\r\n" + inf +" TRUE 启动采集,FALSE 停止采集 ";
RecieveTimer.Start();
}

public static bool pbDevIsRunning;

public static double[] pTempVal=new double[10000];

public static int[] ChannelDistance = new int[MAX_CHANNEL];
public static int[] ChannelPoints = new int[MAX_CHANNEL];
public static int pBufLen = 0;
public static double[] CopyTempVal;
public static double[] ReTempVal;
//CopyTempVal = new double[pTempVal.Length]; ReTempVal = new double[pTempVal.Length]; 这两个数组在前面初始化设备的时候已经定义好长度,空间已申请

private void RecieveTimer_Tick(object sender, EventArgs e)
{
//读通道号
byte channel = byte.Parse(textBox7.Text);
//读数据
int inf = GetVal(devID, channel,ref DeviceSatus, ChannelDistance, ChannelPoints, pTempVal, ref pBufLen);
CopyTempVal = (double[])pTempVal.Clone();

ReTempVal = new double[CopyTempVal.Length];
int i = 0;
foreach (double v in CopyTempVal)
{
ReTempVal[i] = v + 1;
i++;
}
//画到chart上
TempChart.Series[0].Points.DataBindY(CopyTempVal);
TempChart.Series[1].Points.DataBindY(ReTempVal);
}


可以在前几次调用GetVal后得到需要的pTempVal,在循环几次后timer回调的时候报错(10次内必报错),一般在下面地方报错(出现内存读写错误c0000005)
 
CopyTempVal = (double[])pTempVal.Clone();

ReTempVal = new double[CopyTempVal.Length];
int i = 0;
foreach (double v in CopyTempVal)
{
ReTempVal[i] = v + 1;
i++;
}
//画到chart上
TempChart.Series[0].Points.DataBindY(CopyTempVal);
TempChart.Series[1].Points.DataBindY(ReTempVal);

我怀疑是自己类型转换出错,但是也没找到,c++的double*可以转为c#的double[]吧?每次单次读取就没什么问题,一旦放在timer里循环就报错。求各位大神帮看一下!!
...全文
515 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
馨宝宝 2018-04-10
  • 打赏
  • 举报
回复
引用 1 楼 qq_26671507 的回复:
double*是指针,C#里对应InPtr,用这个来接收读取数据.
请问那我定义了 public static IntPtr pTempval; [DllImport("DTSDS_Request.dll", EntryPoint = "GetVal", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)] private static extern int GetVal(int devID, byte channel, ref bool pbDevIsRunning, int[] pChannelDistance, int[] pChannelPoints, IntPtr pTempVal, ref int pBufLen); 然后如何读pTempval里面的数组呢?
xian_wwq 2018-04-10
  • 打赏
  • 举报
回复
IntPtr需要先分配空间 给你个读结构体的示例

// API
[DllImport(RTDB_DLL,EntryPoint = 'DBPT_GetTagsBaseAttribute',CharSet = CharSet.Ansi,CallingConvention= CallingConvention.StdCall]  
public static extern int GetTagsAttributeWithPtr(int nHandle,int nTagCount,[In,Out] int[] errorArray,IntPtr TagAttr[] TagAttary);  

//Sample code
int size = Marshal.SizeOf(typedef(TagAttr)) ;  
IntPtr attrInput = Mashal.AllocHGlobal(count*size);  
DBPT.GetTagsAttributeWithPtr(nHandle,count,out errors,ids, attrInput);  
for(int i = 0;i< count;i++)  
{  
    IntPtr ptr = (IntPtr)((UInt32)attrInput + i* size);  
    tagsArray[i] = (TagAttr)Mashal.PtrToStructure(ptr,typeof(TagAttr));  
}  
Marshal.FreeHGlobal(attrInput);  

xian_wwq 2018-04-10
  • 打赏
  • 举报
回复
个人感觉问题出在pTempVal lz可以修改为每次调用前new试下
qq_26671507 2018-04-08
  • 打赏
  • 举报
回复
double*是指针,C#里对应InPtr,用这个来接收读取数据.

110,539

社区成员

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

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

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