对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。
最近在写一个海康的门禁的自动监控刷卡事件的程序。
因为用c#写的,大家都知道c#是垃圾自动回收的。海康提供的api是用c++写的,要将处理的回调代码委托给api 。刚开始的时候很顺利,但当运行一段时间就会报以下错误:
对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。
大致的原因是:c#把回调函数资源回收了,导致api收到事件的时候执行回调出错。
网上的解决方案是将回调方法写成static的(静态方法)。但我这里不行。
最后还是微软官方的解决方法可靠:
除了设置成static的还要在代码后加:GC.KeepAlive(dev);
public static void MsgCallback(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser) { try { switch (lCommand) { case CHCNetSDK.COMM_ALARM_ACS: ProcessCommAlarmACS(ref pAlarmer, pAlarmInfo, dwBufLen, pUser); break; default: break; } } catch (System.Exception ex) { Program.WriteLog(0, "处理事件报错:" + ex); } }
private void StartRead() { Program.LocalWriteLog("进入StartRead..........."); zd.zd api = new zd.zd(); for (int i = 0; i < _listDoors.Count; i++) { Door d = _listDoors[i]; if (!d.isLogon) { CHCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new CHCNetSDK.NET_DVR_USER_LOGIN_INFO(); loginInfo.wPort = Convert.ToUInt16(d.cPort); loginInfo.sDeviceAddress = d.cIP; loginInfo.sUserName = d.cLoginUser; loginInfo.sPassword = d.cLoginPassword; try { switch (i) { case 0: this._arLoginDevices[i] = new Device00(loginInfo); break; case 1: this._arLoginDevices[i] = new Device01(loginInfo); break; case 2: this._arLoginDevices[i] = new Device02(loginInfo); break; case 3: this._arLoginDevices[i] = new Device03(loginInfo); break; case 4: this._arLoginDevices[i] = new Device04(loginInfo); break; case 5: this._arLoginDevices[i] = new Device05(loginInfo); break; case 6: this._arLoginDevices[i] = new Device06(loginInfo); break; case 7: this._arLoginDevices[i] = new Device07(loginInfo); break; case 8: this._arLoginDevices[i] = new Device08(loginInfo); break; default: this._arLoginDevices[i] = new Device09(loginInfo); break; } //this.listGch.Add(GCHandle.Alloc(this._arLoginDevices[i])); Program.LocalWriteLog("加入设备:" + loginInfo.sDeviceAddress); } catch (System.Exception ex) { string cMsg = "加入设备出错:IP," + loginInfo.sDeviceAddress + ",信息:" + ex.Message; Program.LocalWriteLog(cMsg); api.AddLog(_key,0,cMsg); } } } int j=0; while (true) { foreach (var dev in this._arLoginDevices) { if (dev == null) { continue; } if (!dev.IsLogin) { try { dev.Login(); } catch (System.Exception ex) { string cMsg = "登录设备出错:IP," + dev.DeviceLoginInfo.sDeviceAddress + ",信息:" + ex.Message; Program.LocalWriteLog(cMsg); api.AddLog(_key, 0, cMsg); } } if (dev.IsLogin && !dev.IsGuard) { try { dev.Guard(); } catch (System.Exception ex) { string cMsg = "监控设备出错:IP," + dev.DeviceLoginInfo.sDeviceAddress + ",信息:" + ex.Message; Program.LocalWriteLog(cMsg); api.AddLog(_key, 0, cMsg); } } GC.KeepAlive(dev); } System.Threading.Thread.Sleep(5 * 1000); } Program.LocalWriteLog("正常退出"); }