using Admin.Core.Common; using log4net; using MvCodeReaderSDKNet; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.InteropServices; using System.Text; using UAParser; using static System.Runtime.CompilerServices.RuntimeHelpers; namespace Aucma.Core.Scanner { public class MvCodeHelper { #region 委托事件 #region 条码绑定上位机委托事件 /// /// code1扫码信息刷新 /// /// public delegate void ReceiveCode1(string code1); public static event ReceiveCode1? ReceiveCode1Event; /// /// code2扫码信息刷新,记录表更新 /// /// public delegate void ReceiveCode2(string code2); public static event ReceiveCode2? ReceiveCode2Event; #endregion #region 成品下线上位机委托事件 /// /// code扫码信息刷新 /// /// public delegate void ReceiveCode(string code, int scannerNo); public static event ReceiveCode? ReceiveCodeEvent; #endregion #endregion private static readonly log4net.ILog log = LogManager.GetLogger(typeof(MvCodeHelper)); // 获取到的所有设备 public static MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST m_stDeviceList = new MvCodeReader.MV_CODEREADER_DEVICE_INFO_LIST(); // 连接上的设备和其ip(string)集合 public static Dictionary m_cMyDevices = new Dictionary(); #region 设备连接状态 /// /// 获取不到任务设备即连接失败 /// /// public bool ConnectionStatus(string ip) { // 遍历所有已打开相机 foreach (KeyValuePair hashmap in m_cMyDevices) { if (ip.Equals(hashmap.Value)) { return true; } } return false; } #endregion #region 获取设备列表 /// /// 获取设备列表 /// public static void DeviceListAcqAndOpen() { try { log.Info("获取扫码器设备列表,进入DeviceListAcq()方法"); System.GC.Collect(); m_stDeviceList.nDeviceNum = 0; // 获取设备列表 int nRet = MvCodeReader.MV_CODEREADER_EnumDevices_NET(ref m_stDeviceList, MvCodeReader.MV_CODEREADER_GIGE_DEVICE); if (0 != nRet) { log.Info("获取扫码器列表失败,扫码器错误码:" + nRet); return; } if (0 == m_stDeviceList.nDeviceNum) { log.Info("获取扫码器数量为0,请检查扫码器连接:"); return; } MvCodeReader m_cMyDevice = new MvCodeReader(); //打开所有设备 for (int i = 0; i < m_stDeviceList.nDeviceNum; i++) { MvCodeReader.MV_CODEREADER_DEVICE_INFO stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO)); if (stDevInfo.nTLayerType == MvCodeReader.MV_CODEREADER_GIGE_DEVICE) { IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(stDevInfo.SpecialInfo.stGigEInfo, 0); MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO stGigEDeviceInfo = (MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MvCodeReader.MV_CODEREADER_GIGE_DEVICE_INFO)); // 获取ip string ip = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16) + "." + ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8) + "." + (stGigEDeviceInfo.nCurrentIp & 0x000000ff); // Console.WriteLine($"打印扫码设备信息,下标:{i};IP:{ip}"); log.Info("扫码器设备[" + i + "],ip:" + ip); // 打开第i个设备 stDevInfo = (MvCodeReader.MV_CODEREADER_DEVICE_INFO)Marshal.PtrToStructure(m_stDeviceList.pDeviceInfo[i], typeof(MvCodeReader.MV_CODEREADER_DEVICE_INFO)); nRet = m_cMyDevice.MV_CODEREADER_CreateHandle_NET(ref stDevInfo);//创建设备 if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("创建第" + i + "个扫码器设备失败,ip:" + ip); return; } log.Info("创建第" + i + "个扫码器设备成功,ip:" + ip); nRet = m_cMyDevice.MV_CODEREADER_OpenDevice_NET();//打开设备 if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("打开第" + i + "个扫码器设备失败,销毁设备,ip:" + ip); m_cMyDevice.MV_CODEREADER_DestroyHandle_NET(); return; } else { m_cMyDevices.Add(m_cMyDevice, ip); log.Info("打开第" + i + "个扫码器设备成功,ip:" + ip); } // ch:设置触发模式为off || en:set trigger mode as off if (MvCodeReader.MV_CODEREADER_OK != m_cMyDevice.MV_CODEREADER_SetEnumValue_NET("TriggerMode", 0)) { log.Error("设置第" + i + "个扫码器设备触发模式失败,ip:" + ip); return; } log.Info("第" + i + "个扫码器设备设置采集连续模式成功!ip:" + ip); // ch:开启抓图 | en:start grab nRet = m_cMyDevice.MV_CODEREADER_StartGrabbing_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("设置第" + i + "个扫码器设备开启抓图失败,ip:" + ip); return; } log.Info("*****************************************************************"); log.Info("第" + i + "个扫码器设备创建,打开,开启连续抓图设置成功!ip:" + ip); } } } catch (Exception ex) { log.Error("获取打开设备异常:" + ex); } } #endregion #region 开启扫描 public static void StartGrab() { try { // 所有已打开相机开始扫码 foreach (KeyValuePair hashmap in m_cMyDevices) { Task.Run(() => { // 记录相机上一次扫描到的条码 string lastStr = string.Empty; int nRet = MvCodeReader.MV_CODEREADER_OK; IntPtr pData = IntPtr.Zero; MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2 stFrameInfoEx2 = new MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2(); IntPtr pstFrameInfoEx2 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2))); Marshal.StructureToPtr(stFrameInfoEx2, pstFrameInfoEx2, false); int nCount = 0; while (true) { nRet = hashmap.Key.MV_CODEREADER_GetOneFrameTimeoutEx2_NET(ref pData, pstFrameInfoEx2, 1000); // ch:获取一帧图像 | en:Get one image if (MvCodeReader.MV_CODEREADER_OK == nRet) { stFrameInfoEx2 = (MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)Marshal.PtrToStructure(pstFrameInfoEx2, typeof(MvCodeReader.MV_CODEREADER_IMAGE_OUT_INFO_EX2)); // 分配条码内存空间 MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2 stBcrResult = (MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2)Marshal.PtrToStructure(stFrameInfoEx2.UnparsedBcrList.pstCodeListEx2, typeof(MvCodeReader.MV_CODEREADER_RESULT_BCR_EX2)); for (int i = 0; i < stBcrResult.nCodeNum; ++i) { bool bIsValidUTF8 = IsTextUTF8(stBcrResult.stBcrInfoEx2[i].chCode); if (bIsValidUTF8) { // string strCode = System.Text.Encoding.Default.GetString(stBcrResult.stBcrInfoEx2[i].chCode); string strCode = Encoding.UTF8.GetString(stBcrResult.stBcrInfoEx2[i].chCode); log.Info("bIsValidUTF8:: Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode.Trim().TrimEnd('\0') + "]"); } else { byte[] buffer = new byte[22]; if (stBcrResult.stBcrInfoEx2[i].chCode.Length > 0) { Array.Copy(stBcrResult.stBcrInfoEx2[i].chCode, buffer, 22); } string strCode = Encoding.GetEncoding("UTF-8").GetString(buffer).Trim().TrimEnd('\0'); log.Info("相机ip:" + hashmap.Value + " Get CodeNum: " + "CodeNum[" + i.ToString() + "], CodeString[" + strCode + "]"); if (!string.IsNullOrEmpty(strCode)) { if (strCode != lastStr) { // 处理业务 // 扫码器1,处理扫码器1的业务 if (hashmap.Value.Equals(Appsettings.app("Middleware", "Scanner1", "Ip"))) { #region 条码绑定业务处理 ReceiveCode1Event?.Invoke(strCode); #endregion } else if (hashmap.Value.Equals(Appsettings.app("Middleware", "Scanner2", "Ip"))) // 扫码器2,处理扫码器2的业务 { #region 条码绑定业务处理 ReceiveCode2Event?.Invoke(strCode); #endregion } } lastStr = strCode; } } } } Thread.Sleep(500); } }); } } catch (Exception ex) { log.Error("开启相机扫描异常:" + ex); } } #endregion #region 关闭设备 public static void CloseDevice() { try { log.Info("开始关闭所有设备"); int nRet = MvCodeReader.MV_CODEREADER_OK; // 关闭所有已打开相机 foreach (KeyValuePair hashmap in m_cMyDevices) { // ch:停止抓图 | en:Stop grab image nRet = hashmap.Key.MV_CODEREADER_StopGrabbing_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("设备ip:" + hashmap.Value + "停止抓图失败"); Console.WriteLine("Stop grabbing failed{0:x8}", nRet); } // ch:关闭设备 | en:Close device nRet = hashmap.Key.MV_CODEREADER_CloseDevice_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("设备ip:" + hashmap.Value + "关闭失败"); } // ch:销毁设备 | en:Destroy device nRet = hashmap.Key.MV_CODEREADER_DestroyHandle_NET(); if (MvCodeReader.MV_CODEREADER_OK != nRet) { log.Error("设备ip:" + hashmap.Value + "销毁失败"); } log.Error("设备ip:" + hashmap.Value + "关闭成功!"); } } catch (Exception ex) { log.Error("设备关闭异常:" + ex); } } #endregion #region 判断字符编码 /// /// 判断字符编码 /// /// /// public static bool IsTextUTF8(byte[] inputStream) { int encodingBytesCount = 0; bool allTextsAreASCIIChars = true; for (int i = 0; i < inputStream.Length; i++) { byte current = inputStream[i]; if ((current & 0x80) == 0x80) { allTextsAreASCIIChars = false; } // First byte if (encodingBytesCount == 0) { if ((current & 0x80) == 0) { // ASCII chars, from 0x00-0x7F continue; } if ((current & 0xC0) == 0xC0) { encodingBytesCount = 1; current <<= 2; // More than two bytes used to encoding a unicode char. // Calculate the real length. while ((current & 0x80) == 0x80) { current <<= 1; encodingBytesCount++; } } else { // Invalid bits structure for UTF8 encoding rule. return false; } } else { // Following bytes, must start with 10. if ((current & 0xC0) == 0x80) { encodingBytesCount--; } else { // Invalid bits structure for UTF8 encoding rule. return false; } } } if (encodingBytesCount != 0) { // Invalid bits structure for UTF8 encoding rule. // Wrong following bytes count. return false; } // Although UTF8 supports encoding for ASCII chars, we regard as a input stream, whose contents are all ASCII as default encoding. return !allTextsAreASCIIChars; } #endregion #region 将Byte转换为结构体类型 //将Byte转换为结构体类型 public static object ByteToStruct(byte[] bytes, Type type) { int size = Marshal.SizeOf(type); if (size > bytes.Length) { return null; } //分配结构体内存空间 IntPtr structPtr = Marshal.AllocHGlobal(size); //将byte数组拷贝到分配好的内存空间 Marshal.Copy(bytes, 0, structPtr, size); //将内存空间转换为目标结构体 object obj = Marshal.PtrToStructure(structPtr, type); //释放内存空间 Marshal.FreeHGlobal(structPtr); return obj; } #endregion } }