问题描述
C++dll的头文件接口描述如下:#pragmapack(push,1)typedefstructXCtrlStatus{XCtrlStatus(unsignedlongV=0){*reinterpret_cast<unsignedlong*>(this)=V;}unsignedcharERR:1;unsignedcharAUTO:1;unsignedcharRUN:2;unsignedcharDIR:2;unsignedchar:1;unsignedchar:1;unsignedcharCTRL:8;unsignedchar:8;unsignedchar:8;operatorunsignedlong()const{return*reinterpret_cast<constunsignedlong*>(this);}}XCtrlStatus;typedefstructXRWSwitch{XRWSwitch(unsignedshortV=0){*reinterpret_cast<unsignedshort*>(this)=V;}unsignedchar:1;unsignedcharOVERLOAD:1;unsignedchar:5;unsignedcharCOLD:1;unsignedcharSCREW:2;unsignedcharGRIP2:2;unsignedcharGRIP1:2;unsignedcharPUMP2:1;unsignedcharPUMP1:1;operatorunsignedshort()const{return*reinterpret_cast<constunsignedshort*>(this);}}XRWSwitch;typedefstructXRSwitchIn{XRSwitchIn(unsignedshortV=0){*reinterpret_cast<unsignedshort*>(this)=V;};unsignedcharRIN_0:1;unsignedcharRIN_1:1;unsignedcharRIN_2:1;unsignedcharRIN_3:1;unsignedcharRIN_4:1;unsignedcharRIN_5:1;unsignedcharRIN_6:1;unsignedcharRIN_7:1;unsignedcharRIN_8:1;unsignedcharRIN_9:1;unsignedcharRIN_A:1;unsignedcharRIN_B:1;unsignedcharRIN_C:1;unsignedcharRIN_D:1;unsignedcharRIN_E:1;unsignedcharRIN_F:1;operatorunsignedshort()const{return*reinterpret_cast<constunsignedshort*>(this);}}XRSwitchIn;typedefstructXRSwitchOut{XRSwitchOut(unsignedshortV=0){*reinterpret_cast<unsignedshort*>(this)=V;};unsignedcharROUT_0:1;unsignedcharROUT_1:1;unsignedcharROUT_2:1;unsignedcharROUT_3:1;unsignedcharROUT_4:1;unsignedcharROUT_5:1;unsignedcharROUT_6:1;unsignedcharROUT_7:1;unsignedcharROUT_8:1;unsignedcharROUT_9:1;unsignedcharROUT_A:1;unsignedcharROUT_B:1;unsignedcharROUT_C:1;unsignedcharROUT_D:1;unsignedcharROUT_E:1;unsignedcharROUT_F:1;operatorunsignedshort()const{return*reinterpret_cast<constunsignedshort*>(this);}}XRSwitchOut;typedefstructXSampleHead{XCtrlStatusStatus;XRSwitchInwRSwitchIn;XRSwitchOutwRSwitchOut;XRWSwitchwRWSwitch;longnControl;unsignedlongdwTimeBase;unsignedshortwReserved;}XSampleHead,*PXSampleHead;typedefconstXSampleHead*PCXSampleHead;typedefstructXSampleV{XSampleHeadHead;floatfSensor[1];}XSampleV,*PXSampleV;typedefconstXSampleV*PCXSampleV;constintXMAX_SENSOR=6;typedefstructXSampleMax_V{XSampleHeadHead;floatfSensor[XMAX_SENSOR];}XSampleMax_V,*PXSampleMax_V;typedefconstXSampleMax_V*PCXSampleMax_V;#pragmapack(pop)typedefunsignedlongXG_RESULT;//函数返回值typedefunsignedlongXG_HANDLE;//设备句柄constXG_RESULTIDX_OK=2000;//表示成功,其他值表示不成功//回调对象,在后台工作者线程中调用,不是在主线程调用structXTopReceivedSink{virtualvoid__stdcallfun1(constvoid*,unsignedlong)=0;//请实现为空函数virtualvoid__stdcallRTM_Sample_Value(PCXSampleVlpcSample,unsignedlongnSensorCount)=0;//请拷贝走数据,尽量短小virtualvoid__stdcallfun3(constvoid*,unsignedchar)=0;//请实现为空函数virtualunsignedchar__stdcallfun5(constvoid*)=0;//请直接返回0virtualunsignedchar__stdcallfun6(char,unsignedchar)=0;//请返直接回0virtualvoid__stdcallfun7(constvoid*,unsignedlong)=0;//请实现为空函数};//如果是采用以太网的方式,请用指定IP地址,如192.168.0.234constTCHAREthernet[]={_T("[Connect]")_T("Dll=EthernetLow.dll;")_T("Type=Host;")_T("IP=%s;")_T("HostPort=7777;")_T("DevicePort=9999;")};//如果是采用串口的方式,请用指定串口号,如COM1constTCHARSerial[]={_T("[Connect]")_T("Dll=SerialLow.dll;")_T("Type=Host;")_T("Port=%s;")_T("Settings=38400,n,8,1;")_T("Addr=1;")};#ifdefEXPLICIT_LOADtypedefXG_RESULT(__stdcall*PGetXTop)(constwchar_t*lpSettings,XG_HANDLE&hTop);typedefXG_RESULT(__stdcall*PFreeXTop)(XG_HANDLEhTop);typedefXTopReceivedSink*(__stdcall*PSetReceivedSink)(XG_HANDLEhTop,XTopReceivedSink*sink);typedefXG_RESULT(__stdcall*PStartRecord)(XG_HANDLEhTop);typedefXG_RESULT(__stdcall*PStopRecord)(XG_HANDLEhTop);typedefXG_RESULT(__stdcall*PGetIndex)(XG_HANDLEhTop,int*Fm,int*FeH,int*FeL,int*Fp,int*E1,int*E2);typedefXG_RESULT(__stdcall*PGetValue)(XG_HANDLEhTop,float*Fm,float*FeH,float*FeL,float*Fp,float*Fd,float*Ek,float*Ed);#elseextern"C"{//获得对象句柄,请为lpSettings传递格式化后的Ethernet或Serial,成功后hTop返回句柄XG_RESULT__stdcallGetXTop(constwchar_t*lpSettings,XG_HANDLE&hTop);//释放对象句柄,对应GetXTop,释放对象句柄之前,请先将回调对象设为0XG_RESULT__stdcallFreeXTop(XG_HANDLEhTop);//设置回调对象,每次有数据到来,都会调用回调对象的RTM_Sample_Value方法//释放对象句柄之前,请先将回调对象设为空XTopReceivedSink*__stdcallSetReceivedSink(XG_HANDLEhTop,XTopReceivedSink*sink);//开始记录数据,StartRecord和StopRecord之间的数据将用于计算结果XG_RESULT__stdcallStartRecord(XG_HANDLEhTop);//结束记录数据,StartRecord和StopRecord之间的数据将用于计算结果XG_RESULT__stdcallStopRecord(XG_HANDLEhTop);//保留XG_RESULT__stdcallGetIndex(XG_HANDLEhTop,int*Fm,int*FeH,int*FeL,int*Fp,int*E1,int*E2);//用StartRecord和StopRecord之间的数据计算结果,分别是://最大力值,上屈服力值,下屈服力值,规定塑性延伸(0.2)力值,规定塑性延伸率截距,弹性段斜率,弹性段截距,不需要可以传空XG_RESULT__stdcallGetValue(XG_HANDLEhTop,float*Fm,float*FeH,float*FeL,float*Fp,float*Fd,float*Ek,float*Ed);}#pragmacomment(lib,"UTMTop.lib")#endif
我的C#声明如下:[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTGetXTop(stringlpSettings,refXG_HANDLEhTop);[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTFreeXTop(XG_HANDLEhTop);//设置回调对象,每次有数据到来,都会调用回调对象的RTM_Sample_Value方法[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternUIntPtrSetReceivedSink(XG_HANDLEhTop,refXTopReceivedSinksink);[StructLayout(LayoutKind.Sequential)]publicclassXTopReceivedSink{publicvoidfun1(IntPtra,uintb){return;}publicdelegatevoidCallbackDelegate(refXSampleMax_VlpcSample,uintnSensorCount);publicCallbackDelegateRTM_Sample_Value;//publicvirtualvoidRTM_Sample_Value(refXSampleVlpcSample,ulongnSensorCount);publicvirtualvoidfun3(IntPtra,byteb){return;}publicvirtualbytefun5(IntPtra){return0;}publicvirtualbytefun6(IntPtra,byteb){return0;}publicvirtualvoidfun7(IntPtra,uintb){return;}}[StructLayout(LayoutKind.Sequential)]publicstructXSampleV{publicXSampleHeadHead;[MarshalAs(UnmanagedType.ByValArray,SizeConst=1)]publicfloat[]fSensor;}[StructLayout(LayoutKind.Sequential)]publicstructXSampleMax_V{publicXSampleHeadHead;[MarshalAs(UnmanagedType.ByValArray,SizeConst=6)]publicfloat[]fSensor;}[StructLayout(LayoutKind.Sequential)]publicstructXSampleHead{XCtrlStatusStatus;XRSwitchInwRSwitchIn;XRSwitchOutwRSwitchOut;XRWSwitchwRWSwitch;intnControl;uintdwTimeBase;ushortwReserved;}[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTStartRecord(XG_HANDLEhTop);[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTStopRecord(XG_HANDLEhTop);[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTGetIndex(XG_HANDLEhTop,refintFm,refintFeH,refintFeL,refintFp,refintE1,refintE2);[DllImport("\ManufacturerDLL\Xingao\UTMTop.dll",SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternXG_RESULTGetValue(XG_HANDLEhTop,reffloatFm,reffloatFeH,reffloatFeL,reffloatFp,reffloatFd,reffloatEk,reffloatEd);///<summary>///dll回调对象///</summary>privateXTopReceivedSinktopReceivedSink;
在C#中初始化没有问题:XG_RESULTi=GetXTop(connect,refhDll);if(hDll!=0){//初始化realDataInitReturnData();//时间计数清0milliCount=0;//回调对象实例化,加载对象中的回调委托topReceivedSink=newXTopReceivedSink();topReceivedSink.RTM_Sample_Value+=newXTopReceivedSink.CallbackDelegate(this.CallBackFunction);//回调对象传入dllSetReceivedSink(hDll,reftopReceivedSink);//通知设备开始记录计算用的采集数据StartRecord(hDll);//读数定时器启动timerReceive.Start();return0;}
已经返回成功,返回成功后应该是C#界面等待timer读取回调返回的数据了,但是没有进入timer事件,就立刻提示“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”请高手帮忙看看是哪里存在问题?是我的C#针对dll的结构声明存在问题么?哪里没有匹配上,求助啊,很着急!!!
解决方案
解决方案二:
修改DllImport中CharSet=CharSet.Unicode,增加CallingConvention=CallingConvention.StdCall再试试看
解决方案三:
“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”这种情况,如果你在调试环境下出现此类提示,点击“继续”即可,可以理解为vs“善意的提醒”。不使用vs承载进程,直接运行release版本,通常就不会发生这样的事情。你也可以在项目设置中的“生成”页,勾上“允许不安全的代码”。
解决方案四:
引用1楼xian_wwq的回复:
修改DllImport中CharSet=CharSet.Unicode,增加CallingConvention=CallingConvention.StdCall再试试看
问题依旧
解决方案五:
引用2楼rocmemory的回复:
“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”这种情况,如果你在调试环境下出现此类提示,点击“继续”即可,可以理解为vs“善意的提醒”。不使用vs承载进程,直接运行release版本,通常就不会发生这样的事情。你也可以在项目设置中的“生成”页,勾上“允许不安全的代码”。
也不行,release下程序直接崩溃了
解决方案六:
C++的dll中XCtrlStatus,XRSwitchIn,XRSwitchOut,XRWSwitch四个结构参见顶楼的C++代码,在C#中我不需要使用这四个结构,但是dll声明必须用到,因为C++中这四个结构本意是整形,然后位移操作,我在C#中将他们直接定义成了整形:usingXCtrlStatus=System.UInt32;usingXRSwitchIn=System.UInt16;usingXRSwitchOut=System.UInt16;usingXRWSwitch=System.UInt16;这对调用dll是否有影响?