问题描述
请教大家一个问题,现在有个C++PCIDLL.dll文件,在C#中调用dll,老是出现错误如下:System.AccessViolationException:Attemptedtoreadorwriteprotectedmemory.Thisisoftenanindicationthatothermemoryiscorrupt.请问C#代码哪里有误,我试了几天都没解决,烦请高手指点,谢谢!C++Code:结构体:------------------------------------------typedefstruct_DEV_CTRL_PARAM{intScanType;intSelChannel[12];intmParamType;int*mEtalonPeakNum;float*p_EtalonPeakVal;}DEV_CTRL_PARAM,*PDEV_CTRL_PARAM;externBOOL_stdcallPci_InitDevice(intmDev,PDEV_CTRL_PARAMpParam);调用:--------------------------------------------intmEtalonPeakNum=0;floatEtalonPeakVal[400];DEV_CTRL_PARAMmParam;inttemptype[7]={6,5,4,3,2,1,0};mParam.ScanType=3;mParam.mParamType=0;mParam.mEtalonPeakNum=&mEtalonPeakNum;mParam.p_EtalonPeakVal=EtalonPeakVal;mParam.SelChannel[0]=1;mParam.SelChannel[1]=1;mParam.SelChannel[2]=1;mParam.SelChannel[3]=1;mParam.SelChannel[4]=1;mParam.SelChannel[5]=1;mParam.SelChannel[6]=1;mParam.SelChannel[7]=1;mParam.SelChannel[8]=1;mParam.SelChannel[9]=1;mParam.SelChannel[10]=0;mParam.SelChannel[11]=0;Pci_InitDevice(0,&mParam);----------------------------------------------------------------------------------C#Code:结构体:--------------[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]publicstructDEV_CTRL_PARAM{publicintScanType;[MarshalAs(UnmanagedType.ByValArray,ArraySubType=UnmanagedType.I4,SizeConst=12)]publicint[]SelChannel;publicintmParamType;publicIntPtrmEtalonPeakNum;publicIntPtrp_EtalonPeakVal;}[DllImport("PCIDLL.dll")]publicstaticexternboolPci_InitDevice(intmDev,refDEV_CTRL_PARAMpParam);调用:------------------------DEV_CTRL_PARAMmParam;mParam.SelChannel=newint[12];intmEtalonPeakNum=0;float[]EtalonPeakVal=newfloat[400];int[]temptype=newint[7]{6,5,4,3,2,1,0};mParam.ScanType=3;mParam.mParamType=0;mParam.mEtalonPeakNum=(IntPtr)mEtalonPeakNum;mParam.p_EtalonPeakVal=Marshal.UnsafeAddrOfPinnedArrayElement(EtalonPeakVal,0);mParam.SelChannel[0]=1;mParam.SelChannel[1]=1;mParam.SelChannel[2]=1;mParam.SelChannel[3]=1;mParam.SelChannel[4]=1;mParam.SelChannel[5]=1;mParam.SelChannel[6]=1;mParam.SelChannel[7]=1;mParam.SelChannel[8]=1;mParam.SelChannel[9]=1;mParam.SelChannel[10]=0;mParam.SelChannel[11]=0;Pci_InitDevice(0,refmParam);
解决方案
本帖最后由 wuyiming8 于 2012-01-16 16:18:54 编辑
解决方案二:
两个办法1,SelChannel用fixed关键字声明2,不用ref,直接使用指针至于行不行,我不知道你试试
解决方案三:
mParam.mEtalonPeakNum=(IntPtr)mEtalonPeakNum;mParam.p_EtalonPeakVal=Marshal.UnsafeAddrOfPinnedArrayElement(EtalonPeakVal,0);
不是这样的,需要使用StructToPtr或者PtrToStruct函数。如果是数组,那么需要分配本地内存。AllocCoTaskMem
解决方案四:
不能直接传递数组,可以用指针,或者用下面的办法。传递数组给C++DLL时,传递C#数组的第一个元素和数组长度,并且用ref。由于数组在内存中是连续存放的,DLL获取到第一个元素的ref和数组长度,自己用代码设定一下数组长度。Dll:fun(int[]array,intarrayLength)声明:[DllImport("xxx.dll",CallingConvention=CallingConvention.StdCall)]调用:fun(refarray[0],array.Length)我前几天用这种方法传递数组给delphi的DLL成功,C++应该也一样吧。
解决方案五:
C#中int,好像是32位的,你把那句改成[DllImport("PCIDLL.dll")]publicstaticexternboolPci_InitDevice(int32mDev,refDEV_CTRL_PARAMpParam);我也遇到这个问题的,搞了半天才弄出来的