轮胎外观检测添加思谋语义分割模型检测工具
C3204
7 小时以前 98c0775fe3b61a37d90dd5756287f385a311adf0
LB_SmartVision/VisionForm.cs
@@ -1,6 +1,7 @@
using HalconDotNet;
using LB_SmartVision.Forms;
using LB_SmartVision.Forms.Pages;
using LB_SmartVision.Forms.Pages.BarcodeReaderPage;
using LB_SmartVision.Forms.Pages.CameraPage;
using LB_SmartVision.Forms.Pages.CommunicatorPage;
using LB_SmartVision.Forms.Pages.HistoricalData;
@@ -13,9 +14,12 @@
using LB_SmartVision.ProcessRun;
using LB_SmartVision.SQL;
using LB_SmartVision.Tool;
using LB_SmartVisionCameraDevice.PHM6000;
using LB_SmartVisionCommon;
using LB_SmartVisionLoginUI;
using LB_VisionProcesses;
using LB_VisionProcesses.BarcodeReaders;
using LB_VisionProcesses.BarcodeReaders.Huayray;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Cameras.HikCameras;
using LB_VisionProcesses.Cameras.HRCameras;
@@ -51,10 +55,12 @@
{
    public partial class VisionForm : Form
    {
        #region  Variable
        public string NowBom = string.Empty;
        AllProcessesPage AllProcessesPage = new AllProcessesPage();
        CamerasEditPage CamerasEditPage = new CamerasEditPage();
        BarcodeReadersEditPage BarcodeReadersEditPage = new BarcodeReadersEditPage();
        HistoricalDataEditPage HistoricalDataEditPage = new HistoricalDataEditPage();
        CommunicatorsEditPage CommunicatorsEditPage = new CommunicatorsEditPage();
        SettingEditPage SettingEditPage = new SettingEditPage();
@@ -77,6 +83,8 @@
        // 窗体类的全局变量:标记是否允许切换Tab(默认允许)
        private bool _isTabSwitchAllowed = true;
        #endregion
        public VisionForm()
        {
            InitializeComponent();
@@ -94,10 +102,15 @@
            HistoricalDataEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(HistoricalDataEditPage));
            lEDLightSourceControlEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(lEDLightSourceControlEditPage));
            CamerasEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(CamerasEditPage));
            BarcodeReadersEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(BarcodeReadersEditPage));
            CommunicatorsEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(CommunicatorsEditPage));
@@ -743,6 +756,15 @@
            LB_SmartVision.Tool.Tool.ReadStringConfig("User ID", out string User_ID);
            LB_SmartVision.Tool.Tool.ReadStringConfig("Password", out string Password);
            GlobalVar.strProductName = DateBaseName;
            //加载LB相机参数
            if (LoadAllLBCameras(GlobalVar.allCamerasLBPath))
            {
                LogInfo("LB3D相机配置文件加载成功!", LogInfoType.PASS);
            }
            else
            {
                LogInfo("LB3D相机配置文件加载失败", LogInfoType.ERROR);
            }
            //加载通讯
            foreach (BaseCommunicator com in GlobalVar.dicCommunicators.Values)
            {
@@ -770,6 +792,20 @@
            else
            {
                LogInfo("相机加载失败", LogInfoType.ERROR);
            }
            //加载读码器
            foreach (var reader in GlobalVar.dicBarcodeReaders.Values)
            {
                reader.Dispose();
            }
            GlobalVar.dicBarcodeReaders.Clear();
            if (LoadAllBarcodeReaders(GlobalVar.allBarcodeReadersConnectionStringPath))
            {
                LogInfo("读码器加载成功", LogInfoType.PASS);
            }
            else
            {
                LogInfo("读码器加载失败", LogInfoType.ERROR);
            }
            //加载全局变量
            IProcess.dicGlobalVars.Clear();
@@ -936,7 +972,109 @@
            SaveAllCsv();
            SaveMotionControlDatas();
            SaveSerialPorts();
            SaveAllBarcodeReaders();
        }
        public bool LoadAllBarcodeReaders(string allBarcodeReadersConnectionStringPath)
        {
            if (!File.Exists(allBarcodeReadersConnectionStringPath))
            {
                Debug.WriteLine("读码器配置文件不存在,创建空文件");
                SaveAllBarcodeReaders();
                return true;
            }
            string strJson = string.Empty;
            using (StreamReader streamReader = new StreamReader(allBarcodeReadersConnectionStringPath, Encoding.UTF8))
            {
                strJson = streamReader.ReadToEnd();
                streamReader.Close();
            }
            GlobalVar.allBarcodeReadersConnectionString = JsonConvert.DeserializeObject<ConcurrentDictionary<string, string>>(strJson);
            if (GlobalVar.allBarcodeReadersConnectionString == null)
            {
                MessageBox.Show("读码器加载失败!", "异常");
                return false;
            }
            BarcodeReaderBase reader = null;
            foreach (var ReaderConnectionString in GlobalVar.allBarcodeReadersConnectionString)
            {
                Enum.TryParse<BarcodeReaderBrand>(ReaderConnectionString.Value, out BarcodeReaderBrand brand);
                switch (brand)
                {
                    case BarcodeReaderBrand.Huayray:
                        {
                            reader = new HRBarcodeReader();
                            break;
                        }
                    default:
                        {
                            MessageBox.Show($"[{ReaderConnectionString.Key}]读码器品牌不支持!", "异常");
                            continue;
                        }
                }
                reader.SN = ReaderConnectionString.Key;
                if (!reader.Open(ReaderConnectionString.Key))
                {
                    LogInfo($"初始化读码器[{ReaderConnectionString.Key}]失败", LogInfoType.ERROR);
                    reader.IsConnected = false;
                    reader.IsGrabbing = false;
                }
                else
                {
                    LogInfo($"初始化读码器[{ReaderConnectionString.Key}]成功", LogInfoType.PASS);
                }
                GlobalVar.dicBarcodeReaders.TryAdd(ReaderConnectionString.Key, reader);
            }
            return true;
        }
        public bool SaveAllBarcodeReaders()
        {
            try
            {
                string strJson = string.Empty;
                GlobalVar.allBarcodeReadersConnectionString = new ConcurrentDictionary<string, string>();
                foreach (var item in GlobalVar.dicBarcodeReaders)
                {
                    string ReaderSN = item.Value.SN;
                    string ReaderBrand = item.Value.Brand.ToString();
                    if (string.IsNullOrEmpty(ReaderSN) || string.IsNullOrEmpty(ReaderBrand))
                    {
                        break;
                    }
                    GlobalVar.allBarcodeReadersConnectionString.TryAdd(ReaderSN, ReaderBrand);
                }
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.allBarcodeReadersConnectionString, settings);
                string directoryPath = Path.GetDirectoryName(GlobalVar.allBarcodeReadersConnectionStringPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch (Exception)
                    { }
                }
                File.WriteAllText(GlobalVar.allBarcodeReadersConnectionStringPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
        }
        public bool LoadSerialPorts(string allSerialPortPath)
        {
@@ -1090,7 +1228,13 @@
                        camera.isGrabbing = false;
                    }
                }
                if (camera is LBCamera phmCamera)
                {
                    if (GlobalVar.allLBCameras.ContainsKey(camera.SN) && phmCamera._isConnected)
                    {
                        phmCamera.UpdateSensorConfig(GlobalVar.allLBCameras[camera.SN]);
                    }
                }
                GlobalVar.dicCameras.TryAdd(CameraConnectionString.Key, camera);
            }
@@ -1429,6 +1573,47 @@
            catch { return false; }
        }
        public bool LoadAllLBCameras(string allLBCamerasPath)
        {
            try
            {
                if (!File.Exists(allLBCamerasPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // 获取不带文件名的目录路径
                    string directoryPath = Path.GetDirectoryName(allLBCamerasPath);
                    SaveAllLBCameras();
                    return true;
                }
                GlobalVar.allLBCameras = ConfigManager<ConcurrentDictionary<string, PHM6000SensorConfig>>.LoadConfig<ConcurrentDictionary<string, PHM6000SensorConfig>>(GlobalVar.allCamerasLBPath);
            }
            catch
            {
                return false;
            }
            return true;
        }
        public bool SaveAllLBCameras()
        {
            try
            {
                if (GlobalVar.allLBCameras.Count >= 0)
                {
                    ConfigManager<ConcurrentDictionary<string, PHM6000SensorConfig>>.SaveConfig<ConcurrentDictionary<string, PHM6000SensorConfig>>(GlobalVar.allLBCameras, GlobalVar.allCamerasLBPath);
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
        public bool LoadAllProcess(string allProcessConnectionStringPath)
        {
            try
@@ -1760,6 +1945,8 @@
            }
        }
        bool is3D = false;
        bool is2D = false;
        private void TriggerRunMessageReceived(string name, string msg)
        {
@@ -1834,6 +2021,7 @@
                    }
            }
            var matchedItems = GlobalVar.dicProcessSetting
                .Where(item =>
                {
@@ -1849,6 +2037,23 @@
            if (matchedItems.Count <= 0)
            {
                matchedItems = GlobalVar.dicProcessSetting
                            .Where(item =>
                            {
                                var value = item.Value;
                                var triggerComm = value["触发通讯"];
                                var triggerChar = value["触发字符"];
                                return triggerComm != null && !triggerComm.Equals("无");
                                //return triggerComm != null && triggerComm.Equals(name) &&
                                //       (string.IsNullOrEmpty(triggerChar?.ToString()) ||
                                //        msg.StartsWith(triggerChar.ToString()));
                            })
                            .ToList(); // 避免重复字典访问和装箱操作
            }
            if (matchedItems.Count <= 0)
            {
                return;
            }
@@ -1860,294 +2065,888 @@
            GlobalVar.dicProcesses.Values.AsParallel().ForAll(v => v.bCompleted = false);
            LogInfo(string.Format($"检查到可被触发的流程,清空所有流程运行完成标记位!"), LogInfoType.INFO);
            Task.Factory.StartNew(() =>
            if (!is3D && name.Contains("L"))
            {
                Parallel.ForEach(matchedItems, item =>
                Task.Factory.StartNew(() =>
                {
                    string ProcessName = item.Value["流程名"];
                    LogInfo($"流程[{ProcessName}]开始运行", LogInfoType.INFO);
                    if (!GlobalVar.dicProcesses.ContainsKey(ProcessName))
                    if (name.Contains("L"))
                    {
                        LogInfo(string.Format("流程[{0}]不存在,请检查流程设置", ProcessName), LogInfoType.ERROR);
                        return;
                        is3D = true;
                    }
                    ProcessRunBll RunBll = GlobalVar.dicProcesses[ProcessName];
                    if (RunBll == null || RunBll.bRuning)
                    Parallel.ForEach(matchedItems, item =>
                    {
                        LogInfo(string.Format("流程[{0}]上次未运行完成,触发失败", ProcessName)
                            , LogInfoType.ERROR);
                        return;
                    }
                        string ProcessName = item.Value["流程名"];
                        LogInfo($"流程[{ProcessName}]开始运行", LogInfoType.INFO);
                    try
                    {
                        bool result = false;
                        string msg = string.Empty;
                        int times = Convert.ToInt32(item.Value["重测次数"].ToString());
                        string ConnecResult = item.Value["关联结果"];
                        if (times < 0)
                        if (!GlobalVar.dicProcesses.ContainsKey(ProcessName))
                        {
                            result = RunBll.Run();
                            msg = RunBll.Msg;
                            if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
                            {
                                if (!result)
                                {
                                    LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
                                }
                                RunBll.GetBooleanOutput(ConnecResult, out result);
                                RunBll.Result = result;
                            }
                            if (!result)
                            {
                                LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN);
                                RunBll.Result = true;
                                result = true;
                            }
                            LogInfo(string.Format("流程[{0}]不存在,请检查流程设置", ProcessName), LogInfoType.ERROR);
                            return;
                        }
                        else
                        ProcessRunBll RunBll = GlobalVar.dicProcesses[ProcessName];
                        if (RunBll == null || RunBll.bRuning)
                        {
                            while (times >= 0)
                            LogInfo(string.Format("流程[{0}]上次未运行完成,触发失败", ProcessName)
                                , LogInfoType.ERROR);
                            return;
                        }
                        try
                        {
                            bool result = false;
                            string msg = string.Empty;
                            int times = Convert.ToInt32(item.Value["重测次数"].ToString());
                            string ConnecResult = item.Value["关联结果"];
                            if (times < 0)
                            {
                                result = RunBll.Run();
                                msg = RunBll.Msg;
                                if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
                                {
                                    if (!result)
                                    {
                                        LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
                                    }
                                    RunBll.GetBooleanOutput(ConnecResult, out result);
                                    RunBll.Result = result;
                                }
                                if (result)
                                if (!result)
                                {
                                    break;
                                    LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN);
                                    RunBll.Result = true;
                                    result = true;
                                }
                                else if (!result && times > 0)
                                {
                                    LogInfo(string.Format("流程[{0}]运行失败重新测试,剩余次数[{1}]", ProcessName, times), LogInfoType.WARN);
                                }
                                times--;
                            }
                        }
                        string ConnectProcess = item.Value["关联流程"];
                        if (!(ConnectProcess == null || string.IsNullOrEmpty(ConnectProcess) || ConnectProcess.Trim() == ""))
                        {
                            //用逗号或者分号去间隔关联流程
                            string[] arrConnectProcess;
                            if (ConnectProcess.Split(';').Length >= ConnectProcess.Split(',').Length)
                            {
                                arrConnectProcess = ConnectProcess.Split(';');
                            }
                            else
                            {
                                arrConnectProcess = ConnectProcess.Split(',');
                            }
                            foreach (string strConnectProcess in arrConnectProcess)
                            {
                                if (GlobalVar.dicProcesses.ContainsKey(strConnectProcess))
                                while (times >= 0)
                                {
                                    ProcessRunBll ConnectRunBll = GlobalVar.dicProcesses[strConnectProcess];
                                    int waitTime = 10;
                                    DateTime startTime = DateTime.Now;
                                    while ((DateTime.Now - startTime).TotalSeconds < waitTime
                                    && (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted))
                                    result = RunBll.Run();
                                    msg = RunBll.Msg;
                                    if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
                                    {
                                        LogInfo(string.Format("关联流程[{0}]未运行完成,剩余等待[{1}]s", strConnectProcess, (waitTime - ((DateTime.Now - startTime).TotalSeconds)))
                                            , LogInfoType.NOSHOW);
                                        Thread.Sleep(1000);
                                        continue;
                                        if (!result)
                                        {
                                            LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
                                        }
                                        RunBll.GetBooleanOutput(ConnecResult, out result);
                                        RunBll.Result = result;
                                    }
                                    if (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted)
                                    if (result)
                                    {
                                        GlobalVar.dicProcesses[ProcessName].Msg = string.Format("流程[{0}]未运行完成", ProcessName);
                                        LogInfo(string.Format("关联流程[{0}]未运行完成", strConnectProcess), LogInfoType.ERROR);
                                        result = false;
                                        break;
                                    }
                                    else if (!ConnectRunBll.bRuning && ConnectRunBll.bCompleted)
                                    else if (!result && times > 0)
                                    {
                                        LogInfo(string.Format("关联流程[{0}]运行完成", strConnectProcess), LogInfoType.INFO);
                                        LogInfo(string.Format("流程[{0}]运行失败重新测试,剩余次数[{1}]", ProcessName, times), LogInfoType.WARN);
                                    }
                                    result &= ConnectRunBll.Result;
                                    if (!ConnectRunBll.Result)
                                    times--;
                                }
                            }
                            string ConnectProcess = item.Value["关联流程"];
                            if (!(ConnectProcess == null || string.IsNullOrEmpty(ConnectProcess) || ConnectProcess.Trim() == ""))
                            {
                                //用逗号或者分号去间隔关联流程
                                string[] arrConnectProcess;
                                if (ConnectProcess.Split(';').Length >= ConnectProcess.Split(',').Length)
                                {
                                    arrConnectProcess = ConnectProcess.Split(';');
                                }
                                else
                                {
                                    arrConnectProcess = ConnectProcess.Split(',');
                                }
                                foreach (string strConnectProcess in arrConnectProcess)
                                {
                                    if (GlobalVar.dicProcesses.ContainsKey(strConnectProcess))
                                    {
                                        LogInfo($"流程[{ProcessName}]的关联流程[{strConnectProcess}]运行失败", LogInfoType.ERROR);
                                        msg = $"关联流程[{strConnectProcess}]运行失败";
                                        ProcessRunBll ConnectRunBll = GlobalVar.dicProcesses[strConnectProcess];
                                        int waitTime = 10;
                                        DateTime startTime = DateTime.Now;
                                        while ((DateTime.Now - startTime).TotalSeconds < waitTime
                                        && (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted))
                                        {
                                            LogInfo(string.Format("关联流程[{0}]未运行完成,剩余等待[{1}]s", strConnectProcess, (waitTime - ((DateTime.Now - startTime).TotalSeconds)))
                                                , LogInfoType.NOSHOW);
                                            Thread.Sleep(1000);
                                            continue;
                                        }
                                        if (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted)
                                        {
                                            GlobalVar.dicProcesses[ProcessName].Msg = string.Format("流程[{0}]未运行完成", ProcessName);
                                            LogInfo(string.Format("关联流程[{0}]未运行完成", strConnectProcess), LogInfoType.ERROR);
                                            result = false;
                                            break;
                                        }
                                        else if (!ConnectRunBll.bRuning && ConnectRunBll.bCompleted)
                                        {
                                            LogInfo(string.Format("关联流程[{0}]运行完成", strConnectProcess), LogInfoType.INFO);
                                        }
                                        result &= ConnectRunBll.Result;
                                        if (!ConnectRunBll.Result)
                                        {
                                            LogInfo($"流程[{ProcessName}]的关联流程[{strConnectProcess}]运行失败", LogInfoType.ERROR);
                                            msg = $"关联流程[{strConnectProcess}]运行失败";
                                        }
                                    }
                                }
                            }
                        }
                        LogInfo(result ? $"流程[{ProcessName}]运行成功" : $"流程[{ProcessName}]运行失败,原因是{msg}", result ? LogInfoType.PASS : LogInfoType.ERROR);
                            LogInfo(result ? $"流程[{ProcessName}]运行成功" : $"流程[{ProcessName}]运行失败,原因是{msg}", result ? LogInfoType.PASS : LogInfoType.ERROR);
                        string SendComName = result ? item.Value["成功通讯"] : item.Value["失败通讯"];
                        string SendMsg = result ? item.Value["成功字符"] : item.Value["失败字符"];
                        if (GlobalVar.dicCommunicators.ContainsKey(SendComName) && (!string.IsNullOrEmpty(SendMsg) || SendMsg.Trim() != ""))
                        {
                            GlobalVar.dicCommunicators[SendComName].SendMessage(SendMsg);
                            LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", SendComName, SendMsg), LogInfoType.INFO);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogInfo(string.Format("流程[{0}]运行发生了意外,原因是:{1}", ProcessName, ex.Message + $"【{ex.StackTrace}】"), LogInfoType.ERROR);
                        RunBll.Result = false;
                        RunBll.Msg = $"[意外]{ex.Message}";
                    }
                    finally
                    {
                        #region 从RunSettingPage和Layout中获取是否保存图片
                        string strImageType = "jpeg";
                        bool bSaveRunImage = false;
                        bool bSaveResultImage = false;
                        long lImageQuality = 100L;
                        //ckbSaveRunImage
                        if (GlobalVar.ControlStates.TryGetValue("ckbSaveRunImage_CheckBox", out object oSaveRunImage))
                        {
                            if (oSaveRunImage != null && oSaveRunImage is bool)
                            string SendComName = result ? item.Value["成功通讯"] : item.Value["失败通讯"];
                            string SendMsg = result ? item.Value["成功字符"] : item.Value["失败字符"];
                            if (GlobalVar.dicCommunicators.ContainsKey(SendComName) && (!string.IsNullOrEmpty(SendMsg) || SendMsg.Trim() != ""))
                            {
                                bSaveRunImage = (bool)oSaveRunImage;
                                GlobalVar.dicCommunicators[SendComName].SendMessage(SendMsg);
                                LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", SendComName, SendMsg), LogInfoType.INFO);
                            }
                        }
                        //ckbSaveResultImage
                        if (GlobalVar.ControlStates.TryGetValue("ckbSaveResultImage_CheckBox", out object oSaveResultImage))
                        {
                            if (oSaveResultImage != null && oSaveResultImage is bool)
                            {
                                bSaveResultImage = (bool)oSaveResultImage;
                            }
                        }
                        //txtImageQuality
                        if (GlobalVar.ControlStates.TryGetValue("txtImageQuality_TextBox", out object oImageQuality))
                        catch (Exception ex)
                        {
                            if (oImageQuality != null && oImageQuality is string)
                            {
                                lImageQuality = Convert.ToInt64((string)oImageQuality);
                            }
                            LogInfo(string.Format("流程[{0}]运行发生了意外,原因是:{1}", ProcessName, ex.Message + $"【{ex.StackTrace}】"), LogInfoType.ERROR);
                            RunBll.Result = false;
                            RunBll.Msg = $"[意外]{ex.Message}";
                        }
                        //cmbImageType
                        if (GlobalVar.ControlStates.TryGetValue("cmbImageType_ComboBox", out object oImageType))
                        finally
                        {
                            try
                            #region 从RunSettingPage和Layout中获取是否保存图片
                            string strImageType = "jpeg";
                            bool bSaveRunImage = false;
                            bool bSaveResultImage = false;
                            long lImageQuality = 100L;
                            //ckbSaveRunImage
                            if (GlobalVar.ControlStates.TryGetValue("ckbSaveRunImage_CheckBox", out object oSaveRunImage))
                            {
                                // 动态解析ComboBox数据
                                var json = JsonConvert.SerializeObject(oImageType);
                                var comboData = JsonConvert.DeserializeAnonymousType(json, new
                                if (oSaveRunImage != null && oSaveRunImage is bool)
                                {
                                    Items = new List<object>(),
                                    SelectedIndex = 0
                                });
                                if (comboData != null && comboData.Items.Count > 0)
                                {
                                    strImageType = comboData.Items[comboData.SelectedIndex].ToString();
                                    bSaveRunImage = (bool)oSaveRunImage;
                                }
                            }
                            catch { }
                        }
                        // 生成图片并显示到控件中
                        HObject InputImage = null;
                        HObject RecordImage = null;
                        foreach (var layout in GlobalVar.dicLayout.Values
                                    .Where(layout => layout.ProcessName == ProcessName)
                                    .ToList())
                        {
                            string title = layout.Title;
                            string strImagePath = layout.SaveImageDir;
                            if (!AllProcessesPage.dicProcessControls.ContainsKey(title))
                            //ckbSaveResultImage
                            if (GlobalVar.ControlStates.TryGetValue("ckbSaveResultImage_CheckBox", out object oSaveResultImage))
                            {
                                continue;
                            }
                            RunBll.GetImage(layout, out InputImage, out RecordImage);
                            AllProcessesPage.dicProcessControls[title].ShowHoImage(RecordImage);
                            if (!string.IsNullOrEmpty(layout.SaveImageDir))
                            {
                                string fileNameHead = layout.SaveImageHead;
                                string result = Regex.Replace(fileNameHead, @"\{[^}]+\}", match =>
                                if (oSaveResultImage != null && oSaveResultImage is bool)
                                {
                                    // 去除{}只保留括号内的内容
                                    string content = match.Value;
                                    content = content.Trim('{', '}'); // 去除首尾的{}
                                    RunBll.GetStringOutput(content, out string str);
                                    return str;
                                });
                                string fileName = $"{result}-[{DateTime.Now.ToString("HH.mm.ss.ffff")}]";
                                // 使用正则表达式替换所有非法字符
                                string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
                                string pattern = $"[{invalidChars}]";
                                fileName = Regex.Replace(fileName, pattern, "-");
                                strImagePath = Regex.Replace(strImagePath, @"\{[^}]+\}", match =>
                                {
                                    // 去除{}只保留括号内的内容
                                    string content = match.Value;
                                    content = content.Trim('{', '}'); // 去除首尾的{}
                                    RunBll.GetStringOutput(content, out string str);
                                    return str;
                                });
                                if (bSaveRunImage)
                                {
                                    // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                    string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\原图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                    LB_SmartVision.Tool.Tool.AddRealImage(InputImage, directoryPath, fileName, strImageType, lImageQuality);
                                }
                                if (bSaveResultImage)
                                {
                                    // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                    string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\截图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                    LB_SmartVision.Tool.Tool.AddRealImage(RecordImage, directoryPath, fileName, "jpg", 50L);
                                    bSaveResultImage = (bool)oSaveResultImage;
                                }
                            }
                        }
                        foreach (var csv in GlobalVar.dicCsvSetting.Values
                                    .Where(csv => csv.ProcessName == ProcessName)
                                    .ToList())
                        {
                            if (RunBll.GetCsv(csv
                                , out List<string> DataTitle, out Dictionary<string, object> ResultData))
                            //txtImageQuality
                            if (GlobalVar.ControlStates.TryGetValue("txtImageQuality_TextBox", out object oImageQuality))
                            {
                                string filePath = Path.Combine(GlobalVar.strPathCsv, $"{ProcessName}.csv");
                                LB_SmartVision.Tool.Tool.SaveData(filePath, DataTitle, ResultData);
                                if (oImageQuality != null && oImageQuality is string)
                                {
                                    lImageQuality = Convert.ToInt64((string)oImageQuality);
                                }
                            }
                            //cmbImageType
                            if (GlobalVar.ControlStates.TryGetValue("cmbImageType_ComboBox", out object oImageType))
                            {
                                try
                                {
                                    // 动态解析ComboBox数据
                                    var json = JsonConvert.SerializeObject(oImageType);
                                    var comboData = JsonConvert.DeserializeAnonymousType(json, new
                                    {
                                        Items = new List<object>(),
                                        SelectedIndex = 0
                                    });
                                    if (comboData != null && comboData.Items.Count > 0)
                                    {
                                        strImageType = comboData.Items[comboData.SelectedIndex].ToString();
                                    }
                                }
                                catch { }
                            }
                            // 生成图片并显示到控件中
                            HObject InputImage = null;
                            HObject RecordImage = null;
                            foreach (var layout in GlobalVar.dicLayout.Values
                                        .Where(layout => layout.ProcessName == ProcessName)
                                        .ToList())
                            {
                                string title = layout.Title;
                                string strImagePath = layout.SaveImageDir;
                                if (!AllProcessesPage.dicProcessControls.ContainsKey(title))
                                {
                                    continue;
                                }
                                RunBll.GetImage(layout, out InputImage, out RecordImage);
                                AllProcessesPage.dicProcessControls[title].ShowHoImage(RecordImage);
                                if (!string.IsNullOrEmpty(layout.SaveImageDir))
                                {
                                    string fileNameHead = layout.SaveImageHead;
                                    string result = Regex.Replace(fileNameHead, @"\{[^}]+\}", match =>
                                    {
                                        // 去除{}只保留括号内的内容
                                        string content = match.Value;
                                        content = content.Trim('{', '}'); // 去除首尾的{}
                                        RunBll.GetStringOutput(content, out string str);
                                        return str;
                                    });
                                    string fileName = $"{result}-[{DateTime.Now.ToString("HH.mm.ss.ffff")}]";
                                    // 使用正则表达式替换所有非法字符
                                    string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
                                    string pattern = $"[{invalidChars}]";
                                    fileName = Regex.Replace(fileName, pattern, "-");
                                    strImagePath = Regex.Replace(strImagePath, @"\{[^}]+\}", match =>
                                    {
                                        // 去除{}只保留括号内的内容
                                        string content = match.Value;
                                        content = content.Trim('{', '}'); // 去除首尾的{}
                                        RunBll.GetStringOutput(content, out string str);
                                        return str;
                                    });
                                    if (bSaveRunImage)
                                    {
                                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\原图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                        LB_SmartVision.Tool.Tool.AddRealImage(InputImage, directoryPath, fileName, strImageType, lImageQuality);
                                    }
                                    if (bSaveResultImage)
                                    {
                                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\截图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                        LB_SmartVision.Tool.Tool.AddRealImage(RecordImage, directoryPath, fileName, "jpg", 50L);
                                    }
                                }
                            }
                            foreach (var csv in GlobalVar.dicCsvSetting.Values
                                        .Where(csv => csv.ProcessName == ProcessName)
                                        .ToList())
                            {
                                if (RunBll.GetCsv(csv
                                    , out List<string> DataTitle, out Dictionary<string, object> ResultData))
                                {
                                    string filePath = Path.Combine(GlobalVar.strPathCsv, $"{ProcessName}.csv");
                                    LB_SmartVision.Tool.Tool.SaveData(filePath, DataTitle, ResultData);
                                }
                            }
                            #endregion
                        }
                        #endregion
                    }
                        is3D = false;
                    });
                });
            });
            }
            else if (!is2D && !name.Contains("L"))
            {
                Task.Factory.StartNew(() =>
                {
                    if (!name.Contains("L"))
                    {
                        is2D = true;
                    }
                    Parallel.ForEach(matchedItems, item =>
                    {
                        string ProcessName = item.Value["流程名"];
                        LogInfo($"流程[{ProcessName}]开始运行", LogInfoType.INFO);
                        if (!GlobalVar.dicProcesses.ContainsKey(ProcessName))
                        {
                            LogInfo(string.Format("流程[{0}]不存在,请检查流程设置", ProcessName), LogInfoType.ERROR);
                            return;
                        }
                        ProcessRunBll RunBll = GlobalVar.dicProcesses[ProcessName];
                        if (RunBll == null || RunBll.bRuning)
                        {
                            LogInfo(string.Format("流程[{0}]上次未运行完成,触发失败", ProcessName)
                                , LogInfoType.ERROR);
                            return;
                        }
                        try
                        {
                            bool result = false;
                            string msg = string.Empty;
                            int times = Convert.ToInt32(item.Value["重测次数"].ToString());
                            string ConnecResult = item.Value["关联结果"];
                            if (times < 0)
                            {
                                result = RunBll.Run();
                                msg = RunBll.Msg;
                                if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
                                {
                                    if (!result)
                                    {
                                        LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
                                    }
                                    RunBll.GetBooleanOutput(ConnecResult, out result);
                                    RunBll.Result = result;
                                }
                                if (!result)
                                {
                                    LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN);
                                    RunBll.Result = true;
                                    result = true;
                                }
                            }
                            else
                            {
                                while (times >= 0)
                                {
                                    result = RunBll.Run();
                                    msg = RunBll.Msg;
                                    if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
                                    {
                                        if (!result)
                                        {
                                            LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
                                        }
                                        RunBll.GetBooleanOutput(ConnecResult, out result);
                                        RunBll.Result = result;
                                    }
                                    if (result)
                                    {
                                        break;
                                    }
                                    else if (!result && times > 0)
                                    {
                                        LogInfo(string.Format("流程[{0}]运行失败重新测试,剩余次数[{1}]", ProcessName, times), LogInfoType.WARN);
                                    }
                                    times--;
                                }
                            }
                            string ConnectProcess = item.Value["关联流程"];
                            if (!(ConnectProcess == null || string.IsNullOrEmpty(ConnectProcess) || ConnectProcess.Trim() == ""))
                            {
                                //用逗号或者分号去间隔关联流程
                                string[] arrConnectProcess;
                                if (ConnectProcess.Split(';').Length >= ConnectProcess.Split(',').Length)
                                {
                                    arrConnectProcess = ConnectProcess.Split(';');
                                }
                                else
                                {
                                    arrConnectProcess = ConnectProcess.Split(',');
                                }
                                foreach (string strConnectProcess in arrConnectProcess)
                                {
                                    if (GlobalVar.dicProcesses.ContainsKey(strConnectProcess))
                                    {
                                        ProcessRunBll ConnectRunBll = GlobalVar.dicProcesses[strConnectProcess];
                                        int waitTime = 10;
                                        DateTime startTime = DateTime.Now;
                                        while ((DateTime.Now - startTime).TotalSeconds < waitTime
                                        && (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted))
                                        {
                                            LogInfo(string.Format("关联流程[{0}]未运行完成,剩余等待[{1}]s", strConnectProcess, (waitTime - ((DateTime.Now - startTime).TotalSeconds)))
                                                , LogInfoType.NOSHOW);
                                            Thread.Sleep(1000);
                                            continue;
                                        }
                                        if (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted)
                                        {
                                            GlobalVar.dicProcesses[ProcessName].Msg = string.Format("流程[{0}]未运行完成", ProcessName);
                                            LogInfo(string.Format("关联流程[{0}]未运行完成", strConnectProcess), LogInfoType.ERROR);
                                            result = false;
                                            break;
                                        }
                                        else if (!ConnectRunBll.bRuning && ConnectRunBll.bCompleted)
                                        {
                                            LogInfo(string.Format("关联流程[{0}]运行完成", strConnectProcess), LogInfoType.INFO);
                                        }
                                        result &= ConnectRunBll.Result;
                                        if (!ConnectRunBll.Result)
                                        {
                                            LogInfo($"流程[{ProcessName}]的关联流程[{strConnectProcess}]运行失败", LogInfoType.ERROR);
                                            msg = $"关联流程[{strConnectProcess}]运行失败";
                                        }
                                    }
                                }
                            }
                            LogInfo(result ? $"流程[{ProcessName}]运行成功" : $"流程[{ProcessName}]运行失败,原因是{msg}", result ? LogInfoType.PASS : LogInfoType.ERROR);
                            string SendComName = result ? item.Value["成功通讯"] : item.Value["失败通讯"];
                            string SendMsg = result ? item.Value["成功字符"] : item.Value["失败字符"];
                            if (GlobalVar.dicCommunicators.ContainsKey(SendComName) && (!string.IsNullOrEmpty(SendMsg) || SendMsg.Trim() != ""))
                            {
                                GlobalVar.dicCommunicators[SendComName].SendMessage(SendMsg);
                                LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", SendComName, SendMsg), LogInfoType.INFO);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogInfo(string.Format("流程[{0}]运行发生了意外,原因是:{1}", ProcessName, ex.Message + $"【{ex.StackTrace}】"), LogInfoType.ERROR);
                            RunBll.Result = false;
                            RunBll.Msg = $"[意外]{ex.Message}";
                        }
                        finally
                        {
                            #region 从RunSettingPage和Layout中获取是否保存图片
                            string strImageType = "jpeg";
                            bool bSaveRunImage = false;
                            bool bSaveResultImage = false;
                            long lImageQuality = 100L;
                            //ckbSaveRunImage
                            if (GlobalVar.ControlStates.TryGetValue("ckbSaveRunImage_CheckBox", out object oSaveRunImage))
                            {
                                if (oSaveRunImage != null && oSaveRunImage is bool)
                                {
                                    bSaveRunImage = (bool)oSaveRunImage;
                                }
                            }
                            //ckbSaveResultImage
                            if (GlobalVar.ControlStates.TryGetValue("ckbSaveResultImage_CheckBox", out object oSaveResultImage))
                            {
                                if (oSaveResultImage != null && oSaveResultImage is bool)
                                {
                                    bSaveResultImage = (bool)oSaveResultImage;
                                }
                            }
                            //txtImageQuality
                            if (GlobalVar.ControlStates.TryGetValue("txtImageQuality_TextBox", out object oImageQuality))
                            {
                                if (oImageQuality != null && oImageQuality is string)
                                {
                                    lImageQuality = Convert.ToInt64((string)oImageQuality);
                                }
                            }
                            //cmbImageType
                            if (GlobalVar.ControlStates.TryGetValue("cmbImageType_ComboBox", out object oImageType))
                            {
                                try
                                {
                                    // 动态解析ComboBox数据
                                    var json = JsonConvert.SerializeObject(oImageType);
                                    var comboData = JsonConvert.DeserializeAnonymousType(json, new
                                    {
                                        Items = new List<object>(),
                                        SelectedIndex = 0
                                    });
                                    if (comboData != null && comboData.Items.Count > 0)
                                    {
                                        strImageType = comboData.Items[comboData.SelectedIndex].ToString();
                                    }
                                }
                                catch { }
                            }
                            // 生成图片并显示到控件中
                            HObject InputImage = null;
                            HObject RecordImage = null;
                            foreach (var layout in GlobalVar.dicLayout.Values
                                        .Where(layout => layout.ProcessName == ProcessName)
                                        .ToList())
                            {
                                string title = layout.Title;
                                string strImagePath = layout.SaveImageDir;
                                if (!AllProcessesPage.dicProcessControls.ContainsKey(title))
                                {
                                    continue;
                                }
                                RunBll.GetImage(layout, out InputImage, out RecordImage);
                                AllProcessesPage.dicProcessControls[title].ShowHoImage(RecordImage);
                                if (!string.IsNullOrEmpty(layout.SaveImageDir))
                                {
                                    string fileNameHead = layout.SaveImageHead;
                                    string result = Regex.Replace(fileNameHead, @"\{[^}]+\}", match =>
                                    {
                                        // 去除{}只保留括号内的内容
                                        string content = match.Value;
                                        content = content.Trim('{', '}'); // 去除首尾的{}
                                        RunBll.GetStringOutput(content, out string str);
                                        return str;
                                    });
                                    string fileName = $"{result}-[{DateTime.Now.ToString("HH.mm.ss.ffff")}]";
                                    // 使用正则表达式替换所有非法字符
                                    string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
                                    string pattern = $"[{invalidChars}]";
                                    fileName = Regex.Replace(fileName, pattern, "-");
                                    strImagePath = Regex.Replace(strImagePath, @"\{[^}]+\}", match =>
                                    {
                                        // 去除{}只保留括号内的内容
                                        string content = match.Value;
                                        content = content.Trim('{', '}'); // 去除首尾的{}
                                        RunBll.GetStringOutput(content, out string str);
                                        return str;
                                    });
                                    if (bSaveRunImage)
                                    {
                                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\原图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                        LB_SmartVision.Tool.Tool.AddRealImage(InputImage, directoryPath, fileName, strImageType, lImageQuality);
                                    }
                                    if (bSaveResultImage)
                                    {
                                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
                                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\截图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
                                        LB_SmartVision.Tool.Tool.AddRealImage(RecordImage, directoryPath, fileName, "jpg", 50L);
                                    }
                                }
                            }
                            foreach (var csv in GlobalVar.dicCsvSetting.Values
                                        .Where(csv => csv.ProcessName == ProcessName)
                                        .ToList())
                            {
                                if (RunBll.GetCsv(csv
                                    , out List<string> DataTitle, out Dictionary<string, object> ResultData))
                                {
                                    string filePath = Path.Combine(GlobalVar.strPathCsv, $"{ProcessName}.csv");
                                    LB_SmartVision.Tool.Tool.SaveData(filePath, DataTitle, ResultData);
                                }
                            }
                            #endregion
                        }
                        is2D = false;
                    });
                });
            }
            //Task.Factory.StartNew(() =>
            //{
            //    Parallel.ForEach(matchedItems, item =>
            //    {
            //        string ProcessName = item.Value["流程名"];
            //        LogInfo($"流程[{ProcessName}]开始运行", LogInfoType.INFO);
            //        if (!GlobalVar.dicProcesses.ContainsKey(ProcessName))
            //        {
            //            LogInfo(string.Format("流程[{0}]不存在,请检查流程设置", ProcessName), LogInfoType.ERROR);
            //            return;
            //        }
            //        ProcessRunBll RunBll = GlobalVar.dicProcesses[ProcessName];
            //        if (RunBll == null || RunBll.bRuning)
            //        {
            //            LogInfo(string.Format("流程[{0}]上次未运行完成,触发失败", ProcessName)
            //                , LogInfoType.ERROR);
            //            return;
            //        }
            //        try
            //        {
            //            bool result = false;
            //            string msg = string.Empty;
            //            int times = Convert.ToInt32(item.Value["重测次数"].ToString());
            //            string ConnecResult = item.Value["关联结果"];
            //            if (times < 0)
            //            {
            //                result = RunBll.Run();
            //                msg = RunBll.Msg;
            //                if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
            //                {
            //                    if (!result)
            //                    {
            //                        LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
            //                    }
            //                    RunBll.GetBooleanOutput(ConnecResult, out result);
            //                    RunBll.Result = result;
            //                }
            //                if (!result)
            //                {
            //                    LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN);
            //                    RunBll.Result = true;
            //                    result = true;
            //                }
            //            }
            //            else
            //            {
            //                while (times >= 0)
            //                {
            //                    result = RunBll.Run();
            //                    msg = RunBll.Msg;
            //                    if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
            //                    {
            //                        if (!result)
            //                        {
            //                            LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW);
            //                        }
            //                        RunBll.GetBooleanOutput(ConnecResult, out result);
            //                        RunBll.Result = result;
            //                    }
            //                    if (result)
            //                    {
            //                        break;
            //                    }
            //                    else if (!result && times > 0)
            //                    {
            //                        LogInfo(string.Format("流程[{0}]运行失败重新测试,剩余次数[{1}]", ProcessName, times), LogInfoType.WARN);
            //                    }
            //                    times--;
            //                }
            //            }
            //            string ConnectProcess = item.Value["关联流程"];
            //            if (!(ConnectProcess == null || string.IsNullOrEmpty(ConnectProcess) || ConnectProcess.Trim() == ""))
            //            {
            //                //用逗号或者分号去间隔关联流程
            //                string[] arrConnectProcess;
            //                if (ConnectProcess.Split(';').Length >= ConnectProcess.Split(',').Length)
            //                {
            //                    arrConnectProcess = ConnectProcess.Split(';');
            //                }
            //                else
            //                {
            //                    arrConnectProcess = ConnectProcess.Split(',');
            //                }
            //                foreach (string strConnectProcess in arrConnectProcess)
            //                {
            //                    if (GlobalVar.dicProcesses.ContainsKey(strConnectProcess))
            //                    {
            //                        ProcessRunBll ConnectRunBll = GlobalVar.dicProcesses[strConnectProcess];
            //                        int waitTime = 10;
            //                        DateTime startTime = DateTime.Now;
            //                        while ((DateTime.Now - startTime).TotalSeconds < waitTime
            //                        && (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted))
            //                        {
            //                            LogInfo(string.Format("关联流程[{0}]未运行完成,剩余等待[{1}]s", strConnectProcess, (waitTime - ((DateTime.Now - startTime).TotalSeconds)))
            //                                , LogInfoType.NOSHOW);
            //                            Thread.Sleep(1000);
            //                            continue;
            //                        }
            //                        if (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted)
            //                        {
            //                            GlobalVar.dicProcesses[ProcessName].Msg = string.Format("流程[{0}]未运行完成", ProcessName);
            //                            LogInfo(string.Format("关联流程[{0}]未运行完成", strConnectProcess), LogInfoType.ERROR);
            //                            result = false;
            //                            break;
            //                        }
            //                        else if (!ConnectRunBll.bRuning && ConnectRunBll.bCompleted)
            //                        {
            //                            LogInfo(string.Format("关联流程[{0}]运行完成", strConnectProcess), LogInfoType.INFO);
            //                        }
            //                        result &= ConnectRunBll.Result;
            //                        if (!ConnectRunBll.Result)
            //                        {
            //                            LogInfo($"流程[{ProcessName}]的关联流程[{strConnectProcess}]运行失败", LogInfoType.ERROR);
            //                            msg = $"关联流程[{strConnectProcess}]运行失败";
            //                        }
            //                    }
            //                }
            //            }
            //            LogInfo(result ? $"流程[{ProcessName}]运行成功" : $"流程[{ProcessName}]运行失败,原因是{msg}", result ? LogInfoType.PASS : LogInfoType.ERROR);
            //            string SendComName = result ? item.Value["成功通讯"] : item.Value["失败通讯"];
            //            string SendMsg = result ? item.Value["成功字符"] : item.Value["失败字符"];
            //            if (GlobalVar.dicCommunicators.ContainsKey(SendComName) && (!string.IsNullOrEmpty(SendMsg) || SendMsg.Trim() != ""))
            //            {
            //                GlobalVar.dicCommunicators[SendComName].SendMessage(SendMsg);
            //                LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", SendComName, SendMsg), LogInfoType.INFO);
            //            }
            //        }
            //        catch (Exception ex)
            //        {
            //            LogInfo(string.Format("流程[{0}]运行发生了意外,原因是:{1}", ProcessName, ex.Message + $"【{ex.StackTrace}】"), LogInfoType.ERROR);
            //            RunBll.Result = false;
            //            RunBll.Msg = $"[意外]{ex.Message}";
            //        }
            //        finally
            //        {
            //            #region 从RunSettingPage和Layout中获取是否保存图片
            //            string strImageType = "jpeg";
            //            bool bSaveRunImage = false;
            //            bool bSaveResultImage = false;
            //            long lImageQuality = 100L;
            //            //ckbSaveRunImage
            //            if (GlobalVar.ControlStates.TryGetValue("ckbSaveRunImage_CheckBox", out object oSaveRunImage))
            //            {
            //                if (oSaveRunImage != null && oSaveRunImage is bool)
            //                {
            //                    bSaveRunImage = (bool)oSaveRunImage;
            //                }
            //            }
            //            //ckbSaveResultImage
            //            if (GlobalVar.ControlStates.TryGetValue("ckbSaveResultImage_CheckBox", out object oSaveResultImage))
            //            {
            //                if (oSaveResultImage != null && oSaveResultImage is bool)
            //                {
            //                    bSaveResultImage = (bool)oSaveResultImage;
            //                }
            //            }
            //            //txtImageQuality
            //            if (GlobalVar.ControlStates.TryGetValue("txtImageQuality_TextBox", out object oImageQuality))
            //            {
            //                if (oImageQuality != null && oImageQuality is string)
            //                {
            //                    lImageQuality = Convert.ToInt64((string)oImageQuality);
            //                }
            //            }
            //            //cmbImageType
            //            if (GlobalVar.ControlStates.TryGetValue("cmbImageType_ComboBox", out object oImageType))
            //            {
            //                try
            //                {
            //                    // 动态解析ComboBox数据
            //                    var json = JsonConvert.SerializeObject(oImageType);
            //                    var comboData = JsonConvert.DeserializeAnonymousType(json, new
            //                    {
            //                        Items = new List<object>(),
            //                        SelectedIndex = 0
            //                    });
            //                    if (comboData != null && comboData.Items.Count > 0)
            //                    {
            //                        strImageType = comboData.Items[comboData.SelectedIndex].ToString();
            //                    }
            //                }
            //                catch { }
            //            }
            //            // 生成图片并显示到控件中
            //            HObject InputImage = null;
            //            HObject RecordImage = null;
            //            foreach (var layout in GlobalVar.dicLayout.Values
            //                        .Where(layout => layout.ProcessName == ProcessName)
            //                        .ToList())
            //            {
            //                string title = layout.Title;
            //                string strImagePath = layout.SaveImageDir;
            //                if (!AllProcessesPage.dicProcessControls.ContainsKey(title))
            //                {
            //                    continue;
            //                }
            //                RunBll.GetImage(layout, out InputImage, out RecordImage);
            //                AllProcessesPage.dicProcessControls[title].ShowHoImage(RecordImage);
            //                if (!string.IsNullOrEmpty(layout.SaveImageDir))
            //                {
            //                    string fileNameHead = layout.SaveImageHead;
            //                    string result = Regex.Replace(fileNameHead, @"\{[^}]+\}", match =>
            //                    {
            //                        // 去除{}只保留括号内的内容
            //                        string content = match.Value;
            //                        content = content.Trim('{', '}'); // 去除首尾的{}
            //                        RunBll.GetStringOutput(content, out string str);
            //                        return str;
            //                    });
            //                    string fileName = $"{result}-[{DateTime.Now.ToString("HH.mm.ss.ffff")}]";
            //                    // 使用正则表达式替换所有非法字符
            //                    string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
            //                    string pattern = $"[{invalidChars}]";
            //                    fileName = Regex.Replace(fileName, pattern, "-");
            //                    strImagePath = Regex.Replace(strImagePath, @"\{[^}]+\}", match =>
            //                    {
            //                        // 去除{}只保留括号内的内容
            //                        string content = match.Value;
            //                        content = content.Trim('{', '}'); // 去除首尾的{}
            //                        RunBll.GetStringOutput(content, out string str);
            //                        return str;
            //                    });
            //                    if (bSaveRunImage)
            //                    {
            //                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
            //                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\原图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
            //                        LB_SmartVision.Tool.Tool.AddRealImage(InputImage, directoryPath, fileName, strImageType, lImageQuality);
            //                    }
            //                    if (bSaveResultImage)
            //                    {
            //                        // 最后一级目录必须为年月日,会根据时间来删除旧图片
            //                        string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\截图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\");
            //                        LB_SmartVision.Tool.Tool.AddRealImage(RecordImage, directoryPath, fileName, "jpg", 50L);
            //                    }
            //                }
            //            }
            //            foreach (var csv in GlobalVar.dicCsvSetting.Values
            //                        .Where(csv => csv.ProcessName == ProcessName)
            //                        .ToList())
            //            {
            //                if (RunBll.GetCsv(csv
            //                    , out List<string> DataTitle, out Dictionary<string, object> ResultData))
            //                {
            //                    string filePath = Path.Combine(GlobalVar.strPathCsv, $"{ProcessName}.csv");
            //                    LB_SmartVision.Tool.Tool.SaveData(filePath, DataTitle, ResultData);
            //                }
            //            }
            //            #endregion
            //        }
            //    });
            //});
        }
        private void VisionForm_FormClosing(object sender, FormClosingEventArgs e)
@@ -2237,76 +3036,101 @@
        private void btn_Run_Click(object sender, EventArgs e)
        {
            var matchedItems = GlobalVar.dicProcessSetting
                                        .Where(item =>
                                        {
                                            var value = item.Value;
                                            var triggerComm = value["触发通讯"];
                                            var triggerChar = value["触发字符"];
                                            return triggerComm != null;
                                            //return triggerComm != null && triggerComm.Equals(name) &&
                                            //       (string.IsNullOrEmpty(triggerChar?.ToString()) ||
                                            //        msg.StartsWith(triggerChar.ToString()));
                                        })
                                        .ToList(); // 避免重复字典访问和装箱操作
            if (matchedItems.Count <= 0)
            //var matchedItems = GlobalVar.dicProcessSetting
            //                            .Where(item =>
            //                            {
            //                                var value = item.Value;
            //                                var triggerComm = value["触发通讯"];
            //                                var triggerChar = value["触发字符"];
            //                                return triggerComm != null && !triggerComm.Equals("无");
            //                                //return triggerComm != null && triggerComm.Equals(name) &&
            //                                //       (string.IsNullOrEmpty(triggerChar?.ToString()) ||
            //                                //        msg.StartsWith(triggerChar.ToString()));
            //                            })
            //                            .ToList(); // 避免重复字典访问和装箱操作
            //if (matchedItems.Count <= 0)
            //{
            //    return;
            //}
            //foreach (var item in matchedItems)
            //{
            //    Task.Factory.StartNew(() =>
            //    {
            //        TriggerRunMessageReceived(item.Value["触发通讯"], item.Value["触发字符"]);
            //    });
            //}
            foreach (var item in GlobalVar.dicCameras.Keys)
            {
                return;
                GlobalVar.dicCameras[item].StartSingleGrab();
            }
            TriggerRunMessageReceived(matchedItems[0].Value["触发通讯"], matchedItems[0].Value["触发字符"]);
        }
        private void btn_RunContinuously_Click(object sender, EventArgs e)
        {
            if (btn_RunContinuously.Text.Equals("连续运行"))
            if (this.ckbAllowRun.Checked)
            {
                _isTabSwitchAllowed = false;
                btn_RunContinuously.Text = "暂停运行";
                // 关闭使能
                SelectMainPage();
                btn_GlobalVar.Enabled = false;
                btn_Login.Enabled = false;
                btn_SingleRun.Enabled = false;
                ckbAllowRun.Enabled = false;
                Task.Factory.StartNew(() =>
                if (btn_RunContinuously.Text.Equals("连续运行"))
                {
                    var matchedItems = GlobalVar.dicProcessSetting
                                                .Where(item =>
                                                {
                                                    var value = item.Value;
                                                    var triggerComm = value["触发通讯"];
                                                    var triggerChar = value["触发字符"];
                                                    return triggerComm != null;
                                                    //return triggerComm != null && triggerComm.Equals(name) &&
                                                    //       (string.IsNullOrEmpty(triggerChar?.ToString()) ||
                                                    //        msg.StartsWith(triggerChar.ToString()));
                                                })
                                                .ToList(); // 避免重复字典访问和装箱操作
                    while (btn_RunContinuously.Text.Equals("暂停运行"))
                    _isTabSwitchAllowed = false;
                    btn_RunContinuously.Text = "暂停运行";
                    // 关闭使能
                    SelectMainPage();
                    btn_GlobalVar.Enabled = false;
                    btn_Login.Enabled = false;
                    btn_SingleRun.Enabled = false;
                    ckbAllowRun.Enabled = false;
                    foreach (var item in GlobalVar.dicCameras.Keys)
                    {
                        TriggerRunMessageReceived(matchedItems[0].Value["触发通讯"], matchedItems[0].Value["触发字符"]);
                        Thread.Sleep(3500);
                        GlobalVar.dicCameras[item].StartContinuousGrab();
                    }
                    //this.Invoke(() =>
                    //Task.Factory.StartNew(() =>
                    //{
                    //    var matchedItems = GlobalVar.dicProcessSetting
                    //                                .Where(item =>
                    //                                {
                    //                                    var value = item.Value;
                    //                                    var triggerComm = value["触发通讯"];
                    //                                    var triggerChar = value["触发字符"];
                    //                                    return triggerComm != null && !triggerComm.Equals("无");
                    //                                    //return triggerComm != null && triggerComm.Equals(name) &&
                    //                                    //       (string.IsNullOrEmpty(triggerChar?.ToString()) ||
                    //                                    //        msg.StartsWith(triggerChar.ToString()));
                    //                                })
                    //                                .ToList(); // 避免重复字典访问和装箱操作
                    //    while (btn_RunContinuously.Text.Equals("暂停运行"))
                    //    {
                    //        foreach (var item in matchedItems)
                    //        {
                    //            Task.Factory.StartNew(() =>
                    //            {
                    //                TriggerRunMessageReceived(item.Value["触发通讯"], item.Value["触发字符"]);
                    //            });
                    //        }
                    //        //TriggerRunMessageReceived(matchedItems[0].Value["触发通讯"], matchedItems[0].Value["触发字符"]);
                    //        Thread.Sleep(3500);
                    //    }
                    //    //this.Invoke(() =>
                    //    //{
                    //    //});
                    //});
                });
                }
                else if (btn_RunContinuously.Text.Equals("暂停运行"))
                {
                    btn_RunContinuously.Text = "连续运行";
                    foreach (var item in GlobalVar.dicCameras.Keys)
                    {
                        GlobalVar.dicCameras[item].StopGrabbing();
                    }
                    // 启动使能
                    UnSelectMainPage();
                    btn_GlobalVar.Enabled = true;
                    btn_Login.Enabled = true;
                    btn_SingleRun.Enabled = true;
                    ckbAllowRun.Enabled = true;
                    Thread.Sleep(100);
                    _isTabSwitchAllowed = true;
                }
            }
            else if (btn_RunContinuously.Text.Equals("暂停运行"))
            {
                btn_RunContinuously.Text = "连续运行";
                // 启动使能
                UnSelectMainPage();
                btn_GlobalVar.Enabled = true;
                btn_Login.Enabled = true;
                btn_SingleRun.Enabled = true;
                ckbAllowRun.Enabled = true;
                Thread.Sleep(100);
                _isTabSwitchAllowed = true;
            }
        }
        private void cmbProduct_SelectedValueChanged(object sender, EventArgs e)