1e77d9c016589865f6bd187bda2ea15d8ad0e2da..d0ded5cd9bf5070a120bad58b5be21fe2ac6a4ff
2025-12-20 C3032
test
d0ded5 对比 | 目录
2025-12-20 C3032
test
38c333 对比 | 目录
2025-12-20 C3032
添加项目文件。
154923 对比 | 目录
2025-12-20 C3032
添加 .gitignore 和 .gitattributes。
3f8c9d 对比 | 目录
已添加85个文件
已修改1个文件
14314 ■■■■■ 文件已修改
.gitattributes 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore 186 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vsconfig 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/$null 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/App.config 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/App.xaml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/App.xaml.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/AppRestartHelper.cs 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/DownloadData.xaml 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/DownloadData.xaml.cs 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ExcelResultRecorder.cs 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewer2D.ico 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerDefines.cs 2259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerDefines1.cs 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerDemo.csproj 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerSDK.cs 1030 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerSDK1.cs 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/IDViewerSDK2.cs 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/MTV3Dlogo.ico 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/logo_01.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/logo_02.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/删除.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/刷新.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/单张抓图.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/存储图片.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/宣传图.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/开始采集.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/打开文件.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/断开.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/暂停.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/连接.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/连续抓图.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/Currency/采集.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/ICON/camera-switch-fill.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/ICON/folder-2-fill.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/ICON/folder-open-fill.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/ICON/import-fill.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/ICON/link-m.png 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/testImages/20220706201141516.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/testImages/20220706201152065.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/testImages/20220719092357348.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/testImages/20221013101729295.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Image/testImages/20221018190453100.jpg 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ImageDisplayWindow .xaml 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ImageDisplayWindow .xaml.cs 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ImageService/ImageCleanupService.cs 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ImageService/MemoryAlarmCheck.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LBProjService.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LBProtect.cs 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LoadingWindow.xaml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LoadingWindow.xaml.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LogAutoSaveService.cs 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LogAutoSaveService_Optimized.cs 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LoginWindow.xaml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/LoginWindow.xaml.cs 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/MainWindow.xaml 915 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/MainWindow.xaml.cs 3494 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ModbusTCPClient.cs 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/OperateLog/OperateLogService.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/OperateLog/OperateLogView.xaml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/OperateLog/OperateLogView.xaml.cs 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ProductManager.xaml 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ProductManager.xaml.cs 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Program.cs 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Properties/AssemblyInfo.cs 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Properties/Resources.Designer.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Properties/Resources.resx 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Properties/Settings.Designer.cs 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Properties/Settings.settings 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ResultJudge.xaml 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ResultJudge.xaml.cs 384 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/Settings.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/SmartScanner.csproj 365 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/TcpServerManager.cs 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/User.cs 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/VersionHelper.cs 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/ViewModel/LogViewModel.cs 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/packages.config 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
IDViewer_2D/软件需求规格说明书.md 339 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SmartScanner.sln 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
TCP通讯数据格式说明.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
安装脚本.iss 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
版本说明.txt 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
软件功能列表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
集成相机软件功能列表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
.gitattributes
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain
.gitignore
@@ -1,10 +1,20 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
@@ -12,35 +22,54 @@
[Rr]elease/
[Rr]eleases/
x64/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Roslyn cache directories
*.ide/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
@@ -50,6 +79,7 @@
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
@@ -65,14 +95,21 @@
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
@@ -94,9 +131,23 @@
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
@@ -124,30 +175,34 @@
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
packages/*
*.nupkg
## TODO: If the tool you use requires repositories.config
## uncomment the next line
#!packages/repositories.config
# Enable "build/" folder in the NuGet Packages folder since
# NuGet packages use it for MSBuild targets.
# This line needs to be after the ignore of the build folder
# (and the packages folder if the line above has been uncommented)
!packages/build/
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
sql/
@@ -158,9 +213,9 @@
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
# RIA/Silverlight projects
Generated_Code/
@@ -172,15 +227,106 @@
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
.vsconfig
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
{
  "version": "1.0",
  "components": [
    "Microsoft.VisualStudio.Component.CoreEditor",
    "Microsoft.VisualStudio.Workload.CoreEditor",
    "Microsoft.VisualStudio.Component.NuGet",
    "Microsoft.Net.Component.4.6.1.TargetingPack",
    "Microsoft.VisualStudio.Component.Roslyn.Compiler",
    "Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
    "Microsoft.VisualStudio.Component.FSharp",
    "Microsoft.ComponentGroup.ClickOnce.Publish",
    "Microsoft.NetCore.Component.DevelopmentTools",
    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
    "Microsoft.Net.Component.4.8.SDK",
    "Microsoft.Net.Component.4.7.2.TargetingPack",
    "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
    "Microsoft.VisualStudio.Component.TypeScript.4.3",
    "Microsoft.VisualStudio.Component.JavaScript.TypeScript",
    "Microsoft.Component.MSBuild",
    "Microsoft.VisualStudio.Component.TextTemplating",
    "Microsoft.VisualStudio.Component.Common.Azure.Tools",
    "Microsoft.VisualStudio.Component.SQL.CLR",
    "Microsoft.VisualStudio.Component.ManagedDesktop.Core",
    "Microsoft.Net.Component.4.5.2.TargetingPack",
    "Microsoft.Net.Component.4.5.TargetingPack",
    "Microsoft.Net.Component.4.TargetingPack",
    "Microsoft.Net.Component.4.5.1.TargetingPack",
    "Microsoft.Net.Component.4.6.TargetingPack",
    "Microsoft.Net.ComponentGroup.TargetingPacks.Common",
    "Microsoft.VisualStudio.Component.DiagnosticTools",
    "Microsoft.VisualStudio.Component.EntityFramework",
    "Microsoft.VisualStudio.Component.Debugger.JustInTime",
    "Component.Microsoft.VisualStudio.LiveShare",
    "Microsoft.VisualStudio.Component.IntelliCode",
    "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
    "Microsoft.ComponentGroup.Blend",
    "Microsoft.VisualStudio.Component.DotNetModelBuilder",
    "Microsoft.VisualStudio.Workload.ManagedDesktop",
    "Microsoft.Component.ClickOnce"
  ],
  "extensions": [
    "https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects"
  ]
}
IDViewer_2D/$null
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
Active code page: 65001
IDViewer_2D/App.config
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
            <section name="SmartScanner.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" />
    </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Syncfusion.Licensing" publicKeyToken="632609b4d040f6b4" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-29.1462.37.0" newVersion="29.1462.37.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Drawing.Common" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <userSettings>
    <SmartScanner.Properties.Settings>
      <setting name="LastConfigFilePath" serializeAs="String">
        <value />
      </setting>
      <setting name="DataSavingRoad" serializeAs="String">
        <value />
      </setting>
      <setting name="ImageDeleteEnabled" serializeAs="String">
        <value>False</value>
      </setting>
      <setting name="DeleteImageDays" serializeAs="String">
        <value>30</value>
      </setting>
      <setting name="ImageSaveEnabled" serializeAs="String">
        <value>True</value>
      </setting>
      <setting name="CompressionRatio" serializeAs="String">
        <value>0</value>
      </setting>
      <setting name="ImageFormatSelect" serializeAs="String">
        <value>0</value>
      </setting>
      <setting name="MemoryAlarmSetting" serializeAs="String">
        <value>20</value>
      </setting>
      <setting name="MemoryAlarmEnabled" serializeAs="String">
        <value>False</value>
      </setting>
      <setting name="OutputCheckBoxEnable" serializeAs="String">
        <value>False</value>
      </setting>
      <setting name="DefaultPort" serializeAs="String">
        <value>"8080"</value>
      </setting>
      <setting name="SelectedPort" serializeAs="String">
        <value>8080</value>
      </setting>
      <setting name="LastConfigFilePath_Proj" serializeAs="String">
        <value />
      </setting>
    </SmartScanner.Properties.Settings>
  </userSettings>
</configuration>
IDViewer_2D/App.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
<Application x:Class="SmartScanner.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:SmartScanner"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
    </Application.Resources>
</Application>
IDViewer_2D/App.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace SmartScanner
{
    /// <summary>
    /// App.xaml çš„交互逻辑
    /// </summary>
    public partial class App : Application
    {
    }
}
IDViewer_2D/AppRestartHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace SmartScanner
{
    public static class AppRestartHelper
    {
        private const string TaskName = "MyApp_Restart_Task";
        public static async Task RestartAsync()
        {
            try
            {
                // 1. åˆ›å»ºä¸´æ—¶æ‰¹å¤„理文件
                string batPath = CreateRestartBatchFile();
                // 2. åˆ›å»ºä»»åŠ¡è®¡åˆ’
                CreateScheduledTask(batPath);
                // 3. å»¶è¿Ÿç¡®ä¿ä»»åŠ¡å·²æ³¨å†Œ
                await Task.Delay(500);
                // 4. æ‰§è¡Œä»»åŠ¡å¹¶é€€å‡ºå½“å‰å®žä¾‹
                ExecuteRestartTask();
                Application.Current.Shutdown();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"重启失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private static string CreateRestartBatchFile()
        {
            string tempPath = Path.GetTempPath();
            string batPath = Path.Combine(tempPath, $"{Guid.NewGuid()}_restart.bat");
            string exePath = Process.GetCurrentProcess().MainModule.FileName;
            string workingDir = Path.GetDirectoryName(exePath);
            string batContent = $@"
@echo off
timeout /t 1 /nobreak > nul
cd /d ""{workingDir}""
start """" ""{exePath}""
del ""%~f0""
";
            File.WriteAllText(batPath, batContent);
            return batPath;
        }
        private static void CreateScheduledTask(string batPath)
        {
            // åˆ é™¤å¯èƒ½å­˜åœ¨çš„æ—§ä»»åŠ¡
            DeleteExistingTask();
            // åˆ›å»ºæ–°ä»»åŠ¡
            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = "schtasks.exe",
                Arguments = $"/Create /TN \"{TaskName}\" /TR \"{batPath}\" /SC ONCE /ST {DateTime.Now.AddSeconds(1):HH:mm:ss} /F",
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true
            };
            Process.Start(psi)?.WaitForExit(2000);
        }
        private static void ExecuteRestartTask()
        {
            Process.Start(new ProcessStartInfo
            {
                FileName = "schtasks.exe",
                Arguments = $"/Run /TN \"{TaskName}\"",
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true
            })?.WaitForExit(1000);
            // åˆ é™¤ä»»åŠ¡
            DeleteExistingTask();
        }
        private static void DeleteExistingTask()
        {
            Process.Start(new ProcessStartInfo
            {
                FileName = "schtasks.exe",
                Arguments = $"/Delete /TN \"{TaskName}\" /F",
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true
            })?.WaitForExit(1000);
        }
    }
}
IDViewer_2D/DownloadData.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,216 @@
<Window x:Class="SmartScanner.DownloadData"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="clr-namespace:SmartScanner"
      xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
      xmlns:Properties="clr-namespace:SmartScanner.Properties"
      mc:Ignorable="d"
      Width="490" Height="320"
      Title="图像设置">
    <Grid Background="#3C3C3C">
        <Grid.Resources>
            <Style x:Key="TextBoxStyle" TargetType="TextBox">
                <Style.Setters>
                    <Setter Property="VerticalContentAlignment" Value="Center"/>
                    <Setter Property="HorizontalContentAlignment" Value="Right"/>
                    <Setter Property="Background" Value="#6C6C6C"/>
                    <Setter Property="BorderBrush" Value="#1F0000"/>
                    <Setter Property="Foreground" Value="White"/>
                    <Setter Property="BorderThickness" Value="1"/>
                </Style.Setters>
            </Style>
            <Style TargetType="RadioButton" x:Key="RadioButtonStyle">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="RadioButton">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CheckStates">
                                        <VisualState x:Name="Checked">
                                            <Storyboard>
                                                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="contentPresenter">
                                                    <EasingColorKeyFrame KeyTime="0" Value="White"/>
                                                </ColorAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Unchecked"/>
                                        <VisualState x:Name="Indeterminate"/>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                                <Ellipse Width="{Binding ActualHeight, ElementName=contentPresenter}" Height="{Binding ActualHeight, ElementName=contentPresenter}" Fill="{TemplateBinding Background}"/>
                                <ContentPresenter x:Name="contentPresenter" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="BtnLabelStyle">
                <Style.Triggers>
                    <Trigger Property="Button.IsFocused" Value="False">
                        <Setter Property="Button.Background" Value="Transparent"/>
                        <Setter Property="Button.BorderThickness" Value="0"/>
                    </Trigger>
                    <Trigger Property="Button.IsFocused" Value="True">
                        <Setter Property="Button.Background" Value="#4D0000"/>
                        <Setter Property="Button.BorderThickness" Value="0"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="LabelStyle">
                <Style.Triggers>
                    <Trigger Property="Label.IsFocused" Value="False">
                        <Setter Property="Label.Background" Value="Transparent"/>
                        <Setter Property="Label.Foreground" Value="White"/>
                    </Trigger>
                    <Trigger Property="Label.IsFocused" Value="True">
                        <Setter Property="Label.Background" Value="#FFBEE6FD"/>
                        <Setter Property="Label.Foreground" Value="#4F4F4F"/>
                    </Trigger>
                    <Trigger Property="Label.IsMouseOver" Value="True">
                        <Setter Property="Label.Background" Value="#FFBEE6FD"/>
                        <Setter Property="Label.Foreground" Value="#4F4F4F"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="FocusVisual">
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle Margin="2" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <!--按钮静态时背景颜色-->
            <SolidColorBrush x:Key="Button.Static.Background" Color="#4F4F4F"/>
            <!--按钮静态时边框颜色-->
            <SolidColorBrush x:Key="Button.Static.Border" Color="#2F0000"/>
            <!--按钮静态时文字颜色-->
            <SolidColorBrush x:Key="Button.Static.Foreground" Color="White"/>
            <!--鼠标移入时背景颜色-->
            <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#4D0000"/>
            <!--鼠标移入时边框颜色-->
            <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#2F0000"/>
            <!--鼠标按下时背景颜色-->
            <SolidColorBrush x:Key="Button.Pressed.Background" Color="#4D0000"/>
            <!--鼠标按下时边框颜色-->
            <SolidColorBrush x:Key="Button.Pressed.Border" Color="#2F0000"/>
            <!--按钮不使用时背景颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Background" Color="Gray"/>
            <!--按钮不使用时边框颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
            <!--按钮不使用时文字颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="White"/>
            <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
                <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
                <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
                <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
                <Setter Property="Foreground" Value="{StaticResource Button.Static.Foreground}"/>
                <Setter Property="BorderThickness" Value="1"/>
                <!--边框宽度,设置为0 å³ï¼šæ— è¾¹æ¡†-->
                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="Padding" Value="1"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border x:Name="border" CornerRadius="5" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
                                <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <!--触发器:根据依赖属性的值去控制控件的状态-->
                            <ControlTemplate.Triggers>
                                <!--默认属性-->
                                <Trigger Property="IsDefaulted" Value="true">
                                    <!--<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>-->
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Static.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Static.Border}"/>
                                    <Setter Property="TextElement.Foreground" TargetName="border" Value="{StaticResource Button.Static.Foreground}"/>
                                </Trigger>
                                <!--鼠标移入属性-->
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
                                </Trigger>
                                <!--鼠标按下属性-->
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
                                </Trigger>
                                <!--按钮可用状态属性-->
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
                                    <!--<Setter Property="Foreground" TargetName="border" Value="{StaticResource Button.Disabled.Foreground}"/>-->
                                    <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="70"/>
            <RowDefinition Height="160"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0">
            <Label Content="路径选择:" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Foreground="White" Height="35"/>
            <StackPanel Orientation="Horizontal" Height="35">
                <TextBox Name="SetDataSavingRoad" Text="{Binding Source={x:Static Properties:Settings.Default}, Path=DataSavingRoad, Mode=TwoWay}" Style="{StaticResource TextBoxStyle}"
                         HorizontalContentAlignment="Left"  Height="30" FontSize="14" ToolTip="文件存储路径" Width="400" Margin="10,0,0,0" MouseDoubleClick="SetDataSavingRoad_MouseDoubleClick"/>
                <Button Name="SelectFilePath" Content="浏览…" Width="50" Height="30" Click="SelectFilePath_Click" Style="{DynamicResource ButtonStyle}"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Grid.Row="1">
            <StackPanel Orientation="Horizontal" Height="35">
                <Label Content="保存设置:" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Foreground="White" Width="100"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Height="35">
                <CheckBox Name="ImageDeleteCheck" Content="定期清图" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ImageDeleteEnabled, Mode=TwoWay}" Unchecked="ImageDeleteCheck_Unchecked"  Checked="ImageDeleteCheck_Checked" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Foreground="White" Width="130" Margin="20,0,0,0"/>
                <toolkit:IntegerUpDown x:Name="Data_deleteImage" FormatString="N" Increment="1" Maximum="200000"
                                       Value="{Binding Source={x:Static Properties:Settings.Default}, Path=DeleteImageDays, Mode=TwoWay}"
                                        LostFocus="Data_deleteImage_LostFocus"  Width="100" Height="25"/>
                <Label Content="天" Foreground="White" VerticalAlignment="Center"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Height="35">
                <StackPanel Orientation="Horizontal" Width="300">
                <CheckBox Name="ImageSaveCheck" Content="启用图像保存" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=ImageSaveEnabled, Mode=TwoWay}"
                          Unchecked="ImageSaveCheck_Unchecked" Checked="ImageSaveCheck_Checked"
                          HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Foreground="White" Width="130" Margin="20,0,0,0"/>
                <Label Content="保存格式" Foreground="White" VerticalAlignment="Center"/>
                    <ComboBox Name="ImageFormat" SelectedIndex="{Binding Source={x:Static Properties:Settings.Default}, Path=ImageFormatSelect, Mode=TwoWay}"
                              Height="25" SelectionChanged="ImageFormat_SelectionChanged" LostFocus="ImageFormat_LostFocus">
                    <ComboBoxItem Content=".BMP"/>
                    <ComboBoxItem Content=".JPG"/>
                    <ComboBoxItem Content=".PNG"/>
                </ComboBox>
                </StackPanel>
                <StackPanel x:Name="CompressionVisible" Orientation="Horizontal" Visibility="Visible">
                <Label Content="压缩比率" Foreground="White" VerticalAlignment="Center"/>
                    <toolkit:IntegerUpDown x:Name="ImageCompressionRatio" FormatString="N" Increment="1" Maximum="10" Minimum="0" UpdateValueOnEnterKey="True"
                                       Value="{Binding Source={x:Static Properties:Settings.Default}, Path=CompressionRatio, Mode=TwoWay}"
                                       Watermark="取值[0-10]" Width="85" Height="25" LostFocus="ImageCompressionRatio_LostFocus"/>
                </StackPanel>
            </StackPanel>
            <StackPanel Orientation="Horizontal" Height="35">
                <CheckBox Name="MemoryAlarmCheck" Content="存储空间预警" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=MemoryAlarmEnabled, Mode=TwoWay}"
                          Unchecked="MemoryAlarmCheck_Unchecked"  Checked="MemoryAlarmCheck_Checked"  HorizontalContentAlignment="Left" VerticalContentAlignment="Center" Foreground="White" Width="130" Margin="20,0,0,0"/>
                <toolkit:IntegerUpDown x:Name="MemoryAlarm" FormatString="N" Maximum="90" Minimum="10" UpdateValueOnEnterKey="True"
                                       Value="{Binding Source={x:Static Properties:Settings.Default}, Path=MemoryAlarmSetting, Mode=TwoWay}"
                                       Width="100" Height="25" LostFocus="MemoryAlarm_LostFocus"/>
                <Label Content="%" Foreground="White" VerticalAlignment="Center"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Grid.Row="2">
            <Button Content="确定" Width="300" Height="30" Name="Confirm_Btn" Click="Confirm_Btn_Click"  Margin="5" Style="{DynamicResource ButtonStyle}"/>
        </StackPanel>
    </Grid>
</Window>
IDViewer_2D/DownloadData.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,309 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SmartScanner.OperateLog;
using Microsoft.Win32;
namespace SmartScanner
{
    /// <summary>
    /// DownloadData.xaml çš„交互逻辑
    /// </summary>
    public partial class DownloadData : Window
    {
        public static bool ImageSave;//图像保存
        public static string ImageSavingPath;//保存路径
        public static int ImageCompressionRatio_main;//图像压缩比率
        public static int ImageDeleteData_main;//图像定期删除
        public static string ImageFormat_main;//图像保存格式
        public static bool MemoryAlarm_main;//存储空间报警
        public static int ImageMemoryAlarm_main;//存储空间报警
        private bool isF = false;
        public static bool isOP = true;
        public DownloadData()
        {
            InitializeComponent();
            isF = true;
            Init();
            // çª—口关闭时保存设置
            this.Closed += (s, e) => Properties.Settings.Default.Save();
        }
        public void SetControlsEnabled(bool isEnabled)
        {
            // ç¦ç”¨æˆ–启用所有可编辑的控件
            //LoadConfig_RJ.IsEnabled = isEnabled;
            SelectFilePath.IsEnabled = isEnabled;
            ImageDeleteCheck.IsEnabled = isEnabled;
            Data_deleteImage.IsEnabled = isEnabled;
            ImageSaveCheck.IsEnabled = isEnabled;
            ImageFormat.IsEnabled = isEnabled;
            ImageCompressionRatio.IsEnabled = isEnabled;
            MemoryAlarmCheck.IsEnabled = isEnabled;
            MemoryAlarm.IsEnabled = isEnabled;
            SetDataSavingRoad.IsEnabled = isEnabled;
            // ... å…¶ä»–需要控制的控件
        }
        public void Init()
        {
            ImageSave = (bool)ImageSaveCheck.IsChecked;
            MemoryAlarm_main = (bool)MemoryAlarmCheck.IsChecked;
            ImageMemoryAlarm_main = (int)MemoryAlarm.Value;
            ImageSavingPath = SetDataSavingRoad.Text;
            ImageCompressionRatio_main = (int)ImageCompressionRatio.Value;
            ImageDeleteData_main = (int)Data_deleteImage.Value;
            switch (ImageFormat.SelectedIndex)
            {
                case 0:
                    ImageFormat_main = ".BMP";
                    break;
                case 1:
                    ImageFormat_main = ".JPG";
                    break;
                case 2:
                    ImageFormat_main = ".PNG";
                    break;
                default:
                    break;
            }
            if (ImageFormat.SelectedIndex == 0)
            {
                CompressionVisible.Visibility = Visibility.Collapsed;
            }
            else
            {
                CompressionVisible.Visibility = Visibility.Visible;
            }
        }
        private void SetDataSavingRoad_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var folderDialog = new System.Windows.Forms.FolderBrowserDialog
            {
                Description = "选择图像存储路径",
                SelectedPath = Properties.Settings.Default.DataSavingRoad
            };
            if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Properties.Settings.Default.DataSavingRoad = folderDialog.SelectedPath;
                SetDataSavingRoad.Text = folderDialog.SelectedPath;
            }
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图像存储路径修改",
                $"路径修改为: {folderDialog.SelectedPath}",
                null);
        }
        private void SelectFilePath_Click(object sender, RoutedEventArgs e)
        {
            var folderDialog = new System.Windows.Forms.FolderBrowserDialog
            {
                Description = "选择图像存储路径",
                SelectedPath = Properties.Settings.Default.DataSavingRoad
            };
            if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Properties.Settings.Default.DataSavingRoad = folderDialog.SelectedPath;
                SetDataSavingRoad.Text = folderDialog.SelectedPath;
            }
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图像存储路径修改",
                $"路径修改为: {folderDialog.SelectedPath}",
                null);
        }
        private void ImageDeleteCheck_Unchecked(object sender, RoutedEventArgs e)
        {
        }
        private void ImageDeleteCheck_Checked(object sender, RoutedEventArgs e)
        {
        }
        private void ImageSaveCheck_Unchecked(object sender, RoutedEventArgs e)
        {
            ImageSave = false;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图像是否保存修改",
                $"修改为: ä¸ä¿å­˜",
                null);
        }
        private void ImageSaveCheck_Checked(object sender, RoutedEventArgs e)
        {
            ImageSave = true;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图像是否保存修改",
                $"修改为: ä¿å­˜",
                null);
        }
        private void Confirm_Btn_Click(object sender, RoutedEventArgs e)
        {
            Properties.Settings.Default.Save();
            MessageBox.Show("设置成功  æ³¨ï¼šå®šæœŸæ¸…图功能需重启软件后生效", "成功", MessageBoxButton.OK, MessageBoxImage.Asterisk);
        }
        private void ImageCompressionRatio_LostFocus(object sender, RoutedEventArgs e)
        {
            if (ImageCompressionRatio.Value == null) { return; }
            ImageCompressionRatio_main = (int)ImageCompressionRatio.Value;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图像压缩比率修改",
                $"修改为: {ImageCompressionRatio_main}",
                null);
        }
        private void Data_deleteImage_LostFocus(object sender, RoutedEventArgs e)
        {
            if (Data_deleteImage.Value == null) { return; }
            ImageDeleteData_main = (int)Data_deleteImage.Value;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "清图周期修改",
                $"修改为: {ImageDeleteData_main}",
                null);
        }
        private void ImageFormat_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!isF) return;
            switch (ImageFormat.SelectedIndex)
            {
                case 0:
                    ImageFormat_main = ".BMP";
                    break;
                case 1:
                    ImageFormat_main = ".JPG";
                    break;
                case 2:
                    ImageFormat_main = ".PNG";
                    break;
                default:
                    break;
            }
            if (ImageFormat.SelectedIndex == 0)
            {
                CompressionVisible.Visibility = Visibility.Collapsed;
            }
            else
            {
                CompressionVisible.Visibility = Visibility.Visible;
            }
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图片保存格式修改",
                $"修改为: {ImageFormat_main}",
                null);
        }
        private void ImageFormat_LostFocus(object sender, RoutedEventArgs e)
        {
            if (!isF) return;
            switch (ImageFormat.SelectedIndex)
            {
                case 0:
                    ImageFormat_main = ".BMP";
                    break;
                case 1:
                    ImageFormat_main = ".JPG";
                    break;
                case 2:
                    ImageFormat_main = ".PNG";
                    break;
                default:
                    break;
            }
            if (ImageFormat.SelectedIndex == 0)
            {
                CompressionVisible.Visibility = Visibility.Collapsed;
            }
            else
            {
                CompressionVisible.Visibility = Visibility.Visible;
            }
            // è®°å½•日志
            OperateLogService.LogOperation(
                "图片保存格式修改",
                $"修改为: {ImageFormat_main}",
                null);
        }
        private void MemoryAlarmCheck_Unchecked(object sender, RoutedEventArgs e)
        {
            MemoryAlarm_main = false;
        }
        private void MemoryAlarmCheck_Checked(object sender, RoutedEventArgs e)
        {
            MemoryAlarm_main = true;
        }
        private void MemoryAlarm_LostFocus(object sender, RoutedEventArgs e)
        {
            if (MemoryAlarm.Value == null) { return; }
            ImageMemoryAlarm_main = (int)MemoryAlarm.Value;
        }
        private (double usedPercentage, string driveName) GetDriveUsage()
        {
            // èŽ·å–ç³»ç»Ÿç›˜
            DownloadData downloadData = new DownloadData();
            DriveInfo drive = new DriveInfo($"{downloadData.SetDataSavingRoad.Text}");
            double totalSpace = drive.TotalSize;
            double freeSpace = drive.AvailableFreeSpace;
            double usedPercentage = 100 - (freeSpace / totalSpace * 100);
            return (usedPercentage, drive.Name);
        }
        public async void CheckStorage()
        {
            while (isOP)
            {
                if (MemoryAlarm_main)
                {
                    var (usedPercentage, driveName) = GetDriveUsage();
                    int threshold = 100 - (int)MemoryAlarm.Value;
                    Dispatcher.Invoke(() =>
                    {
                        if (usedPercentage >= threshold)
                        {
                            // æŠ¥è­¦ï¼šæ˜¾ç¤ºçº¢è‰²è­¦å‘Š
                            MessageBox.Show($"{driveName} ç›˜å·²ä½¿ç”¨ {usedPercentage:F1}%!", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                        }
                        else
                        {
                            Console.WriteLine($"{driveName} ç›˜å·²ä½¿ç”¨ {usedPercentage:F1}%!");
                        }
                    });
                    await Task.Delay(10000);
                }
                else
                {
                    await Task.Delay(10000);
                }
            }
        }
    }
}
IDViewer_2D/ExcelResultRecorder.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,198 @@
using SmartScanner.ViewModel;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace SmartScanner
{
    public static class ExcelResultRecorder
    {
        private static readonly string reportDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Reports");
        private static readonly string reportFileName = $"DetectionResults_{DateTime.Now:yyyyMMdd}.xlsx";
        private static readonly List<DetectionRecord> _pendingRecords = new List<DetectionRecord>();
        private static readonly object _lock = new object();
        private static Timer _autoFlushTimer;
        static ExcelResultRecorder()
        {
            try
            {
                // ç¡®ä¿æŠ¥å‘Šç›®å½•存在
                if (!Directory.Exists(reportDirectory))
                {
                    Directory.CreateDirectory(reportDirectory);
                }
                // è®¾ç½®EPPlus许可证上下文
                //ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
                ExcelPackage.License.SetNonCommercialPersonal("Lanbao");
                InitializeAutoFlush();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"ExcelResultRecorder初始化失败: {ex.Message}");
                throw;
            }
        }
        public static void RecordDetectionResult(int sequence, string result, string qrCode = "N/A")
        {
            lock (_lock)
            {
                _pendingRecords.Add(new DetectionRecord
                {
                    QrCode = qrCode,
                    Sequence = sequence,
                    Result = result,
                    Operator = UserManager.CurrentUser?.Username ?? "Unknown"
                });
                // æ¯10条记录或每隔20秒自动保存一次
                if (_pendingRecords.Count >= 10)
                {
                    Task.Run(() => FlushRecords());
                }
            }
        }
        public static void FlushRecords()
        {
            lock (_lock)
            {
                if (_pendingRecords.Count == 0) return;
                try
                {
                    string filePath = Path.Combine(reportDirectory, reportFileName);
                    using (var package = new ExcelPackage(new FileInfo(filePath)))
                    {
                        ExcelWorksheet worksheet = package.Workbook.Worksheets["检测结果"] ??
                                                 package.Workbook.Worksheets.Add("检测结果");
                        // åˆå§‹åŒ–表头(如果文件是新创建的)
                        if (worksheet.Dimension == null)
                        {
                            CreateHeader(worksheet);
                        }
                        // æ‰¾åˆ°ç¬¬ä¸€ä¸ªç©ºè¡Œ
                        int startRow = worksheet.Dimension?.End.Row + 1 ?? 2;
                        // æ‰¹é‡å†™å…¥æ•°æ®
                        for (int i = 0; i < _pendingRecords.Count; i++)
                        {
                            var record = _pendingRecords[i];
                            int currentRow = startRow + i;
                            worksheet.Cells[currentRow, 1].Value = record.QrCode;
                            worksheet.Cells[currentRow, 2].Value = $"点位 {record.Sequence}";
                            worksheet.Cells[currentRow, 3].Value = record.Result;
                            worksheet.Cells[currentRow, 4].Value = record.DetectionTime.ToString("yyyy-MM-dd HH:mm:ss");
                            worksheet.Cells[currentRow, 5].Value = record.Operator;
                            // æ ¹æ®ç»“果设置单元格背景色
                            var resultCell = worksheet.Cells[currentRow, 3];
                            resultCell.Style.Fill.PatternType = ExcelFillStyle.Solid;
                            resultCell.Style.Fill.BackgroundColor.SetColor(
                                record.Result == "OK" ? Color.LightGreen : Color.Red);
                        }
                        // è‡ªåŠ¨è°ƒæ•´åˆ—å®½
                        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
                        // ä¿å­˜æ–‡ä»¶
                        package.Save();
                        EnhancedLogViewModel.Instance.AddLog($"{_pendingRecords.Count}条检测结果已保存至{reportFileName}");
                    }
                    _pendingRecords.Clear();
                }
                catch (Exception ex)
                {
                    // è®°å½•错误并保留未写入的记录
                    Console.WriteLine($"记录检测结果到Excel失败: {ex.Message}");
                    EnhancedLogViewModel.Instance.AddLog($"{_pendingRecords.Count}条检测结果保存失败,请关闭{reportFileName}后重试", "ERROR");
                }
            }
        }
        private static void CreateHeader(ExcelWorksheet worksheet)
        {
            // è®¾ç½®è¡¨å¤´
            worksheet.Cells["A1"].Value = "二维码";
            worksheet.Cells["B1"].Value = "检测点位";
            worksheet.Cells["C1"].Value = "检测结果";
            worksheet.Cells["D1"].Value = "检测时间";
            worksheet.Cells["E1"].Value = "操作人员";
            // è®¾ç½®è¡¨å¤´æ ·å¼
            using (var range = worksheet.Cells["A1:E1"])
            {
                range.Style.Font.Bold = true;
                range.Style.Border.Top.Style = ExcelBorderStyle.Thin;
                range.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                range.Style.Border.Left.Style = ExcelBorderStyle.Thin;
                range.Style.Border.Right.Style = ExcelBorderStyle.Thin;
                range.Style.Fill.PatternType = ExcelFillStyle.Solid;
                range.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
                range.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
            }
        }
        public static void OpenReportFolder()
        {
            try
            {
                if (Directory.Exists(reportDirectory))
                {
                    System.Diagnostics.Process.Start("explorer.exe", reportDirectory);
                }
                else
                {
                    Console.WriteLine("报告目录不存在");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"打开报告文件夹失败: {ex.Message}");
            }
        }
        // å®šæ—¶ä¿å­˜ä»»åŠ¡
        public static void InitializeAutoFlush()
        {
            // å¦‚果定时器已存在,先停止并释放
            if (_autoFlushTimer != null)
            {
                _autoFlushTimer.Stop();
                _autoFlushTimer.Dispose();
            }
            // åˆ›å»ºæ–°çš„定时器
            _autoFlushTimer = new Timer(20000);
            _autoFlushTimer.Elapsed += (s, e) =>
            {
                try
                {
                    Task.Run(() => FlushRecords());
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"定时保存记录失败: {ex.Message}");
                }
            };
            _autoFlushTimer.AutoReset = true;
            _autoFlushTimer.Start();
        }
        private class DetectionRecord
        {
            public string QrCode { get; set; }
            public int Sequence { get; set; }
            public string Result { get; set; }
            public DateTime DetectionTime { get; } = DateTime.Now;
            public string Operator { get; set; }
        }
    }
}
IDViewer_2D/IDViewer2D.ico
IDViewer_2D/IDViewerDefines.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2259 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using static SmartScanner.IDViewerDefines;
using System.Dynamic;
using System.Net;
namespace SmartScanner
{
    class IDViewerDefines
    {
        // ä½¿ç”¨æžšä¸¾è¡¨ç¤ºå›žè°ƒæ¶ˆæ¯ID
        public enum CallbackMessageID
        {
            DeviceConnectionEstablished = 1,
            DeviceConnectionClosed = 2
        }
        public enum ErrorCodes
        {
            ID_OK = 0,                                                              //成功
            ID_ERROR_ALREADY_INIT = 146000010,                                      //已经初始化
            ID_ERROR_NOT_INIT = 146000011,                                          //未初始化
            ID_ERRORREATE_DEVICE_INFO_NOT_EXSIST = 146000012,                       //当前创建设备不存在
            ID_ERROR_SET_IP_DEVICE_ALREADYREATED = 146000013,                       //当前设置IP设备已经创建
            ID_ERROR_DEVICE_HAVE_OPENED = 146000014,                                //设备已经打开
            ID_ERROR_OPEN_DEVICEONNECT_PARAMS_ERROR = 146000015,                    //打开设备连接参数错误
            ID_ERROR_OPEN_DEVICEONNECT_ISREATE = 146000016,                         //打开设备连接已经创建
            ID_ERROR_OPEN_DEVICEONNECT_SOCKET_FAILED = 146000017,                   //打开设备连接建立失败
            ID_ERROR_OPEN_DEVICEONNECT_FAILED = 146000018,                          //打开设备连接失败
            ID_ERROR_DEVICE_NOT_OPEN = 146000019,                                   //设备未打开
            ID_ERROR_DEVICE_IS_RUNNING = 146000020,                                 //设备已经在运行模式
            ID_ERROR_DEVICE_IS_DEBUGGING = 146000021,                               //设备已经在调试模式
            ID_ERROR_DEVICE_QUERY_HARDWARE_INFO_FAILED = 146000022,                 //获取设备硬件信息失败
            ID_ERROR_OPEN_DEVICEREATE_DATA_RECEIVED_FAILED = 146000023,             //打开设备接收数据服务创建失败
            ID_ERROR_OPEN_DEVICE_SOLUTION_MANAGERONNECTION_FAILED = 146000024,      //打开设备时连接方案管理工具失败
            ID_ERROR_SOLUTION_MANAGER_TIMEOUT = 146000025,                          //方案管理类超时
            ID_ERROR_SOLUTION_MANAGERAN_NOT_DELETEURRENT_SOLUTION = 146000026,      //不能删除当前方案
            ID_ERROR_SOLUTION_MANAGERURRENT_SOLUTION_NOT_EXISTED = 146000027,       //当前方案不存在
            ID_ERROR_SET_IP_ADDRESS_INVALID = 146000028,                            //设置IP地址不合法
            ID_ERROR_SET_IP_MASK_INVALID = 146000029,                               //设置子网掩码地址不合法
            ID_ERROR_SET_IP_GATEWAY_INVALID = 146000030,                            //设置网关地址不合法
            ID_ERROR_SET_IP_ADDRESS_GATEWAY_NOT_IN_SAME_SUBNET = 146000031,         //设置的IP地址和网关不在同一网段
            ID_ERROR_SET_IP_ADDRESS_ALREADY_EXISTED = 146000032,                    //设置的IP已经存在
            ID_ERROR_SOLUTION_MANAGER_SOLUTION_NAME_INVALID = 46000033,             //方案名称非法,不能包含<>:\"/\\|?*
            ID_ERROR_SET_PARAMS_CAN_NOT_WHEN_RUNNING = 146000034,                    //运行中不能设置该参数
            ID_ERROR_SET_PARAMS_ROI_NOT_EXISTED = 146000035,                        //删除的ROI不存在
            ID_ERROR_DEBUG_RESPONSE_TYPE_ERROR = 146000036,                            //调试反馈信息类型不匹配
            ID_ERROR_DEVICE_TYPE_NO_SUCH_FUNCTION = 146000037,                        //当前设备类型没有该功能
            ID_ERROR_DEBUG_GET_FOCUS_FAILED = 146000038,                            //获取焦距失败
            ID_ERROR_DEBUG_AUTO_FOCUS_FAILED = 146000039,                            //自动对焦失败
            ID_ERROR_SOLUTION_LOAD_CONTENT_ERROR = 146000040,                        //方案内容解析失败
            ID_ERROR_SOLUTION_PARAMS_INDEX_ERROR = 146000041,                        //参数组错误
            ID_ERROR_SOLUTION_ILLUMINAN_INDEX_ERROR = 146000042,                    //光源通道错误
            ID_ERROR_SOLUTION_ILLUMINAN_BRIGHTNESS_VALUE_ERROR = 146000043,            //光源通道亮度错误
            ID_ERROR_SOLUTION_DOWNLOAD_ERROR = 146000044,                            //当前方案下载失败
            ID_ERROR_IMAGE_CAPTURE_TIMEOUT = 146000045,                             //抓图超时
            ID_ERROR_ROI_ADD_LIMIT_REACHED = 146000046,                             //ROI添加上限已达到
            ID_ERROR_SET_PARAMS_CODETYPE_NOT_EXISTED = 146000047,                    //删除的码制不存在
            ID_ERROR_DEVICE_NOT_IN_FREE_ACQUISITION_MODE = 146000048,                //相机未处于自由采集模式
            ID_ERROR_SET_PARAMS_OCR_NOT_EXISTED = 146000049,                        //删除的OCR不存在
            ID_ERROR_CONFIG_LOAD_CONTENT_ERROR = 146000050,                            //配置内容解析失败
            ID_ERROR_CONFIG_ITEM_NOT_EXISTED = 146000051,                            //配置项不存在
            ID_ERROR_CONFIG_ITEM_SET_FAILED = 146000052,                            //配置项设置失败
            ID_ERROR_CONFIG_ITEM_GET_FAILED = 146000053,                            //配置项获取失败
            ID_ERROR_DO_ADD_LIMIT_RECHED = 146000054,                               //DO添加上限已达到
            ID_ERROR_TRIGGER_SOURCE_NO_EXISTED = 146000055,                         //触发源不存在
            ID_ERROR_PARAM_NO_FOUND = 146000056,                                    //参数不存在
            ID_ERROR_PARAM_POSITION_INVALID = 146000057,                            //参数坐标异常
            ID_ERROR_SET_PARAMS_CAN_NOT_WHEN_DEBUGING = 146000058,                    //调试中不能设置该参数
            ID_ERROR_DI_ADD_LIMIT_RECHED = 146000059,                               //DI添加上限已达到
        }
        public enum IDImageType
        {
            ID_IMAGE_8U = 0,            // 8位无符号类型
            ID_IMAGE_8S,                // 8位有符号类型
            ID_IMAGE_16U,                // 16位无符号类型
            ID_IMAGE_16S,                // 16位有符号类型
            ID_IMAGE_32S,                // 32位有符号类型
            ID_IMAGE_32F,                // 32位浮点类型
            ID_IMAGE_64F              // 64位浮点类型
        }
        /*
        *触发模式
        */
        public enum IDTriggerModel
        {
            ID_TRIGGER_HOLD_MODEL_SINGLE_FRAME = 0,                           //单帧触发
            ID_TRIGGER_HOLD_MODEL_MULTI_FRAME = 1,                                //多帧触发
            ID_TRIGGER_HOLD_MODEL_HOLD = 2,                                       //触发保持
            ID_TRIGGER_HOLD_MODEL_READ_SUCCESS = 3                                //读取成功输出
        }
        /*
        *信号持续条件
        */
        public enum IDTriggerSignalHoldCondition
        {
            ID_TRIGGER_HOLDONDITION_TIMES = 0,                          //时间
            ID_TRIGGER_HOLDONDITION_FRAMES,                             //采集帧数
        }
        /*
        *触发源
        */
        public enum IDTriggerSource
        {
            //ID_TRIGGER_SOURCE_TCP_SERVER = 2,                                 //tcp服务器触发
            //ID_TRIGGER_SOURCE_TCPLIENT = 3,                                   //tcp客户端触发
            //ID_TRIGGER_SOURCE_UDP = 4,                                        //UDP触发
            //ID_TRIGGER_SOURCE_SERIAL_PORT = 5,                                //串口触发
            //ID_TRIGGER_SOURCE_HARDWARE = 13                                   //硬件触发
            ID_TRIGGER_SOURCE_SOFT = 0,                                     //软触发
            ID_TRIGGER_SOURCE_AUTO,                                         //自动触发
            ID_TRIGGER_SOURCE_TCP_SERVER,                                   //tcp服务器触发
            ID_TRIGGER_SOURCE_TCP_CLIENT,                                   //tcp客户端触发
            ID_TRIGGER_SOURCE_UDP,                                          //UDP触发
            ID_TRIGGER_SOURCE_SERIAL_PORT,                                  //串口触发
            ID_TRIGGER_SOURCE_MODBUS,                                       //modbus触发
            ID_TRIGGER_SOURCE_EIP,                                          //EIP触发
            ID_TRIGGER_SOURCE_PROFINET,                                     //profinet触发
            ID_TRIGGER_SOURCE_FINS,                                         //Fins协议触发
            ID_TRIGGER_SOURCE_MC,                                           //MC触发
            ID_TRIGGER_SOURCE_ETHERCAT,                                     //Ethercat
            ID_TRIGGER_SOURCE_NETWORKING,                                   //组网触发
            ID_TRIGGER_SOURCE_HARDWARE,                                     //硬件触发
            ID_TRIGGER_SOURCE_SENSING                                        //感应模式
        }
        /*
        *触发参数
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDTriggerParams
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool triggerStatus;                                             //触发状态
            public uint triggerDelay;                                      //触发延迟ms
            public IDTriggerModel triggerModel;                                  //触发模式
            public IDTriggerSignalHoldCondition conditionMode;                       //==信号保持条件模式 æ³¨ï¼šåªæœ‰è§¦å‘模式选择“多帧”、“读取成功输出”时有效
            public uint triggerFrames;                                     //==触发采集帧数 æ³¨ï¼šåªæœ‰åœ¨ä¿¡å·ä¿æŒæ¡ä»¶æ¨¡å¼é€‰æ‹©â€œé‡‡é›†å¸§æ•°â€æ—¶æœ‰æ•ˆ
            public uint triggerDuration;                                   //触发持续时间 æ³¨ï¼šåªæœ‰åœ¨ä¿¡å·ä¿æŒæ¡ä»¶ä¸ºæ—¶â€œæ—¶é—´â€æœ‰æ•ˆ
            public uint triggerCodeNum;                                    //读取条码数 æ³¨ï¼šåªæœ‰è§¦å‘模式选择“读取成功输出”时有效
            public IDTriggerSource triggerSource;                                    //触发源
            public uint triggerInterval;                                   //软触发间隔ms
            [MarshalAs(UnmanagedType.I1)]
            public bool statisticByCodeNum;                                        //码数目统计使能(只有触发模式选择“读取成功输出”时有效)
        }
        public class IDTriggerParamsCreate
        {
            public IDTriggerParams createIDTriggerParams()
            {
                IDTriggerParams idtriParams = new IDTriggerParams();
                idtriParams.triggerStatus = false;
                idtriParams.triggerDelay = 0;
                idtriParams.triggerModel = IDTriggerModel.ID_TRIGGER_HOLD_MODEL_SINGLE_FRAME;
                idtriParams.conditionMode = IDTriggerSignalHoldCondition.ID_TRIGGER_HOLDONDITION_TIMES;
                idtriParams.triggerFrames = 1;
                idtriParams.triggerDuration = 2000;
                idtriParams.triggerCodeNum = 1;
                idtriParams.triggerSource = IDTriggerSource.ID_TRIGGER_SOURCE_TCP_SERVER;
                idtriParams.triggerInterval = 500;
                idtriParams.statisticByCodeNum = false;
                return idtriParams;
            }
        }
        /*
        *硬件触发极性
        */
        public enum IDTriggerPolarity
        {
            ID_HARDWARE_TRRIGER_LOW_LEVEL = 0,                                //低电平
            ID_HARDWARE_TRRIGER_HIGH_LEVEL = 1,                               //高电平
            ID_HARDWARE_TRRIGER_RISING_EDEG = 2,                              //上升沿
            ID_HARDWARE_TRRIGER_FALLING_EDEG = 3                              //下降沿
        }
        /*
        *硬件触发参数
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDHardwareTrigger
        {
            public uint debounceTime;                                                 //消抖时间us
            public IDTriggerPolarity triggerPolarity;                                //触发极性
            [MarshalAs(UnmanagedType.I1)]
            public bool restrictCodeNum;                                              //启用最大解码数
            public uint triggerCodeNum;                                                 //码数目
            public uint triggerTimeout;                                              //触发超时ms
            [MarshalAs(UnmanagedType.I1)]
            public bool elecLevelStatisticByCodeNum;                               //高低电平码数目统计使能(高低电平启用最大解码数开启才生效)
        }
        public class IDHardwareTriggerCreate
        {
            public IDHardwareTrigger createIDHardwareTrigger()
            {
                IDHardwareTrigger IDhardwareTrigger = new IDHardwareTrigger();
                IDhardwareTrigger.debounceTime = 100;
                IDhardwareTrigger.triggerPolarity = IDTriggerPolarity.ID_HARDWARE_TRRIGER_RISING_EDEG;          //默认高电平上升沿触发
                IDhardwareTrigger.restrictCodeNum = false;
                IDhardwareTrigger.triggerCodeNum = 1;
                IDhardwareTrigger.triggerTimeout = 0;
                IDhardwareTrigger.elecLevelStatisticByCodeNum = false;
                return IDhardwareTrigger;
            }
        }
        /*
        *TCP服务器触发
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDTcpServerTrigger
        {
            public uint port;                                              //服务器端口
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string startCommand;                                          //开始指令
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string endCommand;                                                //结束指令
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
        }
        public class IDTcpServerTriggerCreate
        {
            public IDTcpServerTrigger createIDTcpServerTrigger()
            {
                IDTcpServerTrigger temTcpServer = new IDTcpServerTrigger();
                temTcpServer.port = 1024;
                temTcpServer.startCommand = "start";
                temTcpServer.endCommand = "stop";
                temTcpServer.enableHEX = false;
                return temTcpServer;
            }
        }
        /*
        *TCP客户端触发
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDTcpClientTrigger
        {
            public uint port;                                              //服务器端口
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string ipAddress;                                             //服务器IP地址
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string startCommand;                                          //开始指令
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string endCommand;                                                //结束指令
            [MarshalAs(UnmanagedType.I1)]
            public bool heartBeatEnable;                                           //心跳使能
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string heartBeatCmd;                                          //心跳指令
            public uint heartBeatPeriod;                                   //心跳周期(ms)最小值50ms
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
        }
        public class IDTcpClientTriggerCreate
        {
            public IDTcpClientTrigger createIDTcpClientTrigger()
            {
                IDTcpClientTrigger temIDTcpClient = new IDTcpClientTrigger();
                temIDTcpClient.port = 1024;
                temIDTcpClient.ipAddress = "127.0.0.1";
                temIDTcpClient.startCommand = "start";
                temIDTcpClient.endCommand = "stop";
                temIDTcpClient.heartBeatEnable = false;
                temIDTcpClient.heartBeatCmd = "heartBeat";
                temIDTcpClient.heartBeatPeriod = 500;
                temIDTcpClient.enableHEX = false;
                return temIDTcpClient;
            }
        }
        /*
        *串口触发配置,对应串口参数配置使用串口通讯中数据
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDSerialPortTrigger
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string startCommand;                                          //开始指令
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string endCommand;                                                //结束指令
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
        }
        public class IDSerialPortTriggerCreate
        {
            public IDSerialPortTrigger createIDSerialPortTrigger()
            {
                IDSerialPortTrigger temIDSerialPort = new IDSerialPortTrigger();
                temIDSerialPort.startCommand = "start";
                temIDSerialPort.endCommand = "stop";
                temIDSerialPort.enableHEX = false;
                return temIDSerialPort;
            }
        }
        /*
        *UDP触发
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDUDPTrigger
        {
            public uint port;                                                       //端口
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string startCommand;                                          //开始指令
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string endCommand;                                            //结束指令
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
        }
        public class IDUDPTriggerCreate
        {
            public IDUDPTrigger createIDUDPTrigger()
            {
                IDUDPTrigger temIDUDP = new IDUDPTrigger();
                temIDUDP.port = 1025;
                temIDUDP.startCommand = "start";
                temIDUDP.endCommand = "stop";
                temIDUDP.enableHEX = false;
                return temIDUDP;
            }
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDFilterInfo
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool preventDuplicatEnable;                     //预防重复读取
            [MarshalAs(UnmanagedType.I1)]
            public bool removeDuplicateEnable;                     //去除重复使能
            [MarshalAs(UnmanagedType.I1)]
            public bool historyTimesEnable;                        //历史过滤使能
            [MarshalAs(UnmanagedType.I1)]
            public bool readThresholdEnable;                       //读取阈值使能
            [MarshalAs(UnmanagedType.I1)]
            public bool frameDuplicateEnable;                      //逐帧去重使能
            [MarshalAs(UnmanagedType.I1)]
            public bool angleEnable;                               //角度过滤开关
            public uint preventDuplicate;                  //预防重复读取时间
            public uint historyTimes;                      //历史过滤帧数
            public uint readCountThreshold;                //读取次数阈次数
            public uint angleInit;
            public uint angleOffset;
        }
        public class IDFilterInfoCreate
        {
            public IDFilterInfo createIDFilterInfo()
            {
                IDFilterInfo temIDFilterInfo = new IDFilterInfo
                {
                    preventDuplicatEnable = false,
                    historyTimesEnable = false,
                    readThresholdEnable = false,
                    angleEnable = false,
                    removeDuplicateEnable = true,
                    frameDuplicateEnable = true,
                    preventDuplicate = 20,
                    historyTimes = 1,
                    readCountThreshold = 1,
                    angleInit = 0,
                    angleOffset = 0,
                };
                return temIDFilterInfo;
            }
        }
        public enum IDFilterMode
        {
            ID_FILTER_MODE_REGULAR_C = 0,                                 //普通过滤
            ID_FILTER_MODE_REGEX_C                                        //正则表达式
        }
        //每个ROI的codex的规则
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDFilterRules
        {
            public int minlength;                   //最小条码长度
            public int maxlength;                   //最大条码长度
            public long minvalue;                   //最小值
            public long maxvalue;                   //最大值
            [MarshalAs(UnmanagedType.I1)]
            public bool caseSensitive;              //匹配大小写
            [MarshalAs(UnmanagedType.I1)]
            public bool onlyDigital;                //纯数字
            [MarshalAs(UnmanagedType.I1)]
            public bool onlyAlpha;                  //纯字母
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string startstring;              //以指定字符串开始
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string endstring;                //以指定字符串结束
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string constring;                //包含指定字符串
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string NotConstring;             //不包含指定字符串
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string wildcardstring;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string rule_str; //规则名称
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string regexPattern;
            public IDFilterMode filterMode;
        }
        public class IDFilterRulesCreate
        {
            public IDFilterRules createIDFilterRules()
            {
                IDFilterRules temIDFilterRules = new IDFilterRules();
                temIDFilterRules.minlength = 0;
                temIDFilterRules.maxlength = 0;
                temIDFilterRules.minvalue = 0;
                temIDFilterRules.maxvalue = 0;
                temIDFilterRules.startstring = "";
                temIDFilterRules.endstring = "";
                temIDFilterRules.constring = "";
                temIDFilterRules.NotConstring = "";
                temIDFilterRules.wildcardstring = "";
                temIDFilterRules.caseSensitive = true;
                temIDFilterRules.onlyDigital = false;
                temIDFilterRules.onlyAlpha = false;
                return temIDFilterRules;
            }
        }
        public enum IDSortOrder
        {
            ID_SORT_ORDER_ROI_ASC_C = 0,         // ROI å‡åº
            ID_SORT_ORDER_ROI_DESC_C,            // ROI é™åº
            ID_SORT_ORDER_CENTERX_ASC_C,         // ä¸­å¿ƒåæ ‡ X å‡åº
            ID_SORT_ORDER_CENTERX_DESC_C,        // ä¸­å¿ƒåæ ‡ X é™åº
            ID_SORT_ORDER_CENTERY_ASC_C,         // ä¸­å¿ƒåæ ‡ Y å‡åº
            ID_SORT_ORDER_CENTERY_DESC_C,        // ä¸­å¿ƒåæ ‡ Y é™åº
            ID_SORT_ORDER_CODEVALUE_ASC_C,       // ç ç»“果数值升序
            ID_SORT_ORDER_CODEVALUE_DESC_C       // ç ç»“果数值降序
        }
        /*
        *输出数据格式配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDataConfig
        {
            public IDSortOrder positionRules;
            [MarshalAs(UnmanagedType.I1)]
            public bool noreadStatus;                                              //无读补齐使能
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] noreadString;                                         //无读补齐
            [MarshalAs(UnmanagedType.I1)]
            public bool conditionEnable;                                           //输出条件使能
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] conditionInfo;                                            //输出条件
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] formatInfo;                                               //格式化信息
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] headInfo;                                             //头部插入
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] tailInfo;                                             //尾部插入
            [MarshalAs(UnmanagedType.I1)]
            public bool enterEnable;                                               //回车使能
            [MarshalAs(UnmanagedType.I1)]
            public bool lineFeedEnable;                                            //换行使能
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] falseInfo;                                                //条件false时输出
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] busyInfo;                                             //BUSY时输出
            [MarshalAs(UnmanagedType.I1)]
            public bool emptySendEnabel;                                           //发送空结果使能
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
            [MarshalAs(UnmanagedType.I1)]
            public bool enableInstantOutput;                                       //启用立即输出
            [MarshalAs(UnmanagedType.I1)]
            public bool enableOneByOne;                                            //启用OneByOne
            public uint oneByOnePeriod;                                    //OneByOne周期(ms),范围:20---10000
        }
        public class IDDataConfigCreate
        {
            public IDDataConfig createIDDataConfig()
            {
                IDDataConfig temIDDataConfig = new IDDataConfig();
                temIDDataConfig.noreadStatus = false;
                string noreadString = "NG";
                temIDDataConfig.noreadString = noreadString.ToCharArray();
                temIDDataConfig.conditionEnable = false;
                string formatInfo = "<Code*String>";
                temIDDataConfig.formatInfo = formatInfo.ToCharArray();
                string headInfo = "";
                temIDDataConfig.headInfo = headInfo.ToCharArray();
                string tailInfo = "";
                temIDDataConfig.tailInfo = tailInfo.ToCharArray();
                temIDDataConfig.enterEnable = false;
                temIDDataConfig.lineFeedEnable = false;
                string falseInfo = "";
                temIDDataConfig.falseInfo = falseInfo.ToCharArray();
                string busyInfo = "";
                temIDDataConfig.busyInfo = busyInfo.ToCharArray();
                temIDDataConfig.emptySendEnabel = false;
                temIDDataConfig.enableHEX = false;
                temIDDataConfig.enableInstantOutput = false;
                temIDDataConfig.enableOneByOne = false;
                temIDDataConfig.oneByOnePeriod = 100;
                return temIDDataConfig;
            }
        }
        /*
        *tcp服务器通讯配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDTcpServerCommunication
        {
            public uint port;
            [MarshalAs(UnmanagedType.I1)]
            public bool status;
        }
        public class IDTcpServerCommunicationCreate
        {
            public IDTcpServerCommunication createIDTcpServerCommunication()
            {
                IDTcpServerCommunication temIDTcpServerCommunication = new IDTcpServerCommunication();
                temIDTcpServerCommunication.status = false;
                temIDTcpServerCommunication.port = 1024;
                return temIDTcpServerCommunication;
            }
        }
        /*
        *TCP客户端通讯
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDTcpClientCommunication
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;
            public uint port;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string ipAdress;
            [MarshalAs(UnmanagedType.I1)]
            public bool heartBeatEnable;                                           //心跳使能
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string heartBeatCmd;                                          //心跳指令
            public uint heartBeatPeriod;                                   //心跳周期(ms)最小值50ms
            [MarshalAs(UnmanagedType.I1)]
            public bool enableHEX;                                                 //启用16进制
        }
        public class IDTcpClientCommunicationCreate
        {
            public IDTcpClientCommunication createIDTcpClientCommunication()
            {
                IDTcpClientCommunication temIDTcpClientCommunication = new IDTcpClientCommunication();
                temIDTcpClientCommunication.status = false;
                temIDTcpClientCommunication.port = 1024;
                temIDTcpClientCommunication.ipAdress = "127.0.0.1";
                temIDTcpClientCommunication.heartBeatEnable = false;
                temIDTcpClientCommunication.heartBeatCmd = "heartBeat";
                temIDTcpClientCommunication.heartBeatPeriod = 500;
                temIDTcpClientCommunication.enableHEX = false;
                return temIDTcpClientCommunication;
            }
        }
        /*
        *串口波特率
        */
        public enum IDBaud
        {
            ID_BAUDBR_110 = 0,
            ID_BAUDBR_300 = 1,
            ID_BAUDBR_600 = 2,
            ID_BAUDBR_1200 = 3,
            ID_BAUDBR_2400 = 4,
            ID_BAUDBR_4800 = 5,
            ID_BAUDBR_9600 = 6,
            ID_BAUDBR_14400,
            ID_BAUDBR_19200 = 8,
            ID_BAUDBR_38400 = 9,
            ID_BAUDBR_56000,
            ID_BAUDBR_57600 = 11,
            ID_BAUDBR_115200 = 12,
            ID_BAUDBR_128000,
            ID_BAUDBR_256000
        }
        /*
        *串口校验位
        */
        public enum IDParity
        {
            ID_PARITY_NONE = 0,                                               //无
            ID_PARITY_ODD,                                                    //奇校验
            ID_PARITY_EVEN                                                    //偶校验
        }
        /*
        *串口数据位
        */
        public enum IDDatabits
        {
            ID_DATABITS_5BIT = 0,
            ID_DATABITS_6BIT = 1,
            ID_DATABITS_7BIT = 2,
            ID_DATABITS_8BIT = 3
        }
        /*
        *串口停止位
        */
        public enum IDStopbits
        {
            ID_STOPBITS_ONE = 0,
            ID_STOPBITS_TWO = 1
        }
        /*
        *串口通讯配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDSerialPortCommunication
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;
            public IDBaud baudRate;                          //波特率
            public IDParity parity;                          //校验位
            public IDDatabits databits;                      //数据位
            public IDStopbits stopbits;                      //停止位
        }
        public class IDSerialPortCommunicationCreate
        {
            public IDSerialPortCommunication createIDSerialPortCommunication()
            {
                IDSerialPortCommunication temIDSerialPortCommunication = new IDSerialPortCommunication();
                temIDSerialPortCommunication.status = false;
                temIDSerialPortCommunication.baudRate = IDBaud.ID_BAUDBR_9600;
                temIDSerialPortCommunication.parity = IDParity.ID_PARITY_NONE;
                temIDSerialPortCommunication.databits = IDDatabits.ID_DATABITS_8BIT;
                temIDSerialPortCommunication.stopbits = IDStopbits.ID_STOPBITS_ONE;
                return temIDSerialPortCommunication;
            }
        }
        /*
        *键盘输出
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDKeyboardConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;
        }
        /*
        *EIP配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDEipConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool enable;
            [MarshalAs(UnmanagedType.I1)]
            public bool resultSwap;//结果交换
            public uint inputSize;//输入组件大小
            public uint outputSize;//输出组件大小
            public uint resultTimeout;//结果超时
        }
        public class IDEipConfigCreate
        {
            public IDEipConfig createIDEipConfig()
            {
                IDEipConfig temIDEipConfig = new IDEipConfig();
                temIDEipConfig.enable = false;
                temIDEipConfig.resultSwap = false;
                temIDEipConfig.inputSize = 200;
                temIDEipConfig.outputSize = 200;
                temIDEipConfig.resultTimeout = 1000;
                return temIDEipConfig;
            }
        }
        /*
        *modbus角色
        */
        public enum IDModbusRole
        {
            ID_MODBUS_ROLE_MASTER = 0,
            ID_MODBUS_ROLE_SLAVE = 1
        }
        /*
        *modbus连接类型
        */
        public enum IDModbusConnectionType
        {
            ID_MODBUSONNECTION_TCP = 0,
            ID_MODBUSONNECTIONOM_RTU
        }
        /*
        *modbus功能模块
        */
        public enum IDModbusFunction
        {
            ID_MODBUS_FUNCTIONOILS = 2,                                     //线圈
            ID_MODBUS_FUNCTION_HOLDING_REGISTERS = 4                          //保持寄存器
        }
        /*
        *modbus通讯配置,对应串口参数配置使用串口通讯中数据
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDModbusConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;                                //使能
            public IDModbusRole role;                            //角色,主站/从站
            public IDModbusConnectionType connectionType;        //连接类型
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string tcpServerIp;                           //做主站是连接从站IP
            public uint tcpPort;                       //tcp端口
            public uint timeout;                       //超时时间
            public uint retriesNum;                    //重试次数
            public uint serverAddress;                 //服务器地址
            public IDModbusFunction function;                    //数据功能模块
            public uint startAddress;                  //开始地址
            [MarshalAs(UnmanagedType.I1)]
            public bool resultSwap;                            //数据交换
            public uint resultTimeout;                 //结果超时
        }
        public class IDModbusConfigCreate
        {
            public IDModbusConfig createIDModbusConfig()
            {
                IDModbusConfig temIDModbusConfig = new IDModbusConfig();
                temIDModbusConfig.status = false;
                temIDModbusConfig.role = IDModbusRole.ID_MODBUS_ROLE_MASTER;
                temIDModbusConfig.connectionType = IDModbusConnectionType.ID_MODBUSONNECTION_TCP;
                temIDModbusConfig.tcpServerIp = "127.0.0.1";
                temIDModbusConfig.tcpPort = 512;
                temIDModbusConfig.timeout = 3000;
                temIDModbusConfig.retriesNum = 300;
                temIDModbusConfig.serverAddress = 0;
                temIDModbusConfig.function = IDModbusFunction.ID_MODBUS_FUNCTION_HOLDING_REGISTERS;
                temIDModbusConfig.startAddress = 0;
                temIDModbusConfig.resultSwap = false;
                temIDModbusConfig.resultTimeout = 1000;
                return temIDModbusConfig;
            }
        }
        /*
        *profinet通讯配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDProfinetConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool enable;                                //使能
            [MarshalAs(UnmanagedType.I1)]
            public bool serialModule;                          //串口模块
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string ipAddress;                           //配置名
            [MarshalAs(UnmanagedType.I1)]
            public bool resultSwap;                            //数据交换
            public uint resultSize;                            //结果大小(字节Bytes)
            public uint resultTimeout;                         //结果超时时间(ms)
        }
        public class IDProfinetConfigCreate
        {
            public IDProfinetConfig createIDProfinetConfig()
            {
                IDProfinetConfig temIDProfinetConfig = new IDProfinetConfig();
                temIDProfinetConfig.enable = false;
                temIDProfinetConfig.serialModule = false;
                temIDProfinetConfig.ipAddress = "127.0.0.1";
                temIDProfinetConfig.resultSwap = false;
                temIDProfinetConfig.resultSize = 200;
                temIDProfinetConfig.resultTimeout = 1000;
                return temIDProfinetConfig;
            }
        }
        /*
        *图像格式
        */
        public enum IDImageFormat
        {
            ID_IMAGE_FORMAT_JPG = 0,
            ID_IMAGE_FORMAT_PNG,
            ID_IMAGE_FORMAT_BMP,
            ID_IMAGE_FORMAT_RANDERING_JPG,                                    //渲染图JPG
            ID_IMAGE_FORMAT_RANDERING_PNG,                                    //渲染图PNG
            ID_IMAGE_FORMAT_RANDERING_BMP                                 //渲染图GMP
        }
        public enum IDFtpSendModel
        {
            ID_FTP_SEND_MODEL_NOT = 0,                                        //不保存
            ID_FTP_SEND_MODEL_NG,                                         //NG保存
            ID_FTP_SEND_MODEL_ALL,                                            //全保存
            ID_FTP_SEND_MODELONDITION                                       //指定条件
        }
        public enum IDFtpSaveStrategy
        {
            ID_FTP_SAVE_STRATEGY_ALL_C = 0,          // å…¨éƒ¨å¸§
            ID_FTP_SAVE_STRATEGY_LATEST_C,           // æœ€æ–°å¸§
            ID_FTP_SAVE_STRATEGY_SPECIFIC_INDEX_C,   // æŒ‡å®šå¸§
            ID_FTP_SAVE_STRATEGY_SPECIFIC_RANGE_C,   // æŒ‡å®šèŒƒå›´
        }
        public struct IDFTPSavePolicy
        {
            public IDFtpSaveStrategy saveStrategy;   // ä¿å­˜ç­–ç•¥
            public int frameIndex;                   // æŒ‡å®šå¸§å·ï¼ˆä»…当策略为保存指定帧时使用)
            public int rangeStartFrame;              // èµ·å§‹å¸§å·ï¼ˆä»…当策略为保存指定范围帧时使用)
            public int rangeEndFrame;                // ç»“束帧号(仅当策略为保存指定范围帧时使用)
        }
        /*
        *FTP配置信息
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDFtpConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;                                //使能
            [MarshalAs(UnmanagedType.I1)]
            public bool isLocal;                               //本地保存
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string iPAddress;                         //服务器IP
            public uint port;                          //服务器端口
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string username;                         //用户名
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string password;                         //密码
            public IDImageFormat imageformat;                    //图像格式
            public uint compressionRate;               //压缩率
            public uint maxImageCount;                 //最大保存张数
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string filePath;                         //图像路径
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string defaultFileName;                      //默认文件名
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string localSavePath;                        //本地保存路径
            [MarshalAs(UnmanagedType.I1)]
            public bool containsBarcodeDateEnable;             //包含时间戳
            [MarshalAs(UnmanagedType.I1)]
            public bool containsNumberEnable;                  //包含序号
            [MarshalAs(UnmanagedType.I1)]
            public bool containsFrameNumberEnable;
            [MarshalAs(UnmanagedType.I1)]
            public bool isDecodingResultNaming;                //包含结果
            [MarshalAs(UnmanagedType.I1)]
            public bool containsBarcodeIDEnable;               //ID命名
            [MarshalAs(UnmanagedType.I1)]
            public bool containsTriggerSequenceEnable;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string sendCondition;                        //发送条件
            public IDFTPSavePolicy savePolicy;
            [MarshalAs(UnmanagedType.I1)]
            public bool resultRenderingEnable;
            [MarshalAs(UnmanagedType.I1)]
            public bool boundingBoxRenderingEnable;
        }
        public class IDFtpConfigCreate
        {
            public IDFtpConfig createIDFtpConfig()
            {
                IDFtpConfig temIDFtpConfig = new IDFtpConfig();
                temIDFtpConfig.status = false;
                temIDFtpConfig.isLocal = true;
                temIDFtpConfig.iPAddress = "127.0.0.1";
                temIDFtpConfig.port = 2121;
                temIDFtpConfig.username = "ftp";
                temIDFtpConfig.password = "123456";
                temIDFtpConfig.imageformat = IDImageFormat.ID_IMAGE_FORMAT_BMP;
                temIDFtpConfig.compressionRate = 6;
                temIDFtpConfig.maxImageCount = 50;
                temIDFtpConfig.filePath = "";
                temIDFtpConfig.localSavePath = "/root/solution/NG_Image";
                temIDFtpConfig.defaultFileName = "image";
                temIDFtpConfig.containsBarcodeDateEnable = true;
                temIDFtpConfig.containsNumberEnable = false;
                temIDFtpConfig.isDecodingResultNaming = false;
                temIDFtpConfig.containsBarcodeIDEnable = false;
                temIDFtpConfig.sendCondition = "NG send";
                //temIDFtpConfig.sendModel = IDFtpSendModel.ID_FTP_SEND_MODEL_NG;
                return temIDFtpConfig;
            }
        }
        /*
        *监控HTTP配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDWebpageConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;                                //使能
            public int port;                                   //端口
            public int imageQuality;                           //图像质量
            [MarshalAs(UnmanagedType.I1)]
            public bool resultDispaly;                         //结果展示
            [MarshalAs(UnmanagedType.I1)]
            public bool imageDisplay;                          //图像展示
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string displayInfo;                         //显示信息
        }
        public class IDWebpageConfigCreate
        {
            public IDWebpageConfig createIDWebpageConfig()
            {
                IDWebpageConfig temIDWebpageConfig = new IDWebpageConfig();
                temIDWebpageConfig.status = false;
                temIDWebpageConfig.port = 8080;
                temIDWebpageConfig.imageQuality = 60;
                temIDWebpageConfig.resultDispaly = true;
                temIDWebpageConfig.imageDisplay = true;
                temIDWebpageConfig.displayInfo = "";
                return temIDWebpageConfig;
            }
        }
        /*
        * FINS通讯配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDFinsConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;                                //使能
            [MarshalAs(UnmanagedType.I1)]
            public bool isTcp;                                 //TCP/UDP
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string serverIp;                          //服务器IP
            public uint port;                          //服务器端口
            public uint startAddress;                  //开始地址
            [MarshalAs(UnmanagedType.I1)]
            public bool resultSwap;                            //数据交换
            public uint resultSize;                    //结果大小(字节Bytes)
            public uint resultTimeout;                 //结果超时(ms)
        }
        public class IDFinsConfigCreate
        {
            public IDFinsConfig createIDFinsConfig()
            {
                IDFinsConfig temIDFinsConfig = new IDFinsConfig();
                temIDFinsConfig.status = false;
                temIDFinsConfig.isTcp = true;
                temIDFinsConfig.serverIp = "0.0.0.0";
                temIDFinsConfig.port = 9600;
                temIDFinsConfig.startAddress = 0;
                temIDFinsConfig.resultSwap = false;
                temIDFinsConfig.resultSize = 200;
                temIDFinsConfig.resultTimeout = 1000;
                return temIDFinsConfig;
            }
        }
        /*
        *HTTP发送方式
        */
        public enum IDHttpMethod
        {
            ID_HTTP_METHOD_POST = 0,
            ID_HTTP_METHOD_GET
        }
        /*
        * Http通讯配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDHttpConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool status;
            public IDHttpMethod method;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string httpURL;
        }
        public class IDHttpConfigCreate
        {
            public IDHttpConfig createIDHttpConfig()
            {
                IDHttpConfig temIDHttpConfig = new IDHttpConfig();
                temIDHttpConfig.status = false;
                temIDHttpConfig.method = IDHttpMethod.ID_HTTP_METHOD_POST;
                temIDHttpConfig.httpURL = "";
                return temIDHttpConfig;
            }
        }
        /*
        *组网数据配置
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDNetworkingConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool networkingEnable;                              //组网启用
            [MarshalAs(UnmanagedType.I1)]
            public bool isMaster;                                      //是否是主机
            public uint communitionPort;                       //连接端口
            public uint masterTimeout;                         //主机超时
            public uint masterMaxConnectNumber;                //主机最大被连接数
            public uint slaveID;                               //从机ID
            [MarshalAs(UnmanagedType.I1)]
            public bool isTriggerSlave;                                //是否触发从机
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string masterIP;                                  //主机IP
            [MarshalAs(UnmanagedType.I1)]
            public bool isReceiveTrigger;                              //是否接受主机触发
            public uint triggerDelayTime;                      //触发延时
            [MarshalAs(UnmanagedType.I1)]
            public bool ConnectionStatus;                              //连接状态
            [MarshalAs(UnmanagedType.I1)]
            public bool deviceRoiPlaceholder;                          //设备ROI补齐占位
        }
        public class IDNetworkingConfigCreate
        {
            public IDNetworkingConfig createIDNetworkingConfig()
            {
                IDNetworkingConfig temIDNetworkingConfig = new IDNetworkingConfig();
                temIDNetworkingConfig.networkingEnable = false;
                temIDNetworkingConfig.isMaster = true;
                temIDNetworkingConfig.communitionPort = 5128;
                temIDNetworkingConfig.masterTimeout = 1500;
                temIDNetworkingConfig.masterMaxConnectNumber = 8;
                temIDNetworkingConfig.slaveID = 1;
                temIDNetworkingConfig.isTriggerSlave = false;
                temIDNetworkingConfig.masterIP = "127.0.0.1";
                temIDNetworkingConfig.isReceiveTrigger = false;
                temIDNetworkingConfig.triggerDelayTime = 1;
                temIDNetworkingConfig.ConnectionStatus = false;
                temIDNetworkingConfig.deviceRoiPlaceholder = false;
                return temIDNetworkingConfig;
            }
        }
        //条码类型枚举
        public enum IDCodeType
        {
            IDODETYPE_UNKNOWN = 0x0,
            IDODETYPEODE39 = 0x1,
            IDODETYPEODE128 = 0x2,
            IDODETYPE_EAN8 = 0x4,
            IDODETYPE_EAN13 = 0x8,
            IDODETYPE_UPC_A = 0x10,
            IDODETYPE_UPC_E = 0x20,
            IDODETYPEODE93 = 0x40,
            IDODETYPE_ITF = 0x80,
            IDODETYPE_GS1_128 = 0x100,
            IDODETYPE_GS1_DATABAR_EXPANDED = 0x200,
            IDODETYPE_GS1_DATABAR = 0x400,
            IDODETYPE_GS1_DATABAR_STACKED = 0x600,
            IDODETYPE_GS1_DATABAR_EXPANDED_STACKED = 0x800,
            IDODETYPE_GS1_DATABAR_LINITED = 0x1000,
            IDODETYPE_PHARMACODE = 0x2000,
            IDODETYPE_MSI = 0x4000,
            IDODETYPE_PLESSEY = 0x8000,
            IDODETYPEODEBAR = 0x10000,
            IDODETYPE_INT2OF5 = 0x20000,
            IDODETYPE_STD2OF5 = 0x40000,
            IDODETYPE_MTX2OF5 = 0x80000,
            IDODETYPE_DATAMATRIX = 0x04000000,
            IDODETYPE_QRCODE = 0x08000000,
            IDODETYPE_PDF417 = 0x010000000,
            IDODETYPE_MICROQR = 0x020000000,
            IDODETYPE_AZTEC = 0x040000000,
            ID_CODETYPE_VERICODEC = 0x070000000
        }
        /*
        *MC通信PLC型号
        */
        public enum IDMcBrandModel
        {
            ID_MC_BRAND_L_C = 0,
            ID_MC_BRAND_Q_C = 1,
            ID_MC_BRAND_R_C = 2,
            ID_MC_BRAND_A_C = 4,
            ID_MC_BRAND_FX3U_C = 5,
            ID_MC_BRAND_FX5U_C = 6
        }
        /*
        *MC通信数据格式
        */
        public enum IDMcDataFormat
        {
            ID_MC_DATA_BIN_C = 0,
            ID_MC_DATA_ASCII_C
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDeviceInfo
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string networkIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string networkMask;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string networkGateway;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string networkAdapterFriendName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string networkMac;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string cameraIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraNetMask;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraGateWay;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraMac;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraSN;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraModel;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraManufucturer;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraSoftwareVersion;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraFirmwareVersion;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraAlias;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraType;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string deviceFullType;                       //设备完整型号
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string cameraChipType;                       //相机芯片类型
            public uint cameraImageWidth;                       //相机图像宽度
            public uint cameraImageHeight;                      //相机图像高度
            [MarshalAs(UnmanagedType.I1)]
            public bool isRTDevice;                             //是否为实时设备
            [MarshalAs(UnmanagedType.I1)]
            public bool globalExposure;                         //全局曝光
            [MarshalAs(UnmanagedType.I1)]
            public bool autoFocus;                              //自动对焦
            public uint lightChannelNum;                        //光源通道数
            public uint diNum;                                  //DI引脚数
            public uint doNum;                                  //DO引脚数
            [MarshalAs(UnmanagedType.I1)]
            public bool blueToothInterface;                     //蓝牙设备
            [MarshalAs(UnmanagedType.I1)]
            public bool serialPortInterface;                    //串口接口
            [MarshalAs(UnmanagedType.I1)]
            public bool usbInterface;                           //USB接口
            [MarshalAs(UnmanagedType.I1)]
            public bool wirelessInterface;                      //WIFI接口
            [MarshalAs(UnmanagedType.I1)]
            public bool ethernetInterface;                      //以太网接口
            [MarshalAs(UnmanagedType.I1)]
            public bool busyState;                                //忙碌状态
        }
        //硬件信息通用节点结构体
        public struct IDNodeParam
        {
            public float maxValue;
            public float minValue;
            public float value;
            public int type;
        }
        public IDNodeParam createIDNodeParam()
        {
            IDNodeParam param;
            param.maxValue = 0;
            param.minValue = 0;
            param.value = 0;
            param.type = 0;
            return param;
        }
        //硬件信息结构体
        public struct IDDeviceHarewareParams
        {
            public int imageWidth;
            public int imageHight;
            public IDNodeParam exposureStep;
            public IDNodeParam exposure;
            public IDNodeParam gamma;
            public IDNodeParam gain;
            public IDNodeParam illuminanatInerval;
            public IDNodeParam focusingLocation;
            public IDNodeParam DICount;
            public IDNodeParam DOCount;
            public IDNodeParam isOpenSightingDevice;
        }
        public IDDeviceHarewareParams createID_DEVICE_HARDWARE_PARAMS()
        {
            IDDeviceHarewareParams HarewareParams;
            HarewareParams.imageWidth = 0;
            HarewareParams.imageHight = 0;
            HarewareParams.exposureStep = createIDNodeParam();
            HarewareParams.exposure = createIDNodeParam();
            HarewareParams.gamma = createIDNodeParam();
            HarewareParams.gain = createIDNodeParam();
            HarewareParams.illuminanatInerval = createIDNodeParam();
            HarewareParams.focusingLocation = createIDNodeParam();
            HarewareParams.DICount = createIDNodeParam();
            HarewareParams.DOCount = createIDNodeParam();
            HarewareParams.isOpenSightingDevice = createIDNodeParam();
            return HarewareParams;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        //点类型结构体
        public struct IDPoint
        {
            public double x;
            public double y;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDROIInfo
        {
            public IDPoint topLeftPoint;
            public IDPoint bottomRightPoint;
            public IDCodeType codeType;
            public uint roiIndex;
            public uint codeNum;
            public uint timeout;
        }
        public class IDDeviceROI
        {
            // åˆ›å»ºIDROIInfo的方法
            public IDROIInfo CreateIDROIInfo()
            {
                IDROIInfo temROIInfo = new IDROIInfo
                {
                    codeNum = 1,
                    timeout = 500,
                };
                return temROIInfo;
            }
        }
        //质量评估输出结果
        //ISO IEC 15416-2016   ä¸€ç»´ç 
        public struct IDQuality15416
        {
            public float overallQuality;    //总质量
            public float decode;            //可解码性
            public float edgeDetermination; //边缘确定
            public float symbolContrast;    //字符对比度
            public float minReflectance;    //最小反射率
            public float minEdgeContrast;   //最小边缘对比度
            public float modulation;        //调制
            public float quietZone;         //静止区
            public float decodability;      //解码容错度
            public float defects;           //缺陷
        }
        //ISO_IEC15415-2011 QR
        public struct IDQualityQR15415
        {
            public float overallQuality;        //总质量
            public float decode;                //可解码性
            public float symbolContrast;        //字符对比度
            public float fixedPatternDamage;    //固定模块损坏
            public float modulation;            //调制
            public float reflectanceMargin;     //反射裕度
            public float unusedErrCorrection;   //未使用纠错码
            public float axialNonuniformity;    //轴向不均匀性
            public float gridNonuniformity;     //网格不均匀性
            public float formatInformation;     //格式信息
            public float versionInformation;    //版本信息
            public float contrastUniformity;
            public float printGrowth;
            public float aperture;
        }
        //DM 15415码质量
        public struct IDQualityDM15415
        {
            public float overallQuality;        //总质量
            public float decode;                //可解码性
            public float symbolContrast;        //字符对比度
            public float fixedPatternDamage;    //固定模块损坏
            public float modulation;            //调制
            public float reflectanceMargin;     //反射裕度
            public float unusedErrCorrection;   //未使用纠错码
            public float axialNonuniformity;    //轴向不均匀性
            public float gridNonuniformity;     //网格不均匀性
            public float contrastUniformity;
            public float printGrowth;
            public float aperture;
        }
        //ISO IEC TR 29158-2011(AIM-DPM-1-2006)
        public struct IDQualityDM29518
        {
            public float overallQuality;        //总质量
            public float decode;                //可解码性
            public float cellContrast;          //单元对比度
            public float cellModulation;        //单元调制
            public float reflectanceMargin;     //反射裕度
            public float fixedPatternDamage;    //固定模块损坏
            public float axialNonuniformity;    //轴向不均匀性
            public float gridNonuniformity;     //网格不均匀性
            public float unusedErrCorrection;   //未使用纠错码
            public float contrastUniformity;
            public float meanLight;
            public float printGrowth;
            public float aperture;
        }
        //QR 29158结构体
        public struct IDQualityQR29518
        {
            public float overallQuality;        //总质量
            public float decode;                //可解码性
            public float cellContrast;          //单元对比度
            public float cellModulation;        //单元调制
            public float reflectanceMargin;     //反射裕度
            public float fixedPatternDamage;    //固定模块损坏
            public float axialNonuniformity;    //轴向不均匀性
            public float gridNonuniformity;     //网格不均匀性
            public float unusedErrCorrection;   //未使用纠错码
            public float formatInformation;     //格式信息
            public float versionInformation;    //版本信息
            public float contrastUniformity;
            public float meanLight;
            public float printGrowth;
            public float aperture;
        }
        //PDF417 15415当前算法暂不支持
        public struct IDQualityPDF417_15415
        {
            public float overallQuality;
            public float decode;
            public float symbolContrast;
            public float fixPattern;
            public float modulation;
            public float unusedErrCorrection;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float startStopPattern;
            public float codewordYield;
            public float defects;
            public float aperture;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 36)]
        public struct IDDecodeInfo
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool decodeStatus;                           //解码结果状态OK/NG
            public float runtime;                               //解码耗时
            public uint hardParamIndex;
            public uint successCount;                           //解码成功数
            public uint failedCount;                            //解码失败数
            public uint decodeCount;                            //总解码数
            public double decodeRate;                           //解码率
            public uint IDDecodeROIInfoLength;                  //ROI的个数
        }
        //当前ROI解码结果
        public struct IDDecodeROIInfo
        {
            public int roiIndex;                                        //第几个ROI
            public int decodeReusltLength;                              //目前只会有一个码制,结果为1,后续保留可扩展性
        }
        //当前解码类型,只有一个码制有数据
        public struct IDDecodeResult
        {
            public int conbination;
            public int dmResultsLength;
            public int qrResultsLength;
            public int pdf417ResultsLength;
            public int barcodeResultsLength;
        }
        //DM解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDMCodeResult
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                   // å½“前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] subType;               // å­ç±»åž‹
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;            // è§£ç ç»“æžœ
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;              // æžæ€§
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] shape;                 // æ ·å¼
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                // é•œåƒ
            public int contrast;                 // å¯¹æ¯”度
            public float moduleSize;
            public float orientation;
        }
        //QR解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDQRCodeResult
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                      //当前结果解码状态
                                                                    //IDCodeType codeType;                            //条码类型
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                                //解码结果
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] subType;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] errorLevel;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                                    //镜像
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] version;                                  //版本信息
            public int contrast;
            public float moduleSize;
            public float orientation;                                //角度
        }
        //PDF417解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDPDF417CodeResult
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                        //当前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                                //解码结果
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] subType;                                    //子类型
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;                                //极性
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                                   //镜像
            public int symbolRows;
            public int symbolCols;
            public int errorLevel;
            public int contrast;
            public float moduleHeight;
            public float pixelPerModule;                            //moduleWidth
            public float moduleRatio;
            public float orientation;                               //角度
            //IDQualityPDF417_15415 quality15415;
        }
        //barcode解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDBarCodeResult
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                        //当前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                               //解码结果
            public float orientation;                               //角度
            public float pixelPerModule;
        }
        public unsafe struct StringList
        {
            public char* items;
            public int size;
            public int capacity;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDQRCodeParam
        {
            public int modeType;                //模式
            public int polarity;                //极性
            public int version;                 //版本
            public int sampleRate;              //降采样
            public int edgeThreshod;            //阈值
            public int mirror;                  //镜像
            public int codeNum;                 //码数
            public int timeOut;                 //算法超时
            [MarshalAs(UnmanagedType.I1)]
            public bool outCandidate;
            [MarshalAs(UnmanagedType.I1)]
            public bool outModuleArray;
            [MarshalAs(UnmanagedType.I1)]
            public bool enable15415;            //15415码评级
            [MarshalAs(UnmanagedType.I1)]
            public bool enable29158;            //29158码评级
        }
        public class IDQRCodeParamCreate
        {
            public IDQRCodeParam create()
            {
                IDQRCodeParam idQRCodeParam;
                idQRCodeParam.modeType = 0; //模式, 0,1,2
                idQRCodeParam.polarity = 0; //极性 0,1,2
                idQRCodeParam.version = 0; //版本 0~40
                idQRCodeParam.sampleRate = 0;//降采样倍率 0~6
                idQRCodeParam.edgeThreshod = 30; //边缘阈值 1~255
                idQRCodeParam.mirror = 0; //镜像, 0,1,2
                idQRCodeParam.codeNum = 0; //条码个数 å¤§äºŽç­‰äºŽ1
                idQRCodeParam.timeOut = 500; //超时 å¤§äºŽç­‰äºŽ0
                idQRCodeParam.outCandidate = false;//输出候选区
                idQRCodeParam.outModuleArray = false; //输出模块信息
                idQRCodeParam.enable15415 = false;
                idQRCodeParam.enable29158 = false;
                return idQRCodeParam;
            }
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDBarCodeParam
        {
            public uint Type;
            public int polarity;
            public int sampleRate;
            public int minContrast;
            public int decodeDirection;
            public int codeNum;
            public int timeOut;
            public int code39Check;
            public int ITFCheck;
            public int CodaBarCheck;
            public int sendStartEnd;
            [MarshalAs(UnmanagedType.I1)]
            public bool enable15416;
            public int decodeThreshod;
        }
        public class IDBarCodeParamCreate
        {
            public IDBarCodeParam create()
            {
                IDBarCodeParam tmpIDBarCodeParam;
                tmpIDBarCodeParam.Type = 0;//条码类型  æŒ‰ä½å–值
                tmpIDBarCodeParam.polarity = 0;//极性        0,1,2
                tmpIDBarCodeParam.sampleRate = 0;//降采样 0~2
                tmpIDBarCodeParam.minContrast = 2; //取值范围0到3,0:表示极低对比度,1:低对比度,2:中等对比度,3:高对比度
                tmpIDBarCodeParam.decodeDirection = 0;//解码方向 Pharmacode专用,取值:0:从左到右,1:从右到左,2:从上到下, 3:从下到上
                tmpIDBarCodeParam.codeNum = 1; //条码个数 å¤§äºŽç­‰äºŽ1
                tmpIDBarCodeParam.timeOut = 500; //超时 å¤§äºŽç­‰äºŽ0
                tmpIDBarCodeParam.code39Check = 0;
                tmpIDBarCodeParam.ITFCheck = 0;
                tmpIDBarCodeParam.CodaBarCheck = 0;//0:不校验,1:校验不发送,2:校验发送
                tmpIDBarCodeParam.sendStartEnd = 0;//是否发送起始终止符,CodaBar专用
                tmpIDBarCodeParam.enable15416 = false;
                tmpIDBarCodeParam.decodeThreshod = 0;
                return tmpIDBarCodeParam;
            }
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDMCodeParam
        {
            public int polarity;            //极性
            public int style;               //开始位置
            public int sampleRate;          //降采样
            public int minContrast;         //样式
            public int mirror;              //镜像
            public int codeNum;             //码数目
            public int timeOut;             //算法超时
            [MarshalAs(UnmanagedType.I1)]
            public bool outCandidate;
            [MarshalAs(UnmanagedType.I1)]
            public bool outModuleArray;
            [MarshalAs(UnmanagedType.I1)]
            public bool enable15415;        //15415算法评级
            [MarshalAs(UnmanagedType.I1)]
            public bool enable29158;        //29158算法评级
            [MarshalAs(UnmanagedType.I1)]
            public bool enableAS9132;       //AS9132算法评级
        }
        public class IDDMCodeParamCreate
        {
            public IDDMCodeParam create()
            {
                IDDMCodeParam tmpIDDMCodeParam;
                tmpIDDMCodeParam.polarity = 0;//极性    0,1,2
                tmpIDDMCodeParam.style = -1; //样式 -3,-2,-1,0....29
                tmpIDDMCodeParam.sampleRate = 0; //降采样 0~5
                tmpIDDMCodeParam.minContrast = 30; //最小对比度    1~255
                tmpIDDMCodeParam.mirror = 0; //镜像, 0,1,2
                tmpIDDMCodeParam.codeNum = 0; //条码个数 å¤§äºŽç­‰äºŽ1
                tmpIDDMCodeParam.timeOut = 500; //超时
                tmpIDDMCodeParam.outCandidate = false;//输出候选区
                tmpIDDMCodeParam.outModuleArray = false; //输出模块信息
                tmpIDDMCodeParam.enable15415 = false;
                tmpIDDMCodeParam.enable29158 = false;
                tmpIDDMCodeParam.enableAS9132 = false;
                return tmpIDDMCodeParam;
            }
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDPDF417CodeParam
        {
            public int polarity;                //极性
            public int pdfRows;                 //
            public int pdfCols;                 //
            public int mirror;                  //镜像
            public int codeNum;                 //码数目
            public int timeOut;                 //算法超时
            [MarshalAs(UnmanagedType.I1)]
            public bool outCandidate;
            [MarshalAs(UnmanagedType.I1)]
            public bool enable15415;            //15415算法评级
        }
        public class IDPDF417CodeParamCreate
        {
            public IDPDF417CodeParam create()
            {
                IDPDF417CodeParam tmpIDPDF417CodeParam_C;
                tmpIDPDF417CodeParam_C.polarity = 0;//极性    0,1,2
                tmpIDPDF417CodeParam_C.pdfRows = 0; //行数:0、[3, 90], å…¶ä¸­0表示自动
                tmpIDPDF417CodeParam_C.pdfCols = 0; //列数:[0, 30], å…¶ä¸­0表示自动
                tmpIDPDF417CodeParam_C.mirror = 0; //镜像, 0,1,2,暂不支持
                tmpIDPDF417CodeParam_C.codeNum = 0; //条码个数 å¤§äºŽç­‰äºŽ1
                tmpIDPDF417CodeParam_C.timeOut = 500; //超时
                tmpIDPDF417CodeParam_C.outCandidate = false;//输出候选区,暂不支持
                tmpIDPDF417CodeParam_C.enable15415 = false;//暂不支持
                return tmpIDPDF417CodeParam_C;
            }
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDMicroQRParam
        {
            public int polarity;     // æžæ€§
            public int version;      // ç‰ˆæœ¬
            public int mirror;       // é•œåƒ
            public int codeNum;      // æ¡ç ä¸ªæ•°ï¼Œå¿…须大于等于1
            public int timeOut;      // è¶…时时间,必须大于等于0
            public int outCandidate; // è¾“出候选项
            public int outModuleArray; // è¾“出模块数组
            [MarshalAs(UnmanagedType.I1)]
            public bool enable15415;  // æ˜¯å¦å¯ç”¨15415标准
            [MarshalAs(UnmanagedType.I1)]
            public bool enable29158;  // æ˜¯å¦å¯ç”¨29158标准
        }
        public class IDMicroQRParamCreate
        {
            public IDMicroQRParam create()
            {
                IDMicroQRParam tmpIDMicroQRParam_C;
                tmpIDMicroQRParam_C.polarity = 0;                // åˆå§‹åŒ–为默认极性
                tmpIDMicroQRParam_C.version = 0;                 // åˆå§‹åŒ–为默认版本
                tmpIDMicroQRParam_C.mirror = 0;                  // åˆå§‹åŒ–为默认无镜像
                tmpIDMicroQRParam_C.codeNum = 1;                 // æ¡ç ä¸ªæ•°ï¼Œé»˜è®¤è‡³å°‘为1
                tmpIDMicroQRParam_C.timeOut = 500;               // è¶…时,默认500ms
                tmpIDMicroQRParam_C.outCandidate = 0;            // é»˜è®¤æ— å€™é€‰é¡¹
                tmpIDMicroQRParam_C.outModuleArray = 0;          // é»˜è®¤æ— æ¨¡å—数组
                tmpIDMicroQRParam_C.enable15415 = false;             // é»˜è®¤ä¸å¯ç”¨15415标准
                tmpIDMicroQRParam_C.enable29158 = false;             // é»˜è®¤ä¸å¯ç”¨29158标准
                return tmpIDMicroQRParam_C;
            }
        }
        // æ¡ç ç±»åˆ«
        public enum IDCodeCategory
        {
            ID_CATEGORY_UNKNOWN_C = 0x0,             // æœªçŸ¥ç±»åž‹
            ID_CATEGORY_LINEAR_BARCODE_C = 0x1,      // ä¸€ç»´æ¡ç  (Linear Barcode)
            ID_CATEGORY_QR_CODE_C = 0x2,             // QR äºŒç»´ç  (QR Code)
            ID_CATEGORY_MICROQR_CODE_C = 0x3,        // MicroQR äºŒç»´ç  (MicroQR)
            ID_CATEGORY_DATAMATRIX_CODE_C = 0x4,     // Data Matrix äºŒç»´ç  (Data Matrix Code)
            ID_CATEGORY_STACKED_BARCODE_C = 0x8      // å †å æ¡ç  (Stacked Barcode)
        }
        public enum IDGeneralParamsType
        {
            GP_UNDEFINED_C = 0,
            GP_NUM_C,
            GP_STRING_C,
            GP_BOOL_C,
            GP_POINT_C,
            GP_NUM_ARRAY_C,
            GP_STRING_ARRAY_C,
            GP_BOOL_ARRAY_C,
            GP_POINT_ARRAY_C,
            GP_UCHAR_C,
            GP_FLOAT_C,
            GP_USHORT_C,
            GP_UINT_C,
            GP_ULONG_C,
            GP_SHORT_C,
            GP_INT_C,
            GP_FLAGS_C,
            GP_LONG_C
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDImageROI
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
            public char[] name;
            public IDPoint topLeftPoint;
            public IDPoint bottomRightPoint;
            public IDCodeType codeType;
            public uint mode;
            public uint id;
            public uint roiIndex;
            public uint codeNum;
            public uint timeout;
        }
        public class IDImageROICreate
        {
            public IDImageROI create()
            {
                IDImageROI temIDImageROI_C = new IDImageROI();
                temIDImageROI_C.codeNum = 1;
                temIDImageROI_C.timeout = 500;
                return temIDImageROI_C;
            }
        }
        //图像参数
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDSolutionImage
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool autoExposureEnabled;                   // è‡ªåŠ¨æ›å…‰ä½¿èƒ½
            [MarshalAs(UnmanagedType.I1)]
            public bool autoGainEnabled;                       // è‡ªåŠ¨å¢žç›Šä½¿èƒ½
            public int IDSolutionImageParamsLength;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDSolutionImageParams
        {
            public int paramIndex;
            public double exposure;
            public int gain;
            public double gamma;
            public int focusLocation;
            public int rowCount;                                   //行数
            public int rowFrequence;                               //行频(hz)
            public int illuminantsCount;   //光源通道参数
        }
        //光源通道参数
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDSolutionImageIlluminant
        {
            public int channel;
            [MarshalAs(UnmanagedType.I1)]
            public bool enable;
            public int brightness;
        }
        public enum IDDiInputSource
        {
            INPUT_SOURCE_TRIGGER_C = 0,          // è§¦å‘模式
            INPUT_SOURCE_PRESET_COMPARE_C = 1,   // å¯¹æ¯”预设输入模式
            INPUT_SOURCE_DISABLE = 2             // ç¦ç”¨
        }
        /*
        * IO输入参数
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDIParams
        {
            public IDDiInputSource inputSource;       // è§¦å‘类型,取值:0:触发,1:对比预设输入
            public uint pin;                    // DI对应的引脚号
        }
        public class IDDIParamsCreate
        {
            public IDDIParams createSTRUCT_ID_DI_PARAMS()
            {
                IDDIParams tmpIDDIParams_C;
                tmpIDDIParams_C.inputSource = IDDiInputSource.INPUT_SOURCE_TRIGGER_C;
                tmpIDDIParams_C.pin = 0;
                return tmpIDDIParams_C;
            }
        }
        /*
        *IO事件源
        */
        public enum IDDoEventSource
        {
            EVENT_SOURCE_OFF_C = 0,                // æ— 
            EVENT_SOURCE_ACQUISITION_START_C,      // é‡‡å›¾å¼€å§‹
            EVENT_SOURCE_ACQUISITION_STOP_C,       // é‡‡å›¾ç»“束
            EVENT_SOURCE_EXPOSURE_START_C,         // æ›å…‰å¼€å§‹
            EVENT_SOURCE_NOCODE_READ_C,            // è§£ç  NG æ—¶
            EVENT_SOURCE_READ_SUCCESS_C,           // è§£ç  OK æ—¶
            EVENT_SOURCE_CONDITION_SELECTED_C,     // æ¡ä»¶é€‰æ‹©
            EVENT_SOURCE_DATA_COMPARE_SUCCESS_C,   // æ•°æ®å¯¹æ¯”成功
            EVENT_SOURCE_DATA_COMPARE_FAIL_C       // æ•°æ®å¯¹æ¯”失败
        }
        /*
        * IO输出参数
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDDOParams
        {
            public uint status;            // DO状态(启用或禁用)
            public uint pin;               // DO对应的引脚号
            public uint doModel;           // è¾“出电平
            public uint durationTime;      // æŒç»­æ—¶é—´ï¼ˆms)
            public IDDoEventSource doSource;       // äº‹ä»¶æºï¼ˆæ¥è‡ªå…¶ä»–模块)
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string condition;
        }
        public class IDDOParamsCreate
        {
            public IDDOParams create()
            {
                IDDOParams tmpIDDOParams_C;
                tmpIDDOParams_C.status = 0;
                tmpIDDOParams_C.pin = 0;
                tmpIDDOParams_C.doModel = 0;
                tmpIDDOParams_C.durationTime = 0;
                tmpIDDOParams_C.doSource = IDDoEventSource.EVENT_SOURCE_OFF_C;
                tmpIDDOParams_C.condition = "";
                return tmpIDDOParams_C;
            }
        }
        /*
        * mcConfig é…ç½®
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDMcConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool isEnabled;                        // ä½¿èƒ½
            [MarshalAs(UnmanagedType.I1)]
            public bool isUdpCommunication;               // UDP é€šä¿¡
            public int brandModel;                        // å“ç‰Œåž‹å·
            public int dataFormat;                        // æ•°æ®æ ¼å¼
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string ipAddress;                 // IP åœ°å€
            public int port;                              // ç«¯å£
            public int startAddress;                      // å¼€å§‹åœ°å€
            [MarshalAs(UnmanagedType.I1)]
            public bool isResultSwapped;                  // ç»“果交换
            public uint resultSizeBytes;          // ç»“果大小(字节)
            public uint resultTimeoutMs;          // ç»“果超时(毫秒)
        }
        public class IDMcConfigCreate
        {
            public IDMcConfig create()
            {
                IDMcConfig tmpIDMcConfig_C;
                tmpIDMcConfig_C.isEnabled = false;
                tmpIDMcConfig_C.isUdpCommunication = false;
                tmpIDMcConfig_C.brandModel = 0;
                tmpIDMcConfig_C.dataFormat = 0;
                tmpIDMcConfig_C.ipAddress = "";
                tmpIDMcConfig_C.port = 0;
                tmpIDMcConfig_C.startAddress = 0;
                tmpIDMcConfig_C.isResultSwapped = false;
                tmpIDMcConfig_C.resultSizeBytes = 0;
                tmpIDMcConfig_C.resultTimeoutMs = 0;
                return tmpIDMcConfig_C;
            }
        }
        /*
        * udpConfig é…ç½®
        */
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDUdpConfig
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool isEnabled;                        // ä½¿èƒ½
            public int port;                              // ç«¯å£
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string ipAddress;                 // IP åœ°å€
        }
        public class IDUdpConfigCreate
        {
            public IDUdpConfig create()
            {
                IDUdpConfig tmpIDUdpConfig_C;
                tmpIDUdpConfig_C.isEnabled = false;
                tmpIDUdpConfig_C.port = 0;
                tmpIDUdpConfig_C.ipAddress = "";
                return tmpIDUdpConfig_C;
            }
        }
        public enum IDGeneralParamsName
        {
            ID_PARAM_FILTER_PREVENT_DUPLICATE = 0,                      //重复过滤
            ID_PARAM_FILTER_PREVENT_DUPLICATE_ENABLE,                   //重复过滤使能
            ID_PARAM_FILTER_HISTORY_TIMES,                              //历史过滤
            ID_PARAM_FILTER_HISTORY_TIMES_ENABLE,                       //历史过滤使能
            ID_PARAM_FILTER_READ_THRESHOLD,                             //阈值过滤
            ID_PARAM_FILTER_READ_THRESHOLD_ENABLE,                      //阈值过滤使能
            ID_PARAM_FILTER_REMOVE_DUPLICATE_ENABLE,                    //去除重复使能
            ID_PARAM_FILTER_FRAME_DUPLICATE_ENABLE,                     //逐帧过滤使能
            ID_PARAM_FILTER_ANGLE_INIT,                                 //角度初始值
            ID_PARAM_FILTER_ANGLE_OFFSET,                               //角度偏移值
            ID_PARAM_FILTER_ANGLE_ENABLE,                               //角度使能
            ID_PARAM_COMPARE_CONTROL_ENABLE,                            //比对使能
            ID_PARAM_COMPARE_RULE,                                      //比对规则
            ID_PARAM_COMPARE_PRESET_DATA,                               //预设数据
            ID_PARAM_COMPARE_START_POSITION,                            //起始位置
            ID_PARAM_COMPARE_DIGITS,                                    //比对数
            ID_PARAM_DATACONFIG_NOREAD,                                 //无读补齐配置
            ID_PARAM_DATACONFIG_NOREAD_ENABLE,                          //无读补齐使能
            ID_PARAM_DATACONFIG_CONDITION,                              //输出条件
            ID_PARAM_DATACONFIG_CONDITION_ENABLE,                       //输出条件使能
            ID_PARAM_DATACONFIG_FORMAT_INFO,                            //数据处理格式化内容
            ID_PARAM_DATACONFIG_HEAD_INFO,                              //起始插入
            ID_PARAM_DATACONFIG_TAIL_INFO,                              //结尾插入
            ID_PARAM_DATACONFIG_ENTER_ENABLE,                           //结束回车符使能
            ID_PARAM_DATACONFIG_LINEFEED_ENABLE,                        //结束换行符使能
            ID_PARAM_DATACONFIG_FALSE_INFO,                             //输出条件不满足时输出
            ID_PARAM_DATACONFIG_HEX_ENABLE,                             //输出16进制使能
            ID_PARAM_DATACONFIG_EMPTY_SEND_ENABLE,                      //发送空结果使能
            ID_PARAM_DATACONFIG_INSTANT_OUTPUT_ENABLE,                  //立即输出使能
            ID_PARAM_DATACONFIG_POSITION_RULES,                         //排序规则
            ID_PARAM_DATACONFIG_ONE_BY_ONE_ENABLE,                      //OneByOne使能
            ID_PARAM_DATACONFIG_ONE_BY_ONE_PERIOD,                      //OneByOne周期
            ID_PARAM_QUALITY_BARCODE_15416,                             //条形码质量 (15416 æ ‡å‡†)
            ID_PARAM_QUALITY_QR_CODE_15415,                             //二维码质量 (15415 æ ‡å‡†)
            ID_PARAM_QUALITY_QR_CODE_29158,                             //二维码质量 (29158 æ ‡å‡†)
            ID_PARAM_QUALITY_DATAMATRIX_15415,                          //数据矩阵质量 (15415 æ ‡å‡†)
            ID_PARAM_QUALITY_DATAMATRIX_29158,                          //数据矩阵质量 (29158 æ ‡å‡†)
            ID_PARAM_QUALITY_DATAMATRIX_9132,                           //数据矩阵质量 (9132 æ ‡å‡†)
            ID_PARAM_QUALITY_DATAMATRIX_T100701,                        //数据矩阵质量 (T100701 æ ‡å‡†)
            ID_PARAM_QUALITY_PDF417_15415,                              //PDF417 æ¡ç è´¨é‡ (15415 æ ‡å‡†)
            ID_PARAM_QUALITY_MODE,                                      //条码刻印验证模式,取值:0:标准模式,1:OPT模式
            ID_PARAM_TRIGGER_STATUS,                                    //触发状态
            ID_PARAM_TRIGGER_DELAY,                                     //触发延时
            ID_PARAM_TRIGGER_MODLE,                                     //触发模式
            ID_PARAM_TRIGGER_DURATION,                                  //触发持续时间
            ID_PARAM_TRIGGER_CODE_NUM,                                  //触发解码数
            ID_PARAM_TRIGGER_SOURCE,                                    //触发源
            ID_PARAM_TRIGGER_STATISTIC_BY_NUM_ENABLE,                   //码数目统计使能
            ID_PARAM_TRIGGER_CONDITION_MODE,                            //按时间/帧触发
            ID_PARAM_TRIGGER_TRIGGER_INTERVAL,                          //自动触发间隔
            ID_PARAM_TRIGGER_CACHE_ENABLE,                              //触发缓存使能
            ID_PARAM_TRIGGER_ENABLE_CODE_NUM_RESTRICT,                  //码数目限制开启
            ID_PARAM_TRIGGER_FRAMES,                                    //帧数
            ID_PARAM_HARDWARE_TRIGGER_DEBOUNCETIME,                     //消抖时间
            ID_PARAM_HARDWARE_TRIGGER_POLARITY,                         //触发极性
            ID_PARAM_HARDWARE_TRIGGER_CODE_NUM_ENABLE,                  //启用最大码数目使能
            ID_PARAM_HARDWARE_TRIGGER_CODE_NUM,                         //解码数
            ID_PARAM_HARDWARE_TRIGGER_TIMEOUT,                          //超时时间
            ID_PARAM_HARDWARE_TRIGGER_STATISTIC_BY_NUM_ENABLE,          //硬件触发码数目使能
            ID_PARAM_TCPSEVER_TRIGGER_PORT,                             //tcp服务器端口
            ID_PARAM_TCPSEVER_TRIGGER_START_CMD,                        //tcp服务器开始触发指令
            ID_PARAM_TCPSEVER_TRIGGER_STOP_CMD,                         //tcp服务器停止触发指令
            ID_PARAM_TCPSEVER_TRIGGER_IS_FUZZY_MATCH_ENABLE_CMD,        //tcp服务器启用模糊匹配
            ID_PARAM_TCPSEVER_TRIGGER_HEX_ENABLE,                       //tcp服务器16进制使能
            ID_PARAM_TCPCLIENT_TRIGGER_PORT,                            //tcp客户端端口
            ID_PARAM_TCPCLIENT_TRIGGER_IP,                              //tcp客户端IP
            ID_PARAM_TCPCLIENT_TRIGGER_START_CMD,                       //tcp客户端开始触发指令
            ID_PARAM_TCPCLIENT_TRIGGER_STOP_CMD,                        //tcp客户端停止触发指令
            ID_PARAM_TCPCLIENT_TRIGGER_HEARTBEAT_ENABLE,                //tcp客户端心跳使能
            ID_PARAM_TCPCLIENT_TRIGGER_HEARTBEAT_CMD,                   //tcp客户端心跳指令
            ID_PARAM_TCPCLIENT_TRIGGER_HEARTBEAT_PERIOD,                //tcp客户端心跳周期
            ID_PARAM_TCPCLIENT_TRIGGER_IS_FUZZY_MATCH_ENABLE_CMD,       //tcp客户端启用模糊匹配
            ID_PARAM_TCPCLIENT_TRIGGER_HEX_ENABLE,                      //tcp客户端16进制使能
            ID_PARAM_UDP_TRIGGER_PORT,                                  //udp触发端口
            ID_PARAM_UDP_TRIGGER_START_CMD,                             //udp触发开始指令
            ID_PARAM_UDP_TRIGGER_STOP_CMD,                              //udp触发停止指令
            ID_PARAM_UDP_TRIGGER_IS_FUZZY_MATCH_ENABLE_CMD,             //udp触发启用模糊匹配
            ID_PARAM_UDP_TRIGGER_HEX_ENABLE,                            //udp16进制使能
            ID_PARAM_SERIAL_TRIGGER_START_CMD,                          //串口开始触发指令
            ID_PARAM_SERIAL_TRIGGER_STOP_CMD,                           //串口停止触发指令
            ID_PARAM_SERIAL_TRIGGER_IS_FUZZY_MATCH_ENABLE_CMD,          //串口启用模糊匹配
            ID_PARAM_SERIAL_TRIGGER_HEX_ENABLE,                         //串口16进制使能
            ID_PARAM_ENCODER_CTRL_PARAMS_ENABLE,                        //编码控制器状态(启用或禁用)
            ID_PARAM_ENCODER_CTRL_PARAMS_DIRECTION,                     //控制方向
            ID_PARAM_BUZZER_STATUS,                                     //蜂鸣器状态(启用或禁用)
            ID_PARAM_BUZZER_CONDITION,                                  //持续时间(毫秒)
            ID_PARAM_BUZZER_DURATION_TIME,                              //条件(指定触发条件)
            ID_PARAM_SENSING_SENSITIVITY,                               //感应灵敏度
            ID_PARAM_SENSING_WAITTIME,                                  //感应等待时间
            ID_PARAM_OUTPUT_TCPSEVER_PORT,                              //TCP服务器输出端口
            ID_PARAM_OUTPUT_TCPSEVER_ENABLE,                            //TCP服务器输出使能
            ID_PARAM_OUTPUT_TCPCLIENT_ENABLE,                           //TCP客户端输出使能
            ID_PARAM_OUTPUT_TCPCLIENT_PORT,                             //TCP客户端输出端口
            ID_PARAM_OUTPUT_TCPCLIENT_IP,                               //TCP客户端输出地址
            ID_PARAM_OUTPUT_TCPCLIENT_HEARTBEAT_ENABLE,                 //TCP客户端心跳使能
            ID_PARAM_OUTPUT_TCPCLIENT_HEARTBEAT_CMD,                    //TCP客户端心跳指令
            ID_PARAM_OUTPUT_TCPCLIENT_HEARTBEAT_PERIOD,                 //TCP客户端心跳周期
            ID_PARAM_OUTPUT_TCPCLIENT_HEX_ENABLE,                       //TCP客户端16进制使能
            ID_PARAM_OUTPUT_SERIALPORT_ENABLE,                          //串口输出使能
            ID_PARAM_OUTPUT_SERIALPORT_BAUDRATE,                        //串口波特率
            ID_PARAM_OUTPUT_SERIALPORT_PARITY,                          //串口校验位
            ID_PARAM_OUTPUT_SERIALPORT_DATABIT,                         //串口数据位
            ID_PARAM_OUTPUT_SERIALPORT_STOPBITS,                        //串口停止位
            ID_PARAM_OUTPUT_SERIALPORT_FLOWCTRL,                        //串口流控制
            ID_PARAM_OUTPUT_KEYBOARD_ENABLE,                            //键盘输出使能
            ID_PARAM_OUTPUT_EIP_ENABLE,                                 //EIP使能
            ID_PARAM_OUTPUT_EIP_RESULT_SWAP_ENABLE,                     //EIP结果交换使能
            ID_PARAM_OUTPUT_EIP_INPUT_SIZE,                             //EIP输入组件大小
            ID_PARAM_OUTPUT_EIP_OUTPUT_SIZE,                            //EIP输出组件大小
            ID_PARAM_OUTPUT_EIP_RESULT_TIMEOUT,                         //EIP结果超时
            ID_PARAM_OUTPUT_MODBUS_ENABLE,                              //MODBUS使能
            ID_PARAM_OUTPUT_MODBUS_ROLE,                                //MODBUS角色主站/从站
            ID_PARAM_OUTPUT_MODBUS_CONNECTIONTYPE,                      //MODBUS连接类型TCP/Serial
            ID_PARAM_OUTPUT_MODBUS_TCPSEVER_IP,                         //MODBUS tcp服务器IP
            ID_PARAM_OUTPUT_MODBUS_TCPSEVER_PORT,                       //MODBUS tcp端口
            ID_PARAM_OUTPUT_MODBUS_TIMEOUT,                             //MODBUS è¶…æ—¶æ—¶é—´
            ID_PARAM_OUTPUT_MODBUS_FUNCATION,                           //MODBUS function
            ID_PARAM_OUTPUT_MODBUS_SERVER_ADDRESS,                      //MODBUS æœåŠ¡å™¨åœ°å€
            ID_PARAM_OUTPUT_MODBUS_STARTADDRESS,                        //MODBUS å¯„存器起始地址
            ID_PARAM_OUTPUT_MODBUS_RESULT_SWAP_ENABLE,                  //MODBUS ç»“果交换使能
            ID_PARAM_OUTPUT_MODBUS_RETRIES_NUM,                         //MODBUS é‡è¯•次数
            ID_PARAM_OUTPUT_MODBUS_RESULT_TIMEOUT,                      //MODBUS ç»“果超时
            ID_PARAM_OUTPUT_FTP_ENABLE,                                 //FTP使能
            ID_PARAM_OUTPUT_FTP_LOCAL_ENABLE,                           //FTP æœ¬åœ°å­˜å›¾ä½¿èƒ½
            ID_PARAM_OUTPUT_FTP_IP,                                     //FTP IP地址
            ID_PARAM_OUTPUT_FTP_PORT,                                   //FTP ç«¯å£
            ID_PARAM_OUTPUT_FTP_USERNAME,                               //FTP账号
            ID_PARAM_OUTPUT_FTP_PWD,                                    //FTP密码
            ID_PARAM_OUTPUT_FTP_IMAGE_FORMAT,                           //FTP存图格式
            ID_PARAM_OUTPUT_FTP_COMPRESSRATE,                           //FTP存图压缩率
            ID_PARAM_OUTPUT_FTP_FILEPATH,                               //FTP存图路径
            ID_PARAM_OUTPUT_FTP_DEFAULT_FILENAME,                       //FTP默认文件名
            ID_PARAM_OUTPUT_FTP_LOCAL_PATH,                             //FTP本地保存路径
            ID_PARAM_OUTPUT_FTP_LOCAL_MAX_COUNT,                        //FTP本地保存最大数量
            ID_PARAM_OUTPUT_FTP_CONTAINS_DATE,                          //FTP命名包含时间缀
            ID_PARAM_OUTPUT_FTP_CONTAINS_INDEX,                         //FTP命名包含序号
            ID_PARAM_OUTPUT_FTP_CONTAINS_RESULT,                        //FTP命名包含结果
            ID_PARAM_OUTPUT_FTP_CONTAINS_FRAME_NUMBER,                  //FTP命名包含帧号
            ID_PARAM_OUTPUT_FTP_CONTAINS_BARCODE_ID_ENABLE,             //FTP生成读码器ID文件夹
            ID_PARAM_OUTPUT_FTP_CONTAINS_TRIGGER_SEQUENCE_ENABLE,       //FTP生成触发号文件夹
            ID_PARAM_OUTPUT_FTP_RESULT_RENDERING,                       //FTP结果渲染使能
            ID_PARAM_OUTPUT_FTP_BOUNDINGBOX_RENDERING,                  //FTP定位框渲染使能
            ID_PARAM_OUTPUT_FTP_SAVE_SRATEGY,                           //FTP存图策略
            ID_PARAM_OUTPUT_FTP_SAVE_POLICY_FRAME_INDEX,                //FTP按指定帧号存图
            ID_PARAM_OUTPUT_FTP_FTP_SAVE_POLICY_RANGE_START_FRAME,      //FTP按范围存图起始帧号
            ID_PARAM_OUTPUT_FTP_FTP_SAVE_POLICY_RANGE_END_FRAME,        //FTP按范围存图结束帧号
            ID_PARAM_OUTPUT_FTP_CONDITION,                              //FTP保存条件
            ID_PARAM_OUTPUT_WEB_ENABLE,                                 //WEB页面使能
            ID_PARAM_OUTPUT_WEB_PORT,                                   //WEB页面端口
            ID_PARAM_OUTPUT_WEB_IMAGE_QUALITY,                          //WEB图像质量
            ID_PARAM_OUTPUT_WEB_RESULT_ENABLE,                          //WEB显示结果使能
            ID_PARAM_OUTPUT_WEB_IMAGE_ENABLE,                           //WEB显示图像使能
            ID_PARAM_OUTPUT_WEB_DISPLAY_INFO_FORMAT,                    //WEB显示数据格式化
            ID_PARAM_OUTPUT_NETWORKING_ENABLE,                          //组网使能
            ID_PARAM_OUTPUT_NETWORKING_MASTER_ENABLE,                   //是否是master
            ID_PARAM_OUTPUT_NETWORKING_PORT,                            //组网通信端口
            ID_PARAM_OUTPUT_NETWORKING_MASTER_IP,                       //组网主机IP
            ID_PARAM_OUTPUT_NETWORKING_MASTER_TIMEOUT,                  //组网主机超时时间
            ID_PARAM_OUTPUT_NETWORKING_SLAVE_ID,                        //组网从机ID
            ID_PARAM_OUTPUT_NETWORKING_MASTER_MAX_CONNECT_NUM,          //组网主机最大连接从机数
            ID_PARAM_OUTPUT_NETWORKING_TRIGGER_SLAVE_ENABLE,            //组网主机触发从机使能
            ID_PARAM_OUTPUT_NETWORKING_SLAVE_RECEIVE_TRIGGER_ENABLE,    //组网从机接收主机触发使能
            ID_PARAM_OUTPUT_NETWORKING_SLAVE_TRIGGER_DELAY,             //组网从机触发延迟
            ID_PARAM_OUTPUT_NETWORKING_SLAVE_TRIGGER_CONNECTION_STATUS, //组网连接状态
            ID_PARAM_OUTPUT_NETWORKING_DEVICE_ROI_ENABLE,               //组网设备ROI补齐使能
            ID_PARAM_OUTPUT_PROFINET_ENABLE,                            //PROFINET使能
            ID_PARAM_OUTPUT_PROFINET_RESULT_MODEL_SIZE,                 //PROFINET结果模块大小
            ID_PARAM_OUTPUT_PROFINET_NAME,                              //PROFINET配置名
            ID_PARAM_OUTPUT_PROFINET_RESULT_SWAP_ENABLE,                //PROFINET结果字节交换使能
            ID_PARAM_OUTPUT_PROFINET_RESULT_SIZE,                       //PROFINET结果大小
            ID_PARAM_OUTPUT_PROFINET_RESULT_TIMEOUT,                    //PROFINET结果超时
            ID_PARAM_OUTPUT_FINS_ENABLE,                                //FINS使能
            ID_PARAM_OUTPUT_FINS_IS_TCP,                                //FINS是否启用TCP
            ID_PARAM_OUTPUT_FINS_IP,                                    //FINS上位机IP
            ID_PARAM_OUTPUT_FINS_PROT,                                  //FINS上位机端口
            ID_PARAM_OUTPUT_FINS_STARTADDRESS,                          //FINS数据起始地址
            ID_PARAM_OUTPUT_FINS_RESULT_SWAP_ENABLE,                    //FINS结果交换使能
            ID_PARAM_OUTPUT_FINS_RESULT_SIZE,                           //FINS结果数据大小
            ID_PARAM_OUTPUT_FINS_RESULT_TIMEOUT,                        //FINS结果超时时间
            ID_PARAM_OUTPUT_HTTP_ENABLE,                                //HTTP使能
            ID_PARAM_OUTPUT_HTTP_URL,                                   //HTTP发送地址
            ID_PARAM_OUTPUT_MC_CONFIG_ENABLE,                           //MC使能
            ID_PARAM_OUTPUT_MC_CONFIG_UDP_COMMUNICATION,                //MC UDP通讯使能
            ID_PARAM_OUTPUT_MC_CONFIG_BRAND_MODEL,                      //MC品牌型号
            ID_PARAM_OUTPUT_MC_CONFIG_DATA_FORMAT,                      //MC数据格式
            ID_PARAM_OUTPUT_MC_CONFIG_IP_ADDRESS,                       //MC IP地址
            ID_PARAM_OUTPUT_MC_CONFIG_PORT,                             //MC端口
            ID_PARAM_OUTPUT_MC_CONFIG_START_ADDRESS,                    //MC起始地址
            ID_PARAM_OUTPUT_MC_CONFIG_RESULT_SWAP,                      //MC结果交换
            ID_PARAM_OUTPUT_MC_CONFIG_RESULT_SIZE,                      //MC结果大小
            ID_PARAM_OUTPUT_MC_CONFIG_RESULT_TIMEOUT,                   //MC结果超时
            ID_PARAM_OUTPUT_UDP_CONFIG_ENABLE,                          //UDP使能
            ID_PARAM_OUTPUT_UDP_CONFIG_PORT,                            //UDP端口
            ID_PARAM_OUTPUT_UDP_CONFIG_IP_ADDRESS                        //UDP IP地址
        }
    }
}
IDViewer_2D/IDViewerDefines1.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,452 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace IDViewer_2D
{
    class IDViewerDefines
    {
        // ä½¿ç”¨æžšä¸¾è¡¨ç¤ºå›žè°ƒæ¶ˆæ¯ID
        public enum CallbackMessageID
        {
            DeviceConnectionEstablished = 1,
            DeviceConnectionClosed = 2
        }
        public enum ErrorCodes
        {
            ID_OK = 0,                      //成功
            ID_ERROR_ALREADY_INIT = 146000010,              //已经初始化
            ID_ERROR_NOT_INIT = 146000011,              //未初始化
            ID_ERROR_CREATE_DEVICE_INFO_NOT_EXSIST = 146000012,             //当前创建设备不存在
            ID_ERROR_SET_IP_DEVICE_ALREADY_CREATED = 146000013,             //当前设置IP设备已经创建
            ID_ERROR_DEVICE_HAVE_OPENED = 146000014,                //设备已经打开
            ID_ERROR_OPEN_DEVICE_CONNECT_PARAMS_ERROR = 146000015,              //打开设备连接参数错误
            ID_ERROR_OPEN_DEVICE_CONNECT_IS_CREATE = 146000016,             //打开设备连接已经创建
            ID_ERROR_OPEN_DEVICE_CONNECT_SOCKET_FAILED = 146000017,             //打开设备连接建立失败
            ID_ERROR_OPEN_DEVICE_CONNECT_FAILED = 146000018,                //打开设备连接失败
            ID_ERROR_DEVICE_NOT_OPEN = 146000019,               //设备未打开
            ID_ERROR_DEVICE_IS_RUNNING = 146000020,             //设备已经在运行模式
            ID_ERROR_DEVICE_IS_DEBUGGING = 146000021,               //设备已经在调试模式
            ID_ERROR_DEVICE_QUERY_HARDWARE_INFO_FAILED = 146000022,             //获取设备硬件信息失败
            ID_ERROR_OPEN_DEVICE_CREATE_DATA_RECEIVED_FAILED = 146000023,               //打开设备接收数据服务创建失败
            ID_ERROR_OPEN_DEVICE_SOLUTION_MANAGER_CONNECTION_FAILED = 146000024,                //打开设备时连接方案管理工具失败
            ID_ERROR_SOLUTION_MANAGER_TIMEOUT = 146000025,              //方案管理类超时
            ID_ERROR_SOLUTION_MANAGER_CAN_NOT_DELETE_CURRENT_SOLUTION = 146000026,              //不能删除当前方案
            ID_ERROR_SOLUTION_MANAGER_CURRENT_SOLUTION_NOT_EXISTED = 146000027,             //当前方案不存在
            ID_ERROR_SET_IP_ADDRESS_INVALID = 146000028,                //设置IP地址不合法
            ID_ERROR_SET_IP_MASK_INVALID = 146000029,               //设置子网掩码地址不合法
            ID_ERROR_SET_IP_GATEWAY_INVALID = 146000030,                //设置网关地址不合法
            ID_ERROR_SET_IP_ADDRESS_GATEWAY_NOT_IN_SAME_SUBNET = 146000031,             //设置的IP地址和网关不在同一网段
            ID_ERROR_SET_IP_ADDRESS_ALREADY_EXISTED = 146000032,                //设置的IP已经存在
            ID_ERROR_SOLUTION_MANAGER_SOLUTION_NAME_INVALID = 46000033                //方案名称非法,不能包含<>:\"/\\|?*
        }
        public enum IDImageType
        {
            ID_IMAGE_8U_C = 0,            // 8位无符号类型
            ID_IMAGE_8S_C,                // 8位有符号类型
            ID_IMAGE_16U_C,                // 16位无符号类型
            ID_IMAGE_16S_C,                // 16位有符号类型
            ID_IMAGE_32S_C,                // 32位有符号类型
            ID_IMAGE_32F_C,                // 32位浮点类型
            ID_IMAGE_64F_C              // 64位浮点类型
        }
        //条码类型枚举
        public enum IDCodeType
        {
            ID_CODETYPE_UNKNOWN_C = 0x0,
            ID_CODETYPE_CODE39_C = 0x1,
            ID_CODETYPE_CODE128_C = 0x2,
            ID_CODETYPE_EAN8_C = 0x4,
            ID_CODETYPE_EAN13_C = 0x8,
            ID_CODETYPE_UPC_A_C = 0x10,
            ID_CODETYPE_UPC_E_C = 0x20,
            ID_CODETYPE_CODE93_C = 0x40,
            ID_CODETYPE_ITF_C = 0x80,
            ID_CODETYPE_GS1_128_C = 0x100,
            ID_CODETYPE_GS1_DATABAR_EXPANDED_C = 0x200,
            ID_CODETYPE_GS1_DATABAR_C = 0x400,
            ID_CODETYPE_GS1_DATABAR_STACKED_C = 0x600,
            ID_CODETYPE_GS1_DATABAR_EXPANDED_STACKED_C = 0x800,
            ID_CODETYPE_GS1_DATABAR_LINITED_C = 0x1000,
            ID_CODETYPE_PHARMACODE_C = 0x2000,
            ID_CODETYPE_MSI_C = 0x4000,
            ID_CODETYPE_PLESSEY_C = 0x8000,
            ID_CODETYPE_CODEBAR_C = 0x10000,
            ID_CODETYPE_INT2OF5_C = 0x20000,
            ID_CODETYPE_STD2OF5_C = 0x40000,
            ID_CODETYPE_MTX2OF5_C = 0x80000,
            ID_CODETYPE_DATAMATRIX_C = 0x04000000,
            ID_CODETYPE_QRCODE_C = 0x08000000,
            ID_CODETYPE_PDF417_C = 0x010000000,
            ID_CODETYPE_MICROQR_C = 0x020000000,
            ID_CODETYPE_AZTEC_C = 0x040000000,
            //ID_CODETYPE_VERICODE_C = 0x080000000
        }
        public struct IDDeviceInfo
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public char[] networkIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] networkMask;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] networkGateway;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string networkAdapterFriendName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] networkMac;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public char[] cameraIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraNetMask;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraGateWay;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraMac;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraSN;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraModel;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraManufucturer;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraSoftwareVersion;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraFirmwareVersion;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string cameraAlias;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] cameraType;
        }
        //硬件信息通用节点结构体
        public struct IDNodeParam
        {
            public float maxValue;
            public float minValue;
            public float value;
            public int type;
        }
        public IDNodeParam createIDNodeParam_C() {
            IDNodeParam param;
            param.maxValue = 0;
            param.minValue = 0;
            param.value = 0;
            param.type = 0;
            return param;
        }
        //硬件信息结构体
        public struct IDDeviceHarewareParams
        {
            public int imageWidth;
            public int imageHight;
            public IDNodeParam exposureStep;
            public IDNodeParam exposure;
            public IDNodeParam gamma;
            public IDNodeParam gain;
            public IDNodeParam illuminanatInerval;
            public IDNodeParam focusingLocation;
            public IDNodeParam DICount;
            public IDNodeParam DOCount;
            public IDNodeParam isOpenSightingDevice;
        }
        public IDDeviceHarewareParams createID_DEVICE_HARDWARE_PARAMS()
        {
            IDDeviceHarewareParams HarewareParams;
            HarewareParams.imageWidth = 0;
            HarewareParams.imageHight = 0;
            HarewareParams.exposureStep = createIDNodeParam_C();
            HarewareParams.exposure = createIDNodeParam_C();
            HarewareParams.gamma = createIDNodeParam_C();
            HarewareParams.gain = createIDNodeParam_C();
            HarewareParams.illuminanatInerval = createIDNodeParam_C();
            HarewareParams.focusingLocation = createIDNodeParam_C();
            HarewareParams.DICount = createIDNodeParam_C();
            HarewareParams.DOCount = createIDNodeParam_C();
            HarewareParams.isOpenSightingDevice = createIDNodeParam_C();
            return HarewareParams;
        }
        //点类型结构体
        public struct IDPoint
        {
            public double x;
            public double y;
        }
        //质量评估输出结果
        //ISO IEC 15416-2016
        public struct IDQuality15416
        {
            public float overallQuality;
            public float decode;
            public float edgeDetermination;
            public float symbolContrast;
            public float minReflectance;
            public float minEdgeContrast;
            public float modulation;
            public float quietZone;
            public float decodability;
            public float defects;
        }
        //ISO_IEC15415-2011 QR
        public struct IDQualityQR15415
        {
            public float overallQuality;
            public float decode;
            public float symbolContrast;
            public float fixedPatternDamage;
            public float modulation;
            public float reflectanceMargin;
            public float unusedErrCorrection;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float formatInformation;
            public float versionInformation;
            public float contrastUniformity;
            public float printGrowth;
            public float aperture;
        }
        //DM 15415码质量
        public struct IDQualityDM15415
        {
            public float overallQuality;
            public float decode;
            public float symbolContrast;
            public float fixedPatternDamage;
            public float modulation;
            public float reflectanceMargin;
            public float unusedErrCorrection;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float contrastUniformity;
            public float printGrowth;
            public float aperture;
        }
        //ISO IEC TR 29158-2011(AIM-DPM-1-2006)
        public struct IDQualityDM29518
        {
            public float overallQuality;
            public float decode;
            public float cellContrast;
            public float cellModulation;
            public float reflectanceMargin;
            public float fixedPatternDamage;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float unusedErrCorrection;
            public float contrastUniformity;
            public float meanLight;
            public float printGrowth;
            public float aperture;
        }
        //QR 29158结构体
        public struct IDQualityQR29518
        {
            public float overallQuality;
            public float decode;
            public float cellContrast;
            public float cellModulation;
            public float fixedPatternDamage;
            public float reflectanceMargin;
            public float unusedErrCorrection;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float formatInformation;
            public float versionInformation;
            public float contrastUniformity;
            public float meanLight;
            public float printGrowth;
            public float aperture;
        }
        public struct IDQualityPDF417_15415
        {
            public float overallQuality;
            public float decode;
            public float symbolContrast;
            public float fixPattern;
            public float modulation;
            public float unusedErrCorrection;
            public float axialNonuniformity;
            public float gridNonuniformity;
            public float startStopPattern;
            public float codewordYield;
            public float defects;
            public float aperture;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 36)]
        public struct IDDecodeInfo
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool decodeStatus;                           //解码结果状态OK/NG
            public float runtime;                               //解码耗时
            public uint hardParamIndex;
            public uint successCount;                           //解码成功数
            public uint failedCount;                            //解码失败数
            public uint decodeCount;                            //总解码数
            public double decodeRate;                           //解码率
            public uint IDDecodeROIInfoLength;                  //ROI解码信息数组的长度
        }
        //当前ROI解码结果
        public struct IDDecodeROIInfo
        {
            public int roiIndex;                                        //ROI编号
            public int decodeReusltLength;
        }
        //当前解码结果,当前版本每个解码结果中的集合,只有一个码制有结果,里面的长度代表的是当前码类型的解码个数
        public struct IDDecodeResult {
            public int conbination;
            public int dmResultsLength;
            public int qrResultsLength;
            public int pdf417ResultsLength;
            public int barcodeResultsLength;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi,Pack = 1)]
        public struct IDDMCodeResult
        {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                   // å½“前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256 )]
            public char[] subType;               // å­ç±»åž‹
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;            // è§£ç ç»“æžœ
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;              // æžæ€§
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] shape;                 // æ ·å¼
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                // é•œåƒ
            public int contrast;                 // å¯¹æ¯”度
            public float moduleSize;
            public float orientation;
        }
        //QR解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDQRCodeResult {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                        //当前结果解码状态
            //IDCodeType codeType;                            //条码类型
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                                //解码结果
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] subType;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] errorLevel;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                                    //镜像
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] version;                                    //版本信息
            public int contrast;
            public float moduleSize;
            public float orientation;                                //角度
        }
        //PDF417解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDPDF417CodeResult {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                        //当前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                                //解码结果
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] subType;                                    //子类型
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] polarity;                                //极性
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] mirror;                                    //镜像
            public int symbolRows;
            public int    symbolCols;
            public int    errorLevel;
            public int contrast;
            public float moduleHeight;
            public float pixelPerModule;                            //moduleWidth
            public float  moduleRatio;
            public float orientation;                                //角度
            //IDQualityPDF417_15415 quality15415;
        }
        //barcode解码结果
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct IDBarCodeResult {
            [MarshalAs(UnmanagedType.I1)]
            public bool state;                                        //当前结果解码状态
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public char[] codeString;                                //解码结果
            public float orientation;                                //角度
            public float pixelPerModule;
        }
        public unsafe struct StringList
        {
            public char** items;
            public int size;
            public int capacity;
        }
    }
}
IDViewer_2D/IDViewerDemo.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{72CF1572-12CD-4648-BAA8-1A27421191C4}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>IDViewerDemo</RootNamespace>
    <AssemblyName>IDViewerDemo</AssemblyName>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x64\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
    <OutputPath>bin\x64\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <Optimize>true</Optimize>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="IDViewerDefines.cs" />
    <Compile Include="IDViewerSDK.cs" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>
IDViewer_2D/IDViewerSDK.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1030 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using static SmartScanner.IDViewerDefines;
using System.Reflection;
namespace SmartScanner
{
    class IDViewerSDK
    {
        public class Node
        {
            public IDViewerDefines.IDDeviceInfo data;
            public Node next;
        }
        public struct LinkedList
        {
            public Node head;
            [MarshalAs(UnmanagedType.SysInt)]
            public int size;
        }
        /****************************************
         IDImage
        *****************************************/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Init", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Init(ref IntPtr imagePtr);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Destroy", CharSet = CharSet.Ansi)]
        public static extern void IDImage_Destroy(ref IntPtr imagePtr);             //
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Width", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Width(IntPtr imageHandle);                //图片宽度
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Height", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Height(IntPtr imageHandle);               //图片高度
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Step", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Step(IntPtr imageHandle);                 //步长
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_BitDepth", CharSet = CharSet.Auto)]
        public static extern long IDImage_BitDepth(IntPtr imageHandle, ref IntPtr imageType);       //位深
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Channels", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Channels(IntPtr imageHandle);             //通道数
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_ImageData", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDImage_ImageData(IntPtr imageHandle);          //浅拷贝
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_SaveImage", CharSet = CharSet.Ansi)]
        public static extern long IDImage_SaveImage(IntPtr imageHandle, string filePath, int compression);      //保存
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_SaveImageW", CharSet = CharSet.Unicode)]
        public static extern long IDImage_SaveImageW(IntPtr imageHandle, string filePath, int compression);      //宽字节保存
        /*
        * VarPoint
        */
        // æž„造函数声明
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarPoint_Create", CharSet = CharSet.Ansi)]
        public static extern long VarPoint_Create(ref IntPtr handle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarPoint_CreateWithValues", CharSet = CharSet.Ansi)]
        public static extern long VarPoint_CreateWithValues(ref IntPtr handle, double xPoint, double yPoint);
        // æžæž„函数声明
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarPoint_Destroy", CharSet = CharSet.Ansi)]
        public static extern void VarPoint_Destroy(ref IntPtr handle);
        /*
        * VarFlags
        */
        // æž„造函数
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Create", CharSet = CharSet.Ansi)]
        public static extern long VarFlags_Create(ref IntPtr handle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_CreateWithFlags", CharSet = CharSet.Ansi)]
        public static extern long VarFlags_CreateWithFlags(ref IntPtr handle, uint flags);
        // æˆå‘˜å‡½æ•°
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Set", CharSet = CharSet.Ansi)]
        public static extern void VarFlags_Set(ref IntPtr handle, uint flag);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Unset", CharSet = CharSet.Ansi)]
        public static extern void VarFlags_Unset(ref IntPtr handle, uint flag);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Reset", CharSet = CharSet.Ansi)]
        public static extern void VarFlags_Reset(ref IntPtr handle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Check", CharSet = CharSet.Ansi)]
        public static extern bool VarFlags_Check(ref IntPtr handle, uint flag);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Get", CharSet = CharSet.Ansi)]
        public static extern uint VarFlags_Get(ref IntPtr handle);
        // æžæž„函数
        [DllImport("IDViewerCSDK.dll", EntryPoint = "VarFlags_Destroy", CharSet = CharSet.Ansi)]
        public static extern void VarFlags_Destroy(ref IntPtr handle);
        /*
        * IDVariable
        */
        // åˆ›å»º IDVariable å®žä¾‹
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_CreateIDVariable", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDVariab_CreateIDVariable();
        // é‡Šæ”¾ IDVariable å®žä¾‹
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_DestroyIDVariable", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_DestroyIDVariable(IntPtr IDVariableHandle);
        // è®¾ç½® double æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataDouble", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataDouble(IntPtr IDVariableHandle, double data, bool setInit);
        // è®¾ç½® string æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataChar", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataChar(IntPtr IDVariableHandle, string data, bool setInit);
        // è®¾ç½® string æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataString", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataString(IntPtr IDVariableHandle, string data, bool setInit);
        // è®¾ç½® bool æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataBool", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataBool(IntPtr IDVariableHandle, bool data, bool setInit);
        // è®¾ç½® uint æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataUnsignedInt", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataUnsignedInt(IntPtr IDVariableHandle, uint data, bool setInit = false);
        // è®¾ç½® VarPoint æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataVarPoint", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataVarPoint(IntPtr IDVariableHandle, ref double data, bool setInit = false);
        // è®¾ç½®vector<double> data数据
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataVectorDouble", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataVectorDouble(IntPtr IDVariableHandle, IntPtr data, int size, bool setInit = false);
        // è®¾ç½®vector<string> data æ•°æ®
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataStringArray", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataStringArray(IntPtr IDVariableHandle, string[] data, int size, bool setInit = false);
        // å°†vector<bool>转换
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataBoolVector", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataBoolVector(IntPtr IDVariableHandle, ref bool data, int size, bool setInit = false);
        // å°†vector<bool>转换为C风格的接口
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariab_SetDataVarFlags", CharSet = CharSet.Ansi)]
        public static extern void IDVariab_SetDataVarFlags(IntPtr IDVariableHandle, ref IntPtr handle, bool setInit = false);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariable_ToNumber", CharSet = CharSet.Ansi)]
        public static extern double IDVariable_ToNumber(IntPtr IDVariableHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariable_ToBool", CharSet = CharSet.Ansi)]
        public static extern bool IDVariable_ToBool(IntPtr IDVariableHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariable_ToFlags", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDVariable_ToFlags(IntPtr IDVariableHandle);
        /*
        * class  IDCodeParam
        */
        // æž„造函数的封装
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_Create", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_Create();
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateCopy", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateCopy(IntPtr IDCodeParamHandle);
        // ä½¿ç”¨ä¸åŒå‚数构造函数的封装
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateFromQRCodeParam", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateFromQRCodeParam(ref IDQRCodeParam qrCodeParam);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateFromDMCodeParam", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateFromDMCodeParam(ref IDDMCodeParam dmCodeParam);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateFromPDF417CodeParam", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateFromPDF417CodeParam(ref IDPDF417CodeParam pdf417CodeParam);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateFromBarCodeParam", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateFromBarCodeParam(ref IDBarCodeParam barCodeParam);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_CreateFromMicroQRParam", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDCodeParam_CreateFromMicroQRParam(ref IDMicroQRParam microQRParam);
        // èµ‹å€¼æ“ä½œç¬¦çš„封装
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_Assign", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_Assign(IntPtr self, IntPtr IDCodeParamHandle);
        // è®¾ç½®å’ŒèŽ·å–å‚æ•°çš„å‡½æ•°å°è£…
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_SetQRCodeParam", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_SetQRCodeParam(IntPtr self, ref IDQRCodeParam param);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetQRCodeParam", CharSet = CharSet.Ansi)]
        public static extern ref IDQRCodeParam IDCodeParam_GetQRCodeParam(IntPtr self);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_SetDMCodeParam", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_SetDMCodeParam(IntPtr self, ref IDDMCodeParam param);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetDMCodeParam", CharSet = CharSet.Ansi)]
        public static extern ref IDDMCodeParam IDCodeParam_GetDMCodeParam(IntPtr self);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_SetStackedCodeParam", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_SetStackedCodeParam(IntPtr self, ref IDQRCodeParam param);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetStackedCodeParam", CharSet = CharSet.Ansi)]
        public static extern ref IDPDF417CodeParam IDCodeParam_GetStackedCodeParam(IntPtr self);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_SetBarCodeParam", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_SetBarCodeParam(IntPtr self, ref IDBarCodeParam param);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetBarCodeParam", CharSet = CharSet.Ansi)]
        public static extern ref IDBarCodeParam IDCodeParam_GetBarCodeParam(IntPtr self);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_SetMicroQRParam", CharSet = CharSet.Ansi)]
        public static extern void IDCodeParam_SetMicroQRParam(IntPtr self, ref IDMicroQRParam param);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetMicroQRParam", CharSet = CharSet.Ansi)]
        public static extern ref IDMicroQRParam IDCodeParam_GetMicroQRParam(IntPtr self);
        // èŽ·å–ç±»åž‹çš„å°è£…
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCodeParam_GetType", CharSet = CharSet.Ansi)]
        public static extern IDCodeCategory IDCodeParam_GetType(IntPtr self);
        /**
        * @brief setFilterRules                    è®¾ç½®è¿‡æ»¤è§„则
        * @param filterRules                    è¿‡æ»¤è§„则
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetFilterRules", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetFilterRules(IntPtr deviceHandle, IDFilterRules filterRules);
        /**
        * @brief setFilterRules                    åˆ é™¤è¿‡æ»¤è§„则
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_RemoveFilterRules", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_RemoveFilterRules(IntPtr deviceHandle);
        /**
        * @brief addEnvironmentVariable            æ·»åŠ ä¸€ä¸ªçŽ¯å¢ƒå˜é‡
        * @param varName                        çŽ¯å¢ƒå˜é‡åç§°
        * @param varValue                        çŽ¯å¢ƒå˜é‡å¯¹åº”çš„å€¼
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AddEnvironmentVariable", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_AddEnvironmentVariable(IntPtr deviceHandle, string varName, IntPtr varValue);
        /**
        * @brief deleteEnvironmentVariable        åˆ é™¤æŒ‡å®šçŽ¯å¢ƒå˜é‡
        * @param varName                        è¦åˆ é™¤çš„环境变量名称
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteEnvironmentVariable", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DeleteEnvironmentVariable(IntPtr deviceHandle, string varName);
        /**
        * @brief getEnvironmentVariableNames    èŽ·å–æ‰€æœ‰çŽ¯å¢ƒå˜é‡å
        * @param varNames                        çŽ¯å¢ƒå˜é‡ååˆ—è¡¨
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetEnvironmentVariableNamesEX", CharSet = CharSet.Ansi)]   //使用后需要调用IDDevice_FreeSolutionList é‡Šæ”¾StringList
        public static extern ref StringList IDDevice_GetEnvironmentVariableNamesEX(IntPtr deviceHandle);
        /**
        * @brief getEnvironmentVariable            æ ¹æ®å˜é‡åèŽ·å–çŽ¯å¢ƒå˜é‡çš„å€¼
        * @param varName                        çŽ¯å¢ƒå˜é‡åç§°
        * @param varValue                        çŽ¯å¢ƒå˜é‡å¯¹åº”çš„å€¼
        * @return
*/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetEnvironmentVariable", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetEnvironmentVariable(IntPtr deviceHandle, ref string varName, IntPtr varValue);
        /**
        * @brief getParamValue                    èŽ·å–æ–¹æ¡ˆå‚æ•°
        * @param paramName                        å‚数名枚举值
        * @param generalParam                    å‚数取值
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetParamValue", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetParamValue(IntPtr deviceHandle, IDGeneralParamsName paramName, IntPtr generalParam);
        /**
        * @brief getParamValue                    è®¾ç½®æ–¹æ¡ˆå‚æ•°
        * @param paramName                        å‚数名枚举值
        * @param generalParam                    å‚数取值
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetParamValue", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetParamValue(IntPtr deviceHandle, IDGeneralParamsName paramName, IntPtr generalParam);
        //class IDGeneralParam
        // åˆ›å»ºç©ºå¯¹è±¡
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create();
        // åŸºç¡€ç±»åž‹
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Bool", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Bool(bool data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Char", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Char(string data);
        // æ•°å€¼ç±»åž‹
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UnsignedChar", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UnsignedChar(char data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Float", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Float(float data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UnsignedShort", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UnsignedShort(ushort data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UnsignedInt", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UnsignedInt(uint data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UnsignedLong", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UnsignedLong(ulong data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Long", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Long(long data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Int", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Int(int data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_Short", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_Short(short data);
        // ç‰¹æ®Šç±»åž‹
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_VarPoint", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_VarPoint(IntPtr data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_VarFlags", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_VarFlags(IntPtr data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_VectorDouble", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_VectorDouble(ref double data, int size);
        /*
         string[] data = new string[] { "data1", "data2", "data3" };
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_VectorString", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_VectorString(string[] data, int size);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_VectorBool", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_VectorBool(ref bool data, int size);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UChar", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UChar(char data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UShort", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UShort(ushort data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_UInt", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_UInt(uint data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_Create_ULong", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_Create_ULong(ulong data);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_SetName", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_SetName(IntPtr generalParamHandle, string name);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_GetName", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_GetName(IntPtr generalParamHandle, string name);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_GetType", CharSet = CharSet.Ansi)]
        public static extern IDGeneralParamsType IDGeneralParam_GetType(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_SetComment", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_SetComment(IntPtr generalParamHandle, string comment);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_GetComment", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_GetComment(IntPtr generalParamHandle, string comment);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_GetID", CharSet = CharSet.Ansi)]
        public static extern int IDGeneralParam_GetID(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_SetID", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_SetID(IntPtr generalParamHandle, int id);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToInt", CharSet = CharSet.Ansi)]
        public static extern int IDGeneralParam_ToInt(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToNumber", CharSet = CharSet.Ansi)]   //PLC变量类型是Num
        public static extern double IDGeneralParam_ToNumber(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToBool", CharSet = CharSet.Ansi)]
        public static extern bool IDGeneralParam_ToBool(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToChar", CharSet = CharSet.Ansi)]
        public static extern char IDGeneralParam_ToChar(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToFloat", CharSet = CharSet.Ansi)]
        public static extern float IDGeneralParam_ToFloat(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToCharItr", CharSet = CharSet.Ansi)]
        public static extern IntPtr IDGeneralParam_ToCharItr(IntPtr generalParamHandle);  //字符串类型获取后必须使用IDGeneralParam_FreeCharItr å¯¹æŒ‡é’ˆè¿›è¡Œé‡Šæ”¾ï¼›
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_FreeCharItr", CharSet = CharSet.Ansi)]
        public static extern void IDGeneralParam_FreeCharItr(IntPtr ptr);   //和上面IDGeneralParam_ToCharItr配套使用完后进行释放;
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToUShort", CharSet = CharSet.Ansi)]
        public static extern ushort IDGeneralParam_ToUShort(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToUInt", CharSet = CharSet.Ansi)]
        public static extern uint IDGeneralParam_ToUInt(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToULong", CharSet = CharSet.Ansi)]
        public static extern ulong IDGeneralParam_ToULong(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDGeneralParam_ToShort", CharSet = CharSet.Ansi)]
        public static extern short IDGeneralParam_ToShort(IntPtr generalParamHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVariable_ToFlags", CharSet = CharSet.Ansi)]
        public static extern long IDGeneralParam_ToLong(IntPtr generalParamHandle);
        /****************************************
        IDDevice
        *****************************************/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Open", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_Open(IntPtr deviceHandle);                               //打开设备
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsOpen", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_IsOpen(IntPtr deviceHandle);                             //打开状态
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_StartRunning", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_StartRunning(IntPtr deviceHandle);                       //默认 æ³¨å†Œå›žè°ƒ   è¿è¡Œè®¾å¤‡
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_StartDebugging", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_StartDebugging(IntPtr deviceHandle);                     //启动调试
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsDebugging", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_IsDebugging(IntPtr deviceHandle);                        //调试状态
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsRunning", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_IsRunning(IntPtr deviceHandle);                          //运行状态
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsConnected", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_IsConnected(IntPtr deviceHandle);                        //连接状态
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Stop", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_Stop(IntPtr deviceHandle);                               //停止
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Close", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_Close(IntPtr deviceHandle);                             //关闭
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_CaptureImage", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_CaptureImage(IntPtr deviceHandle, IntPtr imageHandle);   //采集一次
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetLasersightEnable", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetLasersightEnable(IntPtr deviceHandle, bool enable);    //设置使能瞄准器
        /****************************************
        DeviceInfo
        *****************************************/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetDeviceInfo", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetDeviceInfo(IntPtr deviceHandle, ref IDDeviceInfo DeviceInfoHandel); //获取设备信息(SN/MAC/IP/MODEL)
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetHardWareParams", CharSet = CharSet.Ansi)]
        public static extern IDViewerDefines.IDDeviceHarewareParams IDDevice_GetHardWareParams(IntPtr deviceHandle);
        //此接口需要VS2019以上的版本,C#7.0新增引入了新的语法ref return和ref locals,允许函数的返回值也可以被声明为引用
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetSolutionList", CharSet = CharSet.Ansi)]
        public static extern ref StringList IDDevice_GetSolutionList(IntPtr deviceHandle, int timeout = 2000);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetRunningSolution", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetRunningSolution(IntPtr deviceHandle, string solutionName, int timeout = 2000);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetRunningSolution", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetRunningSolution(IntPtr deviceHandle, byte[] solutionName, int timeout = 2000);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteSolution", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DeleteSolution(IntPtr deviceHandle, string solutionName, int timeout = 2000);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Release", CharSet = CharSet.Ansi)]
        public static extern void IDDevice_Release(IntPtr deviceHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_FreeSolutionList", CharSet = CharSet.Ansi)]
        public static extern void IDDevice_FreeSolutionList(StringList solutionList);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_getROIInfoLength", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_getROIInfoLength(IntPtr deviceHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_getROIInfo", CharSet = CharSet.Ansi)]                 //获取ROI
        public static extern IDViewerDefines.IDROIInfo IDDevice_getROIInfo(IntPtr deviceHandle, int roiIndex);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteROI", CharSet = CharSet.Ansi)]                  //删除ROI
        public static extern long IDDevice_DeleteROI(IntPtr deviceHandle, int roiIndex);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AddROI", CharSet = CharSet.Ansi)]                     //添加ROI
        public static extern long IDDevice_AddROI(IntPtr deviceHandle, IDViewerDefines.IDROIInfo roiInfo);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_ModifyROI", CharSet = CharSet.Ansi)]                  //修改ROI
        public static extern long IDDevice_ModifyROI(IntPtr deviceHandle, int roiIndex, IDViewerDefines.IDPoint topLeftPoint, IDViewerDefines.IDPoint bottomRightPoint);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetFocusLocation", CharSet = CharSet.Ansi)]
        public static unsafe extern long IDDevice_GetFocusLocation(IntPtr deviceHandle, int* focusLocation);        //获取焦距位置
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AutoFocus", CharSet = CharSet.Ansi)]     //自动对焦
        public static unsafe extern long IDDevice_AutoFocus(IntPtr deviceHandle, int paramIndex, ref int focusLocation);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetFocusLocation", CharSet = CharSet.Ansi)]     //设置焦距位置
        public static extern long IDDevice_SetFocusLocation(IntPtr deviceHandle, int paramIndex, int focusLocation);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetExposure", CharSet = CharSet.Ansi)]     //设置曝光
        public static extern long IDDevice_SetExposure(IntPtr deviceHandle, int paramIndex, double exposure);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetGain", CharSet = CharSet.Ansi)]     //设置增益
        public static extern long IDDevice_SetGain(IntPtr deviceHandle, int paramIndex, int gain);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetGamma", CharSet = CharSet.Ansi)]     //设置伽马
        public static extern long IDDevice_SetGamma(IntPtr deviceHandle, int paramIndex, double gamma);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetIlluminate", CharSet = CharSet.Ansi)]     //设置通道亮度:通道数,设置-1或小于0,表示同时设置所有通道
        public static extern long IDDevice_SetIlluminate(IntPtr deviceHandle, int paramIndex, int channel, int value);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetIlluminateEnable", CharSet = CharSet.Ansi)]     //设置通道使能:通道数,设置-1或小于0,表示同时设置所有通道
        public static extern long IDDevice_SetIlluminateEnable(IntPtr deviceHandle, int paramIndex, int channel, bool enable);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetIlluminanatbrightnessLength", CharSet = CharSet.Ansi)]//获取illuminanatbrightness æ•°é‡
        public static extern long IDDevice_GetIlluminanatbrightnessLength(IntPtr deviceHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetIlluminanatbrightness", CharSet = CharSet.Ansi)] //获取illuminanatbrightness
        public static extern IDNodeParam IDDevice_GetIlluminanatbrightness(IntPtr deviceHandle, uint index);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetTriggerAllParams", CharSet = CharSet.Ansi)] //获取所有触发参数
        public static extern long IDDevice_GetTriggerAllParams(IntPtr deviceHandle, ref IDTriggerParams triggerParams, ref IDHardwareTrigger hardwareTrigger,
           ref IDTcpServerTrigger tcpServerTrigger, ref IDTcpClientTrigger tcpClientTrigger, ref IDSerialPortTrigger serialPortTrigger, ref IDUDPTrigger udpTrigger);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetDataconfigAllParams", CharSet = CharSet.Ansi)] //获取所有数据处理参数
        public static extern long IDDevice_GetDataconfigAllParams(IntPtr deviceHandle, ref IDFilterInfo filterInfo, ref IDFilterRules filterRules, ref IDDataConfig dataConfig);
        //[DllImport("IDViewerCSDK.dll", EntryPoint = "getTriggerAllParams", CharSet = CharSet.Ansi)]
        //public static extern long getTriggerAllParams(IntPtr deviceHandle, IDTriggerParams triggerParams, IDHardwareTrigger hardwareTrigger,
        //    IDTcpServerTrigger tcpServerTrigger, IDTcpClientTrigger tcpClientTrigger, IDSerialPortTrigger serialPortTrigger, IDUDPTrigger udpTrigger);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetCommunicationAllParams", CharSet = CharSet.Ansi)] //获取所有通信参数
        public static extern long IDDevice_GetCommunicationAllParams(IntPtr deviceHandle, ref IDTcpServerCommunication tcpServerInfo, ref IDTcpClientCommunication tcpClientInfo, ref IDSerialPortCommunication serialPortInfo,
            ref IDKeyboardConfig keyboardInfo, ref IDEipConfig eipConfig, ref IDModbusConfig modbusConfig, ref IDProfinetConfig profinetConfig, ref IDFtpConfig ftpConfig, ref IDWebpageConfig webpageConfig,
            ref IDFinsConfig finsConfig, ref IDHttpConfig httpConfig, ref IDNetworkingConfig networkingConfig);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetCommunicationAllParams_V2", CharSet = CharSet.Ansi)] //获取所有通信参数
        public static extern long IDDevice_GetCommunicationAllParams_V2(IntPtr deviceHandle, ref IDTcpServerCommunication tcpServerInfo, ref IDTcpClientCommunication tcpClientInfo, ref IDSerialPortCommunication serialPortInfo,
            ref IDKeyboardConfig keyboardInfo, ref IDEipConfig eipConfig, ref IDModbusConfig modbusConfig, ref IDProfinetConfig profinetConfig, ref IDFtpConfig ftpConfig, ref IDWebpageConfig webpageConfig,
            ref IDFinsConfig finsConfig, ref IDHttpConfig httpConfig, ref IDNetworkingConfig networkingConfig, ref IDMcConfig mcConfig, ref IDUdpConfig iDUdpConfig);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DownLoadCurrentSolution", CharSet = CharSet.Ansi)] //下载当前方案 å‚数设置为临时设置,需要调用该方法才能保存到设备离线生效
        public static extern long IDDevice_DownLoadCurrentSolution(IntPtr deviceHandle);
        /**
        * @brief uploadSolution                             ä¸Šä¼ æ–¹æ¡ˆ
        * @param solutionData                               æ–¹æ¡ˆæ•°æ®
        * @param solutionName                               æ–¹æ¡ˆåç§°
        * @param timeout                                    è¶…æ—¶æ—¶é—´
        * @return                                           é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_UploadSolution", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_UploadSolution(IntPtr deviceHandle, string solutionData, string solutionName, int timeout = 3000);
        /**
         * @brief downLoadSolution                          ä¸‹è½½æ–¹æ¡ˆ
         * @param solutionData                              æ–¹æ¡ˆæ•°æ®
         * @param solutionName                              æ–¹æ¡ˆåç§°
         * @param timeout                                   è¶…æ—¶æ—¶é—´
         * @return                                          é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DownLoadSolution", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DownLoadSolution(IntPtr deviceHandle, ref string solutionData, string solutionName, int timeout = 3000);
        /**
        * @brief openMC                            æ‰“å¼€MC
        * @param mode                           MC å“ç‰Œåž‹å·ï¼ˆå–值范围:(Mitsubishi_L:0,Mitsubishi_Q:1,Mitsubishi_R:2,Mitsubishi_A:4,Mitsubishi_Fx3U:5,Mitsubishi_Fx5U:6))
        * @param format                         MC æ ¼å¼ ï¼ˆå–值范围:BIN:0,ASCII:1)
        * @param ip                                MC IP地址
        * @param port                            MC ç«¯å£
        * @param startAddress                   MC èµ·å§‹åœ°å€
        * @param resultSwap                     MC ç»“果交换
        * @param resultSize                     MC ç»“果大小
        * @param timeout                        MC MC结果超时
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_OpenMC", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_OpenMC(IntPtr deviceHandle, IDMcBrandModel mode, IDMcDataFormat format, string ip, int port, int startAddress, bool resultSwap, int resultSize, int timeout);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_CloseMC", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_CloseMC(IntPtr deviceHandle);
        /**
        * @brief getMcInfo                        èŽ·å–å½“å‰MC连接配置信息
        * @param mode                           MC品牌型号
        * @param format                         MC格式(BIN/ASCII)
        * @param ip                             MC的IP地址
        * @param port                           MC的端口
        * @param startAddress                   MC起始地址
        * @param resultSwap                     MC结果交换配置
        * @param resultSize                     MC结果大小
        * @param timeout                        MC结果超时时间
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetMcInfo", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetMcInfo(IntPtr deviceHandle, ref IDMcBrandModel mode, ref IDMcDataFormat format, ref string ip, ref int port, ref int startAddress, ref bool resultSwap, ref int resultSize, ref int timeout);
        /*
        * 2025.2.15 æ–°å¢žIDDevice类接口
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_ClearROI", CharSet = CharSet.Ansi)]  //清除所有ROI
        public static extern long IDDevice_ClearROI(IntPtr deviceHandle);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AddImageROI", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_AddImageROI(IntPtr deviceHandle, ref IDImageROI roiInfos); //添加图像ROI
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteImageROI", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DeleteImageROI(IntPtr deviceHandle, int roiIndex); //删除图像ROI
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetROICodeNum", CharSet = CharSet.Ansi)] //设置指定 ROI çš„码数目
        public static extern long IDDevice_SetROICodeNum(IntPtr deviceHandle, int roiIndex, int codeNum);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_ModifyImageROI", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_ModifyImageROI(IntPtr deviceHandle, int roiIndex, IDPoint topLeftPoint, IDPoint bottomRightPoint);//更新图像ROI
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetImageROIsLength", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetImageROIsLength(IntPtr deviceHandle);//获取图像ROI列表长度
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetImageROIsInfo", CharSet = CharSet.Ansi)]
        public static extern IDImageROI IDDevice_GetImageROIsInfo(IntPtr deviceHandle, uint index);//获取图像ROI
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_ClearImageROI", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_ClearImageROI(IntPtr deviceHandle);//清除所有图像ROI
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AddCodeType", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_AddCodeType(IntPtr deviceHandle, IDCodeType type);//添加码制
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteCodeType", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DeleteCodeType(IntPtr deviceHandle, IDCodeType type);//删除码制
        /**
        * @brief clearCodeType                æ¸…除所有码制
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_ClearCodeType", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_ClearCodeType(IntPtr deviceHandle);
        /**
          * @brief getImageROIs                èŽ·å–ç åˆ¶ä¿¡æ¯åˆ—è¡¨é•¿åº¦
          * @param
          * @return                             èŽ·å–ç åˆ¶ä¿¡æ¯åˆ—è¡¨é•¿åº¦
          */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetCodeTypesLength", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetCodeTypesLength(IntPtr deviceHandle);
        /**
          * @brief getImageROIs               èŽ·å–ç åˆ¶ä¿¡æ¯
          * @param index                    ç¬¬å‡ ä¸ªIDCodeType_C信息
          * @return                            IDCodeType_C
          */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetCodeTypesInfo", CharSet = CharSet.Ansi)]
        public static extern IDCodeType IDDevice_GetCodeTypesInfo(IntPtr deviceHandle, uint index);
        /**
        * @brief setCodeCategoryParam       è®¾ç½®æ¡ç ç®—法参数
        * @param codeType                    æ¡ç ç±»åž‹
        * @param codeParam                    æ¡ç å‚数信息
        * @return                            é”™è¯¯ç 
*/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetCodeCategoryParam", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetCodeCategoryParam(IntPtr deviceHandle, IDCodeCategory codeType, IntPtr codeParam);
        /**
         * @brief getSolutionImageParams        èŽ·å–å½“å‰æ–¹æ¡ˆå›¾åƒè®¾ç½®é¡µå‚æ•°
         * @param solutionImage                å›¾åƒé¡µå‚æ•° //图像参数
         * @return                            é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetSolutionImage", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetSolutionImage(IntPtr deviceHandle, ref IDSolutionImage solutionImage);
        /**
         * @brief getSolutionImageParams        èŽ·å–å›¾åƒå‚æ•°ç»„éƒ¨åˆ†å‚æ•°
         * @param solutionImageParams                å›¾åƒå‚数组部分参数
         * @param index                                    å‚数组第几个参数
         * @return                            é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetSolutionImageParams", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetSolutionImageParams(IntPtr deviceHandle, int index, ref IDSolutionImageParams solutionImageParams);
        /**
         * @brief getSolutionImageParams        èŽ·å–å›¾åƒå…‰æºé€šé“å‚æ•°
         * @param solutionImageParams            å›¾åƒå‚数组部分参数
         * @param index                            å‚数组第几个参数
         * @param illIndex                        å‚数组第几个参数的第几个光源通道参数
         * @return                                é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetSolutionImageIlluminant", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetSolutionImageIlluminant(IntPtr deviceHandle, int index, int illIndex, ref IDSolutionImageIlluminant solutionImageIlluminant);
        /**
        * @brief appendLastImageParam        åŸºäºŽæœ€åŽä¸€ä¸ªå‚数节点新增图像参数组
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_AppendLastImageParam", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_AppendLastImageParam(IntPtr deviceHandle);
        /**
        * @brief deleteImageParamAtIndex    åˆ é™¤å›¾åƒå‚数组
        * @param paramIndex                    å‚数组序号
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteImageParamAtIndex", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_DeleteImageParamAtIndex(IntPtr deviceHandle, int paramIndex);
        /**
        * @brief setAutoExposureEnabled        è®¾ç½®ä½¿èƒ½è‡ªåŠ¨æ›å…‰
        * @param enabled                    æ˜¯å¦å¯ç”¨è‡ªåŠ¨æ›å…‰ï¼Œ`true` ä¸ºå¯ç”¨ï¼Œ`false` ä¸ºç¦ç”¨
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetAutoExposureEnabled", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetAutoExposureEnabled(IntPtr deviceHandle, bool enabled);
        /**
        * @brief getExposure                èŽ·å–å½“å‰æ›å…‰
        * @param exposure                    æ›å…‰å€¼
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetExposure", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetExposure(IntPtr deviceHandle, ref double exposure);
        /**
        * @brief setAutoGainEnabled            è®¾ç½®ä½¿èƒ½è‡ªåŠ¨å¢žç›Š
        * @param enabled                    æ˜¯å¦å¯ç”¨è‡ªåŠ¨å¢žç›Šï¼Œ`true` ä¸ºå¯ç”¨ï¼Œ`false` ä¸ºç¦ç”¨
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetAutoGainEnabled", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetAutoGainEnabled(IntPtr deviceHandle, bool enabled);
        /**
        * @brief getGainCount                èŽ·å–å¢žç›Šåˆ—è¡¨ä¸ªæ•°
        * @param count                        å¢žç›Šåˆ—表个数
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetGainCount", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetGainCount(IntPtr deviceHandle, ref int count);
        /**
        * @brief getGain                    èŽ·å–å½“å‰å¢žç›Š
        * @param gain                        å¢žç›Š
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetGain", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetGain(IntPtr deviceHandle, ref int gain);
        /**
        * @brief getGain                    èŽ·å–å½“å‰å¢žç›Š
        * @param paramIndex                    å‚数组
        * @param gain                        å¢žç›Šå€¼
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetGain_1330", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetGain_1330(IntPtr deviceHandle, int paramIndex, ref double gain);
        /**
        * @brief getGain                    èŽ·å–å¢žç›Šåˆ—è¡¨ä¸­æŒ‡å®šä¸‹æ ‡å¯¹åº”çš„å¢žç›Šå€¼
        * @param index                        å¢žç›Šå€¼åœ¨åˆ—表中的索引
        * @param gain                        å¢žç›Šå€¼
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetGainValueByIndex_1330", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetGainValueByIndex_1330(IntPtr deviceHandle, int paramIndex, ref double gain);
        /**
        * @brief getGamma                    èŽ·å–å½“å‰ä¼½é©¬
        * @param gamma                        ä¼½é©¬å€¼
        * @return                            é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetGamma", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_GetGamma(IntPtr deviceHandle, ref double gamma);
        /**
        * @brief setDIParam                    è®¾ç½®DI参数
        * @param pin                        å¼•脚编号
        * @param params                        DI参数信息
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetDIParam", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetDIParam(IntPtr deviceHandle, uint pin, ref IDDIParams iDDIParams);
        /**
        * @brief setDOParam                    è®¾ç½®DO参数
        * @param pin                        å¼•脚编号
        * @param params                        DO参数信息
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetDOParam", CharSet = CharSet.Ansi)]
        public static extern long IDDevice_SetDOParam(IntPtr deviceHandle, uint pin, IDDOParams iDDOParams);
        /*
        * @brief getIOConfigAllParams        èŽ·å–æ‰€æœ‰IO输入参数信息长度
        * @
        * @
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "getIOConfigInputParamsLength", CharSet = CharSet.Ansi)]
        public static extern long getIOConfigInputParamsLength(IntPtr deviceHandle);
        /*
        * èŽ·å–IO输入参数信息
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "getIOConfigInputParamsInfo", CharSet = CharSet.Ansi)]
        public static extern long getIOConfigInputParamsInfo(IntPtr deviceHandle, uint index, ref IDDIParams IDDIParams);
        /* @brief getIOConfigAllParams        èŽ·å–æ‰€æœ‰IO输出参数信息长度
        * @
        * @
        * @return
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "getIOConfigOutputParamsLength", CharSet = CharSet.Ansi)]
        public static extern long getIOConfigOutputParamsLength(IntPtr deviceHandle);
        /**
       * @brief addDOParam                                        æ·»åŠ DO参数
       * @param params                                                DO参数信息
       * @return
       */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "addDOParam", CharSet = CharSet.Ansi)]
        public static extern long addDOParam(IntPtr deviceHandle, ref IDDOParams iDDOParams);
        /*
        * èŽ·å–IO输出参数信息
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "getIOConfigOutputParamsInfo", CharSet = CharSet.Ansi)]
        public static extern long getIOConfigOutputParamsInfo(IntPtr deviceHandle, uint index, ref IDDOParams IDDOParams);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_ResultNotify_")]
        public static extern void IDCallback_ResultNotify_(IntPtr deviceHandle, IntPtr resCallback);   // ç»“果回调函数
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_ResultNotify_Image_")]
        public static extern void IDCallback_ResultNotify_Image_(IntPtr deviceHandle, IntPtr resCallback); // å›¾ç‰‡å›žè°ƒå‡½æ•°
        //[DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeInfo")]
        //public extern static IntPtr IDCallback_GetIDDecodeInfo(IntPtr decodeInfoHandel);  //IDCallback_GetIDDecodeInfo
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeInfo_A")]
        public extern static long IDCallback_GetIDDecodeInfo_A(IntPtr decodeInfoHandel, ref IDDecodeInfo info);  //IDCallback_GetIDDecodeInfo
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeROIInfo", CharSet = CharSet.Ansi)]
        public static extern IDDecodeROIInfo IDCallback_GetIDDecodeROIInfo(IntPtr decodeInfoHandel, uint index);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeResult", CharSet = CharSet.Ansi)]
        public static extern IDDecodeResult IDCallback_GetIDDecodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex, uint index);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDMCodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDDMCodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,                            //DM解码数据
             uint index, ref IDDMCodeResult IDDMCodeResultData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_CheckDeCodeTypeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_CheckDeCodeTypeResult(IntPtr decodeInfoHandel, uint decodeType, uint decodeROIInfoIndex); //详细码类型的结果长度 ,0表示没有解码结果,-1 è¡¨ç¤ºroi不存在
        //[DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetID_QRODE_Result", CharSet = CharSet.Ansi)]
        //public static extern long IDCallback_GetID_QRODE_Result(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,                           //QR解码数据
        //     uint index, ref IDQRCodeResult iDQRCodeResult);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDMCodeResult_QualityDM15415", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDDMCodeResult_QualityDM15415(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,             //15414dm码质量
            uint index, ref IDQualityDM15415 iDQualityDM15415);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDMCodeResult_QUALITY_DM_29158", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDDMCodeResult_QUALITY_DM_29158(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,           //29158dm码质量
            uint index, ref IDQualityDM29518 iDQualityDM29518);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDPDF417CodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDPDF417CodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint index, ref IDPDF417CodeResult iDPDF417CodeResultData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetID_QR_CODE_Result", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetID_QR_CODE_Result(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint index, ref IDQRCodeResult iDQRCodeResult);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetID_QR_CODE_Result_IDQualityQR15415", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetID_QR_CODE_Result_IDQualityQR15415(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,        //15414qr码质量
            uint index, ref IDQualityQR15415 iDQualityQR15415);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetID_QR_CODE_Result_IDQualityQR29518", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetID_QR_CODE_Result_IDQualityQR29518(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,        //29518qr码质量
            uint index, ref IDQualityQR29518 iDQualityQR29518);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDPDF417CodeResult_IDQualityPDF417_15415", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDPDF417CodeResult_IDQualityPDF417_15415(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint index, ref IDQualityPDF417_15415 iDQualityPDF417_15415);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDBarCodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDBarCodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
             uint index, ref IDBarCodeResult iDBarCodeResultData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDBarCodeResult_IDQuality15416", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDBarCodeResult_IDQuality15416(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint index, ref IDQuality15416 iDQuality15416);
        /*
        * decodeInfoHandel å¥æŸ„
        * decodeType è§£ç ç±»åž‹ æ¯”如 1dm ï¼Œ2 qr,3 pdf417,4 barcode
        * decodeROIInfoIndex roi ç¬¬å‡ ä¸ªroi
        * index ç¬¬å‡ ä¸ªå…·ä½“解码类型结果
        * pointIndex第几个点
        * Position ç‚¹æ•°æ®
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDResultPosition", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDResultPosition(IntPtr decodeInfoHandel, uint decodeType, uint decodeROIInfoIndex,
            uint index, uint pointIndex, ref IDPoint iDPoint);
        /**
        * @brief IDVIEWER_Init ä½¿ç”¨SDK其他功能前需要先调用该初始化方法
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_Init_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_Init_();
        /**
        * @brief IDVIEWER_DiscoveryDevices æ‰«æè®¾å¤‡åˆ—表
        * @param deviceList    è¿”回获取的设备列表
        * @param discoveryTime æ‰«æå‘¨æœŸ,默认200(单位毫秒)
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_DiscoveryDevices_", CharSet = CharSet.Ansi)]
        public extern static IntPtr IDVIEWER_DiscoveryDevices_(uint discoveryTime = 1000);
        /**
         * @brief IDVIEWER_GetDevicesLength_ è®¾å¤‡åˆ—表长度
         * @param deviceList    è¿”回获取的设备列表长度
         *
         * @return é•¿åº¦
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_GetDevicesLength_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_GetDevicesLength_(IntPtr DevicesList);
        /**
         * @brief IDVIEWER_SelectIDDeviceInfo_ èŽ·å–æŸä¸ªåºå·çš„è®¾å¤‡
         * @param DevicesList å½“前设备列表指针
         * @param index    è®¾å¤‡åˆ—表的序号
         * @return è®¾å¤‡ä¿¡æ¯
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_SelectIDDeviceInfo_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_SelectIDDeviceInfo_(IntPtr DevicesList, ref IDDeviceInfo IDDeviceInfoHandel, uint index);
        /**
        * @brief IDVIEWER_SetIP è®¾ç½®IP è®¾ç½®IP后需要重新扫描
        * @param deviceInfo å½“前设备信息
        * @param iPv4    æ–°çš„IP地址
        * @param mask    æ–°çš„MASK地址
        * @param gateway æ–°çš„网关地址
        * @param isStatic æ˜¯å¦è®¾ç½®é™æ€IP(false为临时IP)
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_SetIP_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_SetIP_(ref IDViewerDefines.IDDeviceInfo deviceInfo, string iPv4, string mask, string gateway, bool isStatic);
        /**
        * @brief IDVIEWER_CreateDevice CreateDevice åˆ›å»ºè®¾å¤‡
        * @param deviceInfo å½“前设备信息
        * @param device åˆ›å»ºçš„设备指针
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_CreateDevice_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_CreateDevice_(ref IDViewerDefines.IDDeviceInfo deviceInfo, ref IntPtr deviceHandle);
        /**
         * @brief IDVIEWERreateDevice IDVIEWERreateDeviceBySN æ›´åŠ SN创建设备
         * @param cameraSN å½“前设备SN
         * @param device åˆ›å»ºçš„设备指针
         * @return é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_CreateDeviceBySN_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_CreateDeviceBySN_(string cameraSN, ref IntPtr deviceHandle);
        /**
         * @brief IDVIEWERreateDevice IDVIEWERreateDeviceByIP æ›´åŠ SN创建设备
         * @param cameraIP å½“前设备IP
         * @param device åˆ›å»ºçš„设备指针
         * @return é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_CreateDeviceByIP_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_CreateDeviceByIP_(string cameraIP, ref IntPtr deviceHandle);
        /**
        * @brief IDVIEWER_UnInit ä½¿ç”¨å®ŒSDK后调用释放资源
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_UnInit_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_UnInit_(IntPtr deviceList);
    }
}
IDViewer_2D/IDViewerSDK1.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using static IDViewer_2D.IDViewerDefines;
namespace IDViewer_2D
{
    class IDViewerSDK
    {
        public class Node
        {
            public IDViewerDefines.IDDeviceInfo data;
            public Node next;
        }
        public struct LinkedList
        {
            public Node head;
            [MarshalAs(UnmanagedType.SysInt)]
            public int size;
        }
        /****************************************
         IDImage
        //*****************************************/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Init", CharSet = CharSet.Ansi)]
        public static extern long IDImage_Init(ref IntPtr imagePtr);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Destroy", CharSet = CharSet.Ansi)]
            public static extern void IDImage_Destroy(ref IntPtr imagePtr);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Width", CharSet = CharSet.Ansi)]
            public static extern long IDImage_Width(IntPtr imageHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Height", CharSet = CharSet.Ansi)]
            public static extern long IDImage_Height(IntPtr imageHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Step", CharSet = CharSet.Ansi)]
            public static extern long IDImage_Step(IntPtr imageHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_BitDepth", CharSet = CharSet.Auto)]
            public static extern long IDImage_BitDepth(IntPtr imageHandle,ref IntPtr imageType);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_Channels", CharSet = CharSet.Ansi)]
            public static extern long IDImage_Channels(IntPtr imageHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_ImageData", CharSet = CharSet.Ansi)]
            public static extern IntPtr IDImage_ImageData(IntPtr imageHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_SaveImage", CharSet = CharSet.Ansi)]
            public static extern long IDImage_SaveImage(IntPtr imageHandle, string filePath, int compression);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDImage_SaveImageW", CharSet = CharSet.Unicode)]
            public static extern long IDImage_SaveImageW(IntPtr imageHandle, string filePath, int compression);
            /****************************************
            IDDevice
            *****************************************/
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Open", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_Open(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsOpen", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_IsOpen(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_StartRunning", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_StartRunning(IntPtr deviceHandle,int isCallBack);  //isCallBack>0 æ³¨å†Œå›žè°ƒï¼Œç­‰äºŽ0 ä¸æ³¨å†Œå›žè°ƒ
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_StartDebugging", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_StartDebugging(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsRunning", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_IsRunning(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_IsConnected", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_IsConnected(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Stop", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_Stop(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Close", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_Close(IntPtr deviceHandle);
        /****************************************
        DeviceInfo
        *****************************************/
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetDeviceInfo", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_GetDeviceInfo(IntPtr deviceHandle, ref IDDeviceInfo DeviceInfoHandel);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetHardWareParams", CharSet = CharSet.Ansi)]
            public static extern IDViewerDefines.IDDeviceHarewareParams IDDevice_GetHardWareParams(IntPtr deviceHandle);
            //此接口需要VS2019以上版本,C#7.0更新支持引入了新的语法ref return和ref locals,允许函数的返回值也可以被声明为引用
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetSolutionList", CharSet = CharSet.Ansi)]
            public static extern ref StringList  IDDevice_GetSolutionList(IntPtr deviceHandle,  int timeout = 2000);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_SetRunningSolution", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_SetRunningSolution(IntPtr deviceHandle,byte[] solutionName, int timeout = 2000);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetRunningSolution", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_GetRunningSolution(IntPtr deviceHandle, byte[] solutionName, int timeout = 2000);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_DeleteSolution", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_DeleteSolution(IntPtr deviceHandle, string solutionName, int timeout = 2000);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_Release", CharSet = CharSet.Ansi)]
            public static extern void IDDevice_Release(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_FreeSolutionList", CharSet = CharSet.Ansi)]
            public static extern void IDDevice_FreeSolutionList(StringList solutionList);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetIlluminanatbrightnessLength", CharSet = CharSet.Ansi)]
            public static extern long IDDevice_GetIlluminanatbrightnessLength(IntPtr deviceHandle);
            [DllImport("IDViewerCSDK.dll", EntryPoint = "IDDevice_GetIlluminanatbrightness", CharSet = CharSet.Ansi)]
            public static extern IDNodeParam IDDevice_GetIlluminanatbrightness(IntPtr deviceHandle, uint index);
        //回调函数
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_ResultNotify_")]
        public static extern void IDCallback_ResultNotify_(IntPtr deviceHandle, IntPtr resCallback);
        //[DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeInfo")]
        //public extern static IntPtr IDCallback_GetIDDecodeInfo(IntPtr decodeInfoHandel);  //IDCallback_GetIDDecodeInfo
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeInfo_A")]
        public extern static long IDCallback_GetIDDecodeInfo_A(IntPtr decodeInfoHandel,ref IDDecodeInfo info);  //IDCallback_GetIDDecodeInfo
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeROIInfo", CharSet = CharSet.Ansi)]
        public static extern IDDecodeROIInfo IDCallback_GetIDDecodeROIInfo(IntPtr decodeInfoHandel, uint index);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDecodeResult", CharSet = CharSet.Ansi)]
        public static extern IDDecodeResult IDCallback_GetIDDecodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex, uint index);
        /*
         *decodeROIInfoIndex ç¬¬å‡ ä¸ªROI
         *decodeResultIndex  å…ˆå¿½ç•¥ï¼Œ
         *index  ROI内的第几个成功解码结果
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDDMCodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDDMCodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint decodeResultIndex, uint index, ref IDDMCodeResult IDDMCodeResultData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetID_QR_CODE_Result", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetID_QR_CODE_Result(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint decodeResultIndex, uint index,  ref IDQRCodeResult ID_QR_CODE_RESULTData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDPDF417CodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDPDF417CodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint decodeResultIndex, uint index, ref IDPDF417CodeResult IDPDF417CodeResultData);
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDCallback_GetIDBarCodeResult", CharSet = CharSet.Ansi)]
        public static extern long IDCallback_GetIDBarCodeResult(IntPtr decodeInfoHandel, uint decodeROIInfoIndex,
            uint decodeResultIndex, uint index, ref IDBarCodeResult IDBarCodeResultData);
        /**
        * @brief IDVIEWER_Init ä½¿ç”¨SDK其他功能前需要先调用该初始化方法
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_Init_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_Init_();
        /**
        * @brief IDVIEWER_DiscoveryDevices æ‰«æè®¾å¤‡åˆ—表
        * @param deviceList    è¿”回获取的设备列表
        * @param discoveryTime æ‰«æå‘¨æœŸ,默认200(单位毫秒)
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_DiscoveryDevices_", CharSet = CharSet.Ansi)]
        public extern static IntPtr IDVIEWER_DiscoveryDevices_(uint discoveryTime = 200);
        /**
         * @brief IDVIEWER_GetDevicesLength_ è®¾å¤‡åˆ—表长度
         * @param deviceList    è¿”回获取的设备列表长度
         *
         * @return é•¿åº¦
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_GetDevicesLength_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_GetDevicesLength_(IntPtr DevicesList);
        /**
         * @brief IDVIEWER_SelectIDDeviceInfo_ èŽ·å–æŸä¸ªåºå·çš„è®¾å¤‡
         * @param DevicesList å½“前设备列表指针
         * @param index    è®¾å¤‡åˆ—表的序号
         * @return è®¾å¤‡ä¿¡æ¯
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_SelectIDDeviceInfo_", CharSet = CharSet.Ansi)]
        public extern static long IDVIEWER_SelectIDDeviceInfo_(IntPtr DevicesList, ref IDDeviceInfo IDDeviceInfoHandel, uint index);
        /**
        * @brief IDVIEWER_SetIP è®¾ç½®IP è®¾ç½®IP后需要重新扫描
        * @param deviceInfo å½“前设备信息
        * @param iPv4    æ–°çš„IP地址
        * @param mask    æ–°çš„MASK地址
        * @param gateway æ–°çš„网关地址
        * @param isStatic æ˜¯å¦è®¾ç½®é™æ€IP(false为临时IP)
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_SetIP_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_SetIP_(ref IDViewerDefines.IDDeviceInfo deviceInfo, string iPv4, string mask, string gateway, bool isStatic);
        /**
         * @brief IDVIEWER_CreateDevice IDVIEWER_CreateDeviceBySN æ›´åŠ SN创建设备
         * @param cameraSN å½“前设备SN
         * @param device åˆ›å»ºçš„设备指针
         * @return é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_CreateDeviceBySN_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_CreateDeviceBySN_(string cameraSN, ref IntPtr deviceHandle);
        /**
         * @brief IDVIEWER_CreateDevice IDVIEWER_CreateDeviceByIP æ›´åŠ SN创建设备
         * @param cameraIP å½“前设备IP
         * @param device åˆ›å»ºçš„设备指针
         * @return é”™è¯¯ç 
         */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_CreateDeviceByIP_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_CreateDeviceByIP_(string cameraIP, ref IntPtr deviceHandle);
        /**
        * @brief IDVIEWER_UnInit ä½¿ç”¨å®ŒSDK后调用释放资源
        * @return é”™è¯¯ç 
        */
        [DllImport("IDViewerCSDK.dll", EntryPoint = "IDVIEWER_UnInit_", CharSet = CharSet.Ansi)]
        public static extern long IDVIEWER_UnInit_(IntPtr deviceList);
    }
}
IDViewer_2D/IDViewerSDK2.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static SmartScanner.IDViewerDefines;
using System.IO;
using System.Drawing;
namespace SmartScanner
{
    class IDViewerSDK2
    {
        [DllImport("yolov8_ov_infer.dll", EntryPoint = "CreateDetector_CPU", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr CreateDetector_CPU();
        [DllImport("yolov8_ov_infer.dll", EntryPoint = "InitializeDetector_CPU", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern bool InitializeDetector_CPU(IntPtr m_yolov8, string device_char, string model_path_char);
        [DllImport("yolov8_ov_infer.dll", EntryPoint = "PredictDetector_CPU", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void PredictDetector_CPU(IntPtr m_yolov8,
            byte[] image_batch,
            float[] x1_ptr,
            float[] y1_ptr,
            float[] x2_ptr,
            float[] y2_ptr,
            float[] prob_ptr,
            int[] class_ptr,
            int[] num_boxes,
            int buffer_size,
            int width,
            int height,
            int batch_size,
            float conf_thresh,
            float nms_thres,
            int is_Saved,
            int sequence);
        [DllImport("yolov8_ov_infer.dll", EntryPoint = "DisposeDetector_CPU", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void DisposeDetector_CPU(IntPtr m_yolov8);
        [DllImport("yolov8_ov_infer.dll", EntryPoint = "ConvertSingletoThreeChannels", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void ConvertSingletoThreeChannels(IntPtr m_yolov8, byte[] input, int width, int height, byte[] output);
        //OPT提供的C++SDK
        [DllImport("optSDK.dll", EntryPoint = "IDImage_Create", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr IDImage_Create();
        [DllImport("IDViewerSDK.dll", EntryPoint = "IDImage", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern long IDImage(byte[] srcImageData, int step, int rows, int cols, int channel, IDImageType depth);
        [DllImport("IDViewerSDK.dll", EntryPoint = "captureImage", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern long captureImage(IntPtr image);
    }
}
IDViewer_2D/Image/Currency/MTV3Dlogo.ico
IDViewer_2D/Image/Currency/logo.png
IDViewer_2D/Image/Currency/logo_01.png
IDViewer_2D/Image/Currency/logo_02.png
IDViewer_2D/Image/Currency/ɾ³ý.png
IDViewer_2D/Image/Currency/Ë¢ÐÂ.png
IDViewer_2D/Image/Currency/µ¥ÕÅץͼ.png
IDViewer_2D/Image/Currency/´æ´¢Í¼Æ¬.png
IDViewer_2D/Image/Currency/Ðû´«Í¼.png
IDViewer_2D/Image/Currency/¿ªÊ¼²É¼¯.jpg
IDViewer_2D/Image/Currency/´ò¿ªÎļþ.png
IDViewer_2D/Image/Currency/¶Ï¿ª.png
IDViewer_2D/Image/Currency/ÔÝÍ£.png
IDViewer_2D/Image/Currency/Á¬½Ó.png
IDViewer_2D/Image/Currency/Á¬Ðø×¥Í¼.png
IDViewer_2D/Image/Currency/²É¼¯.png
IDViewer_2D/Image/ICON/camera-switch-fill.png
IDViewer_2D/Image/ICON/folder-2-fill.png
IDViewer_2D/Image/ICON/folder-open-fill.png
IDViewer_2D/Image/ICON/import-fill.png
IDViewer_2D/Image/ICON/link-m.png
IDViewer_2D/Image/testImages/20220706201141516.jpg
IDViewer_2D/Image/testImages/20220706201152065.jpg
IDViewer_2D/Image/testImages/20220719092357348.jpg
IDViewer_2D/Image/testImages/20221013101729295.jpg
IDViewer_2D/Image/testImages/20221018190453100.jpg
IDViewer_2D/ImageDisplayWindow .xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
<Window x:Class="SmartScanner.ImageDisplayWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:opencvsharp1="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
        mc:Ignorable="d"
        Title="ImageDisplayWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="10*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
        <opencvsharp1:Image x:Name="ResultImage" Grid.Column="1" Grid.Row="0" Stretch="Uniform"/>
            <!--<StackPanel Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Center">-->
            <Button x:Name="PrevButton" Content="&lt;" Grid.Row="0" Grid.Column="0"  HorizontalAlignment="Stretch"
                    BorderThickness="0" FontSize="48" Click="PrevButton_Click" Background="{x:Null}" BorderBrush="{x:Null}" >
                    <!--<TextBox Text="&lt;" HorizontalAlignment="Center"  VerticalAlignment="Center" FontSize="48" BorderBrush="{x:Null}">
                    </TextBox>-->
                </Button>
            <!--</StackPanel>-->
            <!--<StackPanel Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center">-->
            <Button x:Name="NextButton" Content=">" Click="NextButton_Click"  FontSize="48"
                    BorderThickness="0" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" Background="White" BorderBrush="{x:Null}" >
                    <!--<TextBox Text=">" HorizontalAlignment="Center"  VerticalAlignment="Center" FontSize="48" BorderBrush="{x:Null}">
                    </TextBox>-->
                </Button>
            <!--</StackPanel>-->
        </Grid>
        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
            <!--<Button x:Name="PrevButton" Content="上一张" Width="80" Margin="10" Click="PrevButton_Click"/>-->
            <!--<Button x:Name="NextButton" Content="下一张" Width="80" Margin="10" Click="NextButton_Click"/>-->
        </StackPanel>
    </Grid>
</Window>
IDViewer_2D/ImageDisplayWindow .xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SmartScanner
{
    /// <summary>
    /// ImageDisplayWindow.xaml çš„交互逻辑
    /// </summary>
    public partial class ImageDisplayWindow : System.Windows.Window
    {
        private List<string> _imagePaths = new List<string>();
        private int _currentIndex = -1;
        public ImageDisplayWindow()
        {
            InitializeComponent();
        }
        public void AddImage(List<string> imagePath)
        {
            for (int i = 0; i < imagePath.Count; i++)
            {
                if (!File.Exists(imagePath[i]))
                {
                    MessageBox.Show($"图片不存在: {imagePath}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
            }
            // æ·»åŠ åˆ°åˆ—è¡¨
            //_imagePaths = imagePath;
            _imagePaths = new List<string>(imagePath);
            ShowImage(0);
        }
        private void ShowImage(int index)
        {
            if (index < 0 || index >= _imagePaths.Count) return;
            _currentIndex = index;
            string imagePath = _imagePaths[index];
            try
            {
                // ä½¿ç”¨OpenCvSharp读取图片
                using (Mat image = Cv2.ImRead(imagePath, ImreadModes.Color))
                {
                    if (image.Empty())
                    {
                        throw new Exception("图片加载失败");
                    }
                    // ä½¿ç”¨Dispatcher确保UI线程更新
                    Dispatcher.Invoke(() =>
                    {
                        ResultImage.Source = image.ToBitmapSource();
                        Title = $"图片查看 ({index + 1}/{_imagePaths.Count}) - {System.IO.Path.GetFileName(imagePath)}";
                        // æ›´æ–°æŒ‰é’®çŠ¶æ€
                        PrevButton.IsEnabled = index > 0;
                        NextButton.IsEnabled = index < _imagePaths.Count - 1;
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载图片失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private void PrevButton_Click(object sender, RoutedEventArgs e)
        {
            ShowImage(_currentIndex - 1);
        }
        private void NextButton_Click(object sender, RoutedEventArgs e)
        {
            ShowImage(_currentIndex + 1);
        }
        public bool ShowImage_main(string imagePath)
        {
            try
            {
                // ä½¿ç”¨OpenCvSharp读取图片
                using (Mat image = Cv2.ImRead(imagePath, ImreadModes.Color))
                {
                    if (image.Empty())
                    {
                        return false;
                    }
                    // ä½¿ç”¨Dispatcher确保UI线程更新
                    Dispatcher.Invoke(() =>
                    {
                        ResultImage.Source = image.ToBitmapSource();
                        Title = $"图片查看:{System.IO.Path.GetFileName(imagePath)}";
                        // æ›´æ–°æŒ‰é’®çŠ¶æ€
                        PrevButton.IsEnabled = false;
                        NextButton.IsEnabled = false;
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载图片失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
            return true;
        }
    }
}
IDViewer_2D/ImageService/ImageCleanupService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SmartScanner
{
    class ImageCleanupService
    {
        private readonly string _imageDirectory;
        private readonly int _retentionDays;
        private Timer _cleanupTimer;
        private bool _isRunning;
        public ImageCleanupService(string imageDirectory, int retentionDays)
        {
            _imageDirectory = imageDirectory;
            _retentionDays = retentionDays;
        }
        public void Start()
        {
            if (_isRunning) return;
            // ç«‹å³æ‰§è¡Œä¸€æ¬¡æ¸…理
            Task.Run(() => CleanupOldImages());
            // è®¾ç½®æ¯å¤©å‡Œæ™¨2点执行清理
            var now = DateTime.Now;
            var nextRunTime = new DateTime(now.Year, now.Month, now.Day, 2, 0, 0).AddDays(1);
            var dueTime = nextRunTime - now;
            _cleanupTimer = new Timer(_ => CleanupOldImages(), null, dueTime, TimeSpan.FromDays(1));
            _isRunning = true;
        }
        public void Stop()
        {
            _cleanupTimer?.Dispose();
            _isRunning = false;
        }
        private void CleanupOldImages()
        {
            try
            {
                if (!Directory.Exists(_imageDirectory)) return;
                var cutoffDate = DateTime.Now.AddDays(-_retentionDays);
                var searchOption = SearchOption.AllDirectories;
                foreach (var file in Directory.EnumerateFiles(_imageDirectory, "*.*", searchOption))
                {
                    try
                    {
                        var fileInfo = new FileInfo(file);
                        if (fileInfo.LastWriteTime < cutoffDate)
                        {
                            File.Delete(file);
                            // å¯é€‰ï¼šè®°å½•删除日志
                            LogDeletion(file);
                        }
                    }
                    catch (Exception ex)
                    {
                        // è®°å½•错误但继续处理其他文件
                        LogError($"删除文件失败: {file}", ex);
                    }
                }
            }
            catch (Exception ex)
            {
                LogError("清理旧图像时发生错误", ex);
            }
        }
        private void LogDeletion(string filePath)
        {
            // å®žçŽ°æ—¥å¿—è®°å½•ï¼Œå¯ä»¥å†™å…¥æ–‡ä»¶æˆ–æ•°æ®åº“
            string logMessage = $"{DateTime.Now}: å·²åˆ é™¤è¿‡æœŸå›¾åƒ - {filePath}";
            System.Diagnostics.Debug.WriteLine(logMessage);
        }
        private void LogError(string message, Exception ex)
        {
            // å®žçŽ°é”™è¯¯æ—¥å¿—è®°å½•
            string errorMessage = $"{DateTime.Now}: {message} - {ex.Message}";
            System.Diagnostics.Debug.WriteLine(errorMessage);
        }
    }
}
IDViewer_2D/ImageService/MemoryAlarmCheck.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmartScanner.ImageService
{
    class MemoryAlarmCheck
    {
        private (double usedPercentage, string driveName) GetDriveUsage()
        {
            // èŽ·å–ç³»ç»Ÿç›˜
            DownloadData downloadData = new DownloadData();
            DriveInfo drive = new DriveInfo($"{downloadData.SetDataSavingRoad.Text}");
            double totalSpace = drive.TotalSize;
            double freeSpace = drive.AvailableFreeSpace;
            double usedPercentage = 100 - (freeSpace / totalSpace * 100);
            return (usedPercentage, drive.Name);
        }
    }
}
IDViewer_2D/LBProjService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;
namespace SmartScanner
{
    public static class LBProjService
    {
        private const string ConfigFileName = "config.json";
        private const string ModelNameFileName = "model_name.txt";
        private const string ModelDir = "model";  // å›ºå®šæ¨¡åž‹ç›®å½•
        /// <summary>
        /// åˆ›å»ºä¸´æ—¶ç›®å½•
        /// </summary>
        private static string CreateTempDirectory()
        {
            string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            Directory.CreateDirectory(tempDir);
            return tempDir;
        }
        /// <summary>
        /// èŽ·å–æ‰€æœ‰å¯ç”¨æ¨¡åž‹
        /// </summary>
        public static string[] GetAvailableModels()
        {
            string modelPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ModelDir);
            if (!Directory.Exists(modelPath))
            {
                Directory.CreateDirectory(modelPath);
                return Array.Empty<string>();
            }
            return Directory.GetFiles(modelPath, "*.lb")
                           .Select(Path.GetFileName)
                           .ToArray();
        }
        /// <summary>
        /// åˆ›å»ºå·¥ç¨‹æ–‡ä»¶
        /// </summary>
        public static (bool Success, string Message) CreateLBProj(
            string paramFilePath,
            string modelFileName,
            string outputPath)
        {
            try
            {
                // éªŒè¯æ¨¡åž‹æ˜¯å¦å­˜åœ¨
                string fullModelPath = Path.Combine(ModelDir, modelFileName);
                if (!File.Exists(fullModelPath))
                {
                    return (false, $"模型文件 {modelFileName} ä¸å­˜åœ¨äºŽ {ModelDir} ç›®å½•");
                }
                // åˆ›å»ºä¸´æ—¶ç›®å½•并打包
                string tempDir = CreateTempDirectory();
                try
                {
                    // 1. ä¿å­˜å‚数文件
                    File.Copy(paramFilePath, Path.Combine(tempDir, ConfigFileName), true);
                    // 2. ä¿å­˜æ¨¡åž‹æ–‡ä»¶åï¼ˆéžè·¯å¾„)
                    File.WriteAllText(Path.Combine(tempDir, ModelNameFileName), modelFileName);
                    // 3. åˆ›å»ºZIP包
                    ZipFile.CreateFromDirectory(tempDir, outputPath);
                    return (true, "工程文件创建成功");
                }
                finally
                {
                    Directory.Delete(tempDir, true);
                }
            }
            catch (Exception ex)
            {
                return (false, $"创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// åŠ è½½å·¥ç¨‹æ–‡ä»¶
        /// </summary>
        public static (string ModelName, string configPath, string ConfigContent, string Message) LoadLBProj(string projectFilePath)
        {
            try
            {
                string tempDir = CreateTempDirectory();
                try
                {
                    ZipFile.ExtractToDirectory(projectFilePath, tempDir);
                    // 1. è¯»å–模型文件名
                    string modelNameFile = Path.Combine(tempDir, ModelNameFileName);
                    if (!File.Exists(modelNameFile))
                    {
                        return (null, null, null, "工程文件中缺少模型名称记录");
                    }
                    string modelName = File.ReadAllText(modelNameFile);
                    // 2. éªŒè¯æ¨¡åž‹æ˜¯å¦å­˜åœ¨
                    string fullModelPath = Path.Combine(ModelDir, modelName);
                    if (!File.Exists(fullModelPath))
                    {
                        return (null, null, null, $"模型 {modelName} ä¸å­˜åœ¨äºŽ {ModelDir} ç›®å½•");
                    }
                    // 3. è¯»å–配置
                    string configPath = Path.Combine(tempDir, ConfigFileName);
                    string configContent = File.ReadAllText(configPath);
                    return (modelName, configPath, configContent, "加载成功");
                }
                finally
                {
                    Directory.Delete(tempDir, true);
                }
            }
            catch (Exception ex)
            {
                return (null, null, null, $"加载失败: è¯·è¾“入正确的工程文件路径: {ex.Message}");
            }
        }
    }
}
IDViewer_2D/LBProtect.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace SmartScanner
{
    class LBProtect
    {
        //私钥
        private static readonly string privateKey = "<RSAKeyValue><Modulus>zM7HeOAK8nORTQ56zl4IInkg7Y5k3Zf2FtXaHwu4nSCJOdWmABnbIbTlIt9y9gmLnDHG0maUXlaxZrbUGeAScrmI6kD4qlDypf9qKO7iB5K9xf0MD7ecioeljLXJtG8ahPo6pqiyg9Sx0Czue2pg672ssPtbGL81iFrgwy+Zgok=</Modulus><Exponent>AQAB</Exponent><P>zUb5vO3p4iqncynb+WGVyO1d73M/bXrqLG7cCaZN4gk7XxeWWyfIk2flCCI2veAdp4MKpdG3j4W+Y7+8xq5fzw==</P><Q>/2oalvvC/i1YtJNGCZk4+k83asfBZZpElTp/t+U4FC8vGGKE8slfBzflSps8PTJ67/MKZ8sgD0pW9Vp2e4j2Jw==</Q><DP>sU5v4edh0C9liUyLq2DFvtKAA5Z5H7g+UnjC6DbUKLwuoxk9jqjTT7c6lYbv35uYIZtHdCirs3UjGQeBJ99v8w==</DP><DQ>taKxEhosSzHYWWI6dmz+dhOLp2YzBJw2laEqXo6l2MTNSxwUy8ukxq9bYjkPF74kayt9hN6RCA6n1Ifmpmd6FQ==</DQ><InverseQ>AxT3HFNQY9mBI/fe68ACR56ARDIUCXb62REnjbJDA0/7Ti/n5NN+yaELwVDZpw2LVlqePyYdmMJgUAJGBjHl4A==</InverseQ><D>YtiRsScAYY+hWv1YC+2aI3kuiTimOcSzwsWnpkAz87HWSRFyMq5H8nap+DC7/T8SIGptuPJFPVq9+ALZTzuz6siESv1EtND58nyrR6HnUKXlhiGuoG9vXL2rP71BnZA+H+lnIFrG48orFKP/8kA2Hy9cP9l4b1pBXEZJHQHG1hk=</D></RSAKeyValue>";
        private static readonly RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider();
        // è§£å¯†
        public static string RsaDecrypt(string textRsa)
        {
            cryptoServiceProvider.FromXmlString(privateKey);
            byte[] inputBytes = Convert.FromBase64String(textRsa);
            byte[] decryptedBytes = cryptoServiceProvider.Decrypt(inputBytes, false);
            return Encoding.UTF8.GetString(decryptedBytes);
        }
        // èŽ·å–ç¡¬ä»¶æŒ‡çº¹
        public static string GetHardwareFingerprint()
        {
            StringBuilder sb = new StringBuilder();
            // CPU ID
            sb.Append(GetWmiInfo("Win32_Processor", "ProcessorId"));
            // ä¸»æ¿åºåˆ—号
            sb.Append(GetWmiInfo("Win32_BaseBoard", "SerialNumber"));
            // ä¸»ç¡¬ç›˜åºåˆ—号
            sb.Append(GetFixedDiskSerialNumber());
            // è®¡ç®—SHA256哈希
            using (SHA256 sha256 = SHA256.Create())
            {
                byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
                return BitConverter.ToString(hash).Replace("-", "").Substring(0, 16);
            }
        }
        private static string GetWmiInfo(string className, string propertyName)
        {
            try
            {
                using (ManagementClass mc = new ManagementClass(className))
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        return mo[propertyName]?.ToString() ?? string.Empty;
                    }
                }
            }
            catch { }
            return string.Empty;
        }
        // éªŒè¯ç¡¬ä»¶æŒ‡çº¹
        public static bool ValidateFingerprint()
        {
            string sRsaVal = "";
            string currentConfigDirectory = Directory.GetCurrentDirectory() + "\\config";
            string currentFingerprint = GetHardwareFingerprint();
            try
            {
                if (!Directory.Exists(currentConfigDirectory))
                    Directory.CreateDirectory(currentConfigDirectory);
                string sRsa = File.ReadAllText(currentConfigDirectory + "\\" + currentFingerprint + ".lic");
                sRsaVal = RsaDecrypt(sRsa);
            }
            catch
            { }
            bool bSame = true;
            if (currentFingerprint != sRsaVal)
            {
                bSame = false;
                File.WriteAllText(currentConfigDirectory + "\\MachineId.txt", currentFingerprint);
            }
            return bSame;
        }
        // èŽ·å–å›ºå®šç¡¬ç›˜åºåˆ—å·ï¼ˆæŽ’é™¤å¯ç§»åŠ¨è®¾å¤‡ï¼‰
        private static string GetFixedDiskSerialNumber()
        {
            try
            {
                // æŸ¥æ‰¾å›ºå®šç¡¬ç›˜
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber, MediaType FROM Win32_DiskDrive WHERE MediaType = 'Fixed hard disk media'"))
                using (ManagementObjectCollection moc = searcher.Get())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        string serialNumber = mo["SerialNumber"]?.ToString()?.Trim() ?? string.Empty;
                        if (!string.IsNullOrEmpty(serialNumber))
                            return serialNumber;
                    }
                }
                // æŸ¥æ‰¾éžUSB接口的设备
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber, InterfaceType FROM Win32_DiskDrive WHERE InterfaceType != 'USB'"))
                using (ManagementObjectCollection moc = searcher.Get())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        string serialNumber = mo["SerialNumber"]?.ToString()?.Trim() ?? string.Empty;
                        if (!string.IsNullOrEmpty(serialNumber))
                            return serialNumber;
                    }
                }
            }
            catch { }
            return string.Empty;
        }
    }
}
IDViewer_2D/LoadingWindow.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
<Window x:Class="SmartScanner.LoadingWindow"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Loading..." Height="150" Width="300" WindowStyle="None"
        AllowsTransparency="True" Background="Transparent"
        WindowStartupLocation="CenterScreen">
    <Border Background="#3C3C3C" CornerRadius="10">
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBlock x:Name="Loading" Text="软件加载中· Â· Â·" Foreground="White"
                       FontSize="16" Margin="0,10,0,10" />
            <ProgressBar IsIndeterminate="True" Width="250" Height="20"/>
        </StackPanel>
    </Border>
</Window>
IDViewer_2D/LoadingWindow.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SmartScanner
{
    /// <summary>
    /// LoadingWindow.xaml çš„交互逻辑
    /// </summary>
    public partial class LoadingWindow : Window
    {
        public LoadingWindow()
        {
            InitializeComponent();
        }
    }
}
IDViewer_2D/LogAutoSaveService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using SmartScanner.ViewModel;
namespace SmartScanner
{
    /// <summary>
    /// ä¼˜åŒ–的日志自动保存服务
    /// åŠŸèƒ½ï¼šæ‰¹é‡ä¿å­˜48小时内每一条日志到D盘02 LBLog文件夹
    /// è§¦å‘条件:最多300条或十分钟批量保存一次
    /// </summary>
    public class LogAutoSaveService
    {
        private readonly ObservableCollection<LogEntry> _logEntries;
        private Timer _cleanupTimer;
        private Timer _batchSaveTimer;
        private const int CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1小时清理一次
        private const int BATCH_SAVE_INTERVAL_MS = 600000; // ååˆ†é’Ÿæ‰¹é‡ä¿å­˜ä¸€æ¬¡
        private const int MAX_BATCH_SIZE = 300; // æœ€å¤š300条日志批量保存
        private readonly string _logDirectory = @"D:\02 LBLog";
        private bool _isSaving = false;
        private readonly object _fileLock = new object();
        private readonly object _bufferLock = new object();
        private string _currentLogFilePath;
        private readonly Queue<LogEntry> _logBuffer = new Queue<LogEntry>(); // æ—¥å¿—缓冲区
        private int _bufferCount = 0; // ç¼“冲区计数
        public LogAutoSaveService(ObservableCollection<LogEntry> logEntries)
        {
            _logEntries = logEntries ?? throw new ArgumentNullException(nameof(logEntries));
            // åˆ›å»ºæ—¥å¿—目录
            if (!Directory.Exists(_logDirectory))
            {
                Directory.CreateDirectory(_logDirectory);
            }
            // åˆå§‹åŒ–当前日志文件路径
            InitializeCurrentLogFile();
            // å¯åŠ¨æ‰¹é‡ä¿å­˜å®šæ—¶å™¨
            _batchSaveTimer = new Timer(OnBatchSaveTimerElapsed, null, BATCH_SAVE_INTERVAL_MS, BATCH_SAVE_INTERVAL_MS);
            // å¯åŠ¨æ¸…ç†å®šæ—¶å™¨
            _cleanupTimer = new Timer(OnCleanupTimerElapsed, null, CLEANUP_INTERVAL_MS, CLEANUP_INTERVAL_MS);
        }
        /// <summary>
        /// åˆå§‹åŒ–当前日志文件路径
        /// </summary>
        private void InitializeCurrentLogFile()
        {
            string currentDate = DateTime.Now.ToString("yyyyMMdd");
            string fileName = $"Log_{currentDate}.txt";
            _currentLogFilePath = Path.Combine(_logDirectory, fileName);
        }
        /// <summary>
        /// æ·»åŠ æ—¥å¿—åˆ°ç¼“å†²åŒºï¼Œå»¶è¿Ÿæ‰¹é‡ä¿å­˜
        /// </summary>
        public void LogAdded(LogEntry logEntry)
        {
            if (_isSaving) return;
            lock (_bufferLock)
            {
                _logBuffer.Enqueue(logEntry);
                _bufferCount++;
                // å¦‚果缓冲区达到最大大小,立即触发保存
                if (_bufferCount >= MAX_BATCH_SIZE)
                {
                    Task.Run(() => SaveBatchAsync());
                }
            }
        }
        /// <summary>
        /// æ‰¹é‡ä¿å­˜å®šæ—¶å™¨å›žè°ƒ
        /// </summary>
        private void OnBatchSaveTimerElapsed(object state)
        {
            if (!_isSaving && _bufferCount > 0)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
        /// <summary>
        /// å¼‚步批量保存日志
        /// </summary>
        private async Task SaveBatchAsync()
        {
            if (_isSaving) return;
            _isSaving = true;
            try
            {
                // æ£€æŸ¥æ˜¯å¦éœ€è¦åˆ‡æ¢åˆ°æ–°æ–‡ä»¶
                await CheckAndSwitchLogFileAsync();
                // èŽ·å–ç¼“å†²åŒºä¸­çš„æ‰€æœ‰æ—¥å¿—
                List<LogEntry> batchToSave;
                lock (_bufferLock)
                {
                    if (_bufferCount == 0)
                    {
                        _isSaving = false;
                        return;
                    }
                    batchToSave = new List<LogEntry>(_logBuffer);
                    _logBuffer.Clear();
                    _bufferCount = 0;
                }
                // æ‰¹é‡ä¿å­˜åˆ°æ–‡ä»¶
                await SaveBatchToFileAsync(batchToSave);
                Console.WriteLine($"批量保存了 {batchToSave.Count} æ¡æ—¥å¿—到文件");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量保存失败: {ex.Message}");
            }
            finally
            {
                _isSaving = false;
            }
        }
        /// <summary>
        /// æ‰¹é‡ä¿å­˜æ—¥å¿—到文件
        /// </summary>
        private async Task SaveBatchToFileAsync(List<LogEntry> batch)
        {
            await Task.Run(() =>
            {
                lock (_fileLock)
                {
                    try
                    {
                        using (StreamWriter writer = new StreamWriter(_currentLogFilePath, true, Encoding.UTF8))
                        {
                            foreach (var entry in batch)
                            {
                                string logLine = $"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{entry.Level}] {entry.Message}";
                                writer.WriteLine(logLine);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"批量保存到文件失败: {ex.Message}");
                    }
                }
            });
        }
        /// <summary>
        /// æ£€æŸ¥æ˜¯å¦éœ€è¦åˆ‡æ¢åˆ°æ–°çš„æ—¥å¿—文件
        /// </summary>
        private async Task CheckAndSwitchLogFileAsync()
        {
            await Task.Run(() =>
            {
                string currentDate = DateTime.Now.ToString("yyyyMMdd");
                string fileName = $"Log_{currentDate}.txt";
                string newFilePath = Path.Combine(_logDirectory, fileName);
                // å¦‚果日期变化,切换到新文件
                if (_currentLogFilePath != newFilePath)
                {
                    _currentLogFilePath = newFilePath;
                }
            });
        }
        private void OnCleanupTimerElapsed(object state)
        {
            // æ¸…理超过48小时的日志文件
            if (!_isSaving)
            {
                Task.Run(() => CleanupOldLogFilesAsync());
            }
        }
        /// <summary>
        /// æ¸…理超过48小时的日志文件
        /// </summary>
        private async Task CleanupOldLogFilesAsync()
        {
            await Task.Run(() =>
            {
                try
                {
                    if (Directory.Exists(_logDirectory))
                    {
                        var files = Directory.GetFiles(_logDirectory, "Log_*.txt");
                        DateTime cutoffTime = DateTime.Now.AddHours(-48);
                        foreach (string file in files)
                        {
                            try
                            {
                                FileInfo fileInfo = new FileInfo(file);
                                if (fileInfo.LastWriteTime < cutoffTime)
                                {
                                    File.Delete(file);
                                    Console.WriteLine($"清理过期日志文件: {file}");
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"清理文件失败 {file}: {ex.Message}");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"清理过期日志文件失败: {ex.Message}");
                }
            });
        }
        /// <summary>
        /// æ‰‹åŠ¨ä¿å­˜å½“å‰æ‰€æœ‰æ—¥å¿—
        /// </summary>
        public void ForceSave()
        {
            if (!_isSaving)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
        /// <summary>
        /// åœæ­¢æœåŠ¡
        /// </summary>
        public void Stop()
        {
            _batchSaveTimer?.Dispose();
            _batchSaveTimer = null;
            _cleanupTimer?.Dispose();
            _cleanupTimer = null;
            // ä¿å­˜æœ€åŽçš„æ—¥å¿—
            if (!_isSaving && _bufferCount > 0)
            {
                ForceSave();
            }
        }
        /// <summary>
        /// èŽ·å–ä¿å­˜ç»Ÿè®¡ä¿¡æ¯
        /// </summary>
        public string GetStatus()
        {
            try
            {
                string currentFileInfo = "";
                if (File.Exists(_currentLogFilePath))
                {
                    FileInfo fileInfo = new FileInfo(_currentLogFilePath);
                    currentFileInfo = $", å½“前文件大小: {fileInfo.Length / 1024} KB";
                }
                return $"自动保存服务运行中 - ç¼“冲区: {_bufferCount} æ¡{currentFileInfo}";
            }
            catch
            {
                return $"自动保存服务运行中 - ç¼“冲区: {_bufferCount} æ¡";
            }
        }
    }
}
IDViewer_2D/LogAutoSaveService_Optimized.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using SmartScanner.ViewModel;
namespace SmartScanner
{
    /// <summary>
    /// ä¼˜åŒ–的日志自动保存服务
    /// åŠŸèƒ½ï¼šæ‰¹é‡ä¿å­˜24小时内每一条日志到D盘02 LBLog文件夹
    /// è§¦å‘条件:最多100条或5秒内批量保存一次
    /// </summary>
    public class LogAutoSaveService
    {
        private readonly ObservableCollection<LogEntry> _logEntries;
        private Timer _cleanupTimer;
        private Timer _batchSaveTimer;
        private const int CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1小时清理一次
        private const int BATCH_SAVE_INTERVAL_MS = 5000; // 5秒批量保存一次
        private const int MAX_BATCH_SIZE = 100; // æœ€å¤š100条日志批量保存
        private readonly string _logDirectory = @"D:\02 LBLog";
        private bool _isSaving = false;
        private readonly object _fileLock = new object();
        private readonly object _bufferLock = new object();
        private string _currentLogFilePath;
        private readonly Queue<LogEntry> _logBuffer = new Queue<LogEntry>(); // æ—¥å¿—缓冲区
        private int _bufferCount = 0; // ç¼“冲区计数
        public LogAutoSaveService(ObservableCollection<LogEntry> logEntries)
        {
            _logEntries = logEntries ?? throw new ArgumentNullException(nameof(logEntries));
            // åˆ›å»ºæ—¥å¿—目录
            if (!Directory.Exists(_logDirectory))
            {
                Directory.CreateDirectory(_logDirectory);
            }
            // åˆå§‹åŒ–当前日志文件路径
            InitializeCurrentLogFile();
            // å¯åŠ¨æ‰¹é‡ä¿å­˜å®šæ—¶å™¨
            _batchSaveTimer = new Timer(OnBatchSaveTimerElapsed, null, BATCH_SAVE_INTERVAL_MS, BATCH_SAVE_INTERVAL_MS);
            // å¯åŠ¨æ¸…ç†å®šæ—¶å™¨
            _cleanupTimer = new Timer(OnCleanupTimerElapsed, null, CLEANUP_INTERVAL_MS, CLEANUP_INTERVAL_MS);
        }
        /// <summary>
        /// åˆå§‹åŒ–当前日志文件路径
        /// </summary>
        private void InitializeCurrentLogFile()
        {
            string currentDate = DateTime.Now.ToString("yyyyMMdd");
            string fileName = $"Log_{currentDate}.txt";
            _currentLogFilePath = Path.Combine(_logDirectory, fileName);
        }
        /// <summary>
        /// æ·»åŠ æ—¥å¿—åˆ°ç¼“å†²åŒºï¼Œå»¶è¿Ÿæ‰¹é‡ä¿å­˜
        /// </summary>
        public void LogAdded(LogEntry logEntry)
        {
            if (_isSaving) return;
            lock (_bufferLock)
            {
                _logBuffer.Enqueue(logEntry);
                _bufferCount++;
                // å¦‚果缓冲区达到最大大小,立即触发保存
                if (_bufferCount >= MAX_BATCH_SIZE)
                {
                    Task.Run(() => SaveBatchAsync());
                }
            }
        }
        /// <summary>
        /// æ‰¹é‡ä¿å­˜å®šæ—¶å™¨å›žè°ƒ
        /// </summary>
        private void OnBatchSaveTimerElapsed(object state)
        {
            if (!_isSaving && _bufferCount > 0)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
        /// <summary>
        /// å¼‚步批量保存日志
        /// </summary>
        private async Task SaveBatchAsync()
        {
            if (_isSaving) return;
            _isSaving = true;
            try
            {
                // æ£€æŸ¥æ˜¯å¦éœ€è¦åˆ‡æ¢åˆ°æ–°æ–‡ä»¶
                await CheckAndSwitchLogFileAsync();
                // èŽ·å–ç¼“å†²åŒºä¸­çš„æ‰€æœ‰æ—¥å¿—
                List<LogEntry> batchToSave;
                lock (_bufferLock)
                {
                    if (_bufferCount == 0)
                    {
                        _isSaving = false;
                        return;
                    }
                    batchToSave = new List<LogEntry>(_logBuffer);
                    _logBuffer.Clear();
                    _bufferCount = 0;
                }
                // æ‰¹é‡ä¿å­˜åˆ°æ–‡ä»¶
                await SaveBatchToFileAsync(batchToSave);
                Console.WriteLine($"批量保存了 {batchToSave.Count} æ¡æ—¥å¿—到文件");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量保存失败: {ex.Message}");
            }
            finally
            {
                _isSaving = false;
            }
        }
        /// <summary>
        /// æ‰¹é‡ä¿å­˜æ—¥å¿—到文件
        /// </summary>
        private async Task SaveBatchToFileAsync(List<LogEntry> batch)
        {
            await Task.Run(() =>
            {
                lock (_fileLock)
                {
                    try
                    {
                        using (StreamWriter writer = new StreamWriter(_currentLogFilePath, true, Encoding.UTF8))
                        {
                            foreach (var entry in batch)
                            {
                                string logLine = $"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{entry.Level}] {entry.Message}";
                                writer.WriteLine(logLine);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"批量保存到文件失败: {ex.Message}");
                    }
                }
            });
        }
        /// <summary>
        /// æ£€æŸ¥æ˜¯å¦éœ€è¦åˆ‡æ¢åˆ°æ–°çš„æ—¥å¿—文件
        /// </summary>
        private async Task CheckAndSwitchLogFileAsync()
        {
            await Task.Run(() =>
            {
                string currentDate = DateTime.Now.ToString("yyyyMMdd");
                string fileName = $"Log_{currentDate}.txt";
                string newFilePath = Path.Combine(_logDirectory, fileName);
                // å¦‚果日期变化,切换到新文件
                if (_currentLogFilePath != newFilePath)
                {
                    _currentLogFilePath = newFilePath;
                }
            });
        }
        private void OnCleanupTimerElapsed(object state)
        {
            // æ¸…理超过48小时的日志文件
            if (!_isSaving)
            {
                Task.Run(() => CleanupOldLogFilesAsync());
            }
        }
        /// <summary>
        /// æ¸…理超过48小时的日志文件
        /// </summary>
        private async Task CleanupOldLogFilesAsync()
        {
            await Task.Run(() =>
            {
                try
                {
                    if (Directory.Exists(_logDirectory))
                    {
                        var files = Directory.GetFiles(_logDirectory, "Log_*.txt");
                        DateTime cutoffTime = DateTime.Now.AddHours(-48);
                        foreach (string file in files)
                        {
                            try
                            {
                                FileInfo fileInfo = new FileInfo(file);
                                if (fileInfo.LastWriteTime < cutoffTime)
                                {
                                    File.Delete(file);
                                    Console.WriteLine($"清理过期日志文件: {file}");
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"清理文件失败 {file}: {ex.Message}");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"清理过期日志文件失败: {ex.Message}");
                }
            });
        }
        /// <summary>
        /// æ‰‹åŠ¨ä¿å­˜å½“å‰æ‰€æœ‰æ—¥å¿—
        /// </summary>
        public void ForceSave()
        {
            if (!_isSaving)
            {
                Task.Run(() => SaveBatchAsync());
            }
        }
        /// <summary>
        /// åœæ­¢æœåŠ¡
        /// </summary>
        public void Stop()
        {
            _batchSaveTimer?.Dispose();
            _batchSaveTimer = null;
            _cleanupTimer?.Dispose();
            _cleanupTimer = null;
            // ä¿å­˜æœ€åŽçš„æ—¥å¿—
            if (!_isSaving && _bufferCount > 0)
            {
                ForceSave();
            }
        }
        /// <summary>
        /// èŽ·å–ä¿å­˜ç»Ÿè®¡ä¿¡æ¯
        /// </summary>
        public string GetStatus()
        {
            try
            {
                string currentFileInfo = "";
                if (File.Exists(_currentLogFilePath))
                {
                    FileInfo fileInfo = new FileInfo(_currentLogFilePath);
                    currentFileInfo = $", å½“前文件大小: {fileInfo.Length / 1024} KB";
                }
                return $"自动保存服务运行中 - ç¼“冲区: {_bufferCount} æ¡{currentFileInfo}";
            }
            catch
            {
                return $"自动保存服务运行中 - ç¼“冲区: {_bufferCount} æ¡";
            }
        }
    }
}
IDViewer_2D/LoginWindow.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
<Window x:Class="SmartScanner.LoginWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmartScanner"
        mc:Ignorable="d"
        Title="权限验证" Height="200" Width="300" ResizeMode="NoResize">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="AUto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="AUTO"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Content="用户名:"/>
        <ComboBox Grid.Row="1" x:Name="cmbUsername" ItemsSource="{Binding UserList}" Height="25" DisplayMemberPath="Username"/>
        <Label Grid.Row="2" Content="密码:"/>
        <PasswordBox Grid.Row="3" x:Name="txtPassword" Height="25"/>
        <StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="登录" Width="80" Margin="5" Click="BtnLogin_Click"/>
            <Button Content="取消" Width="80" Margin="5" Click="BtnCancel_Click"/>
        </StackPanel>
    </Grid>
</Window>
IDViewer_2D/LoginWindow.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SmartScanner
{
    /// <summary>
    /// LoginWindow.xaml çš„交互逻辑
    /// </summary>
    public partial class LoginWindow : Window
    {
        public LoginWindow()
        {
            InitializeComponent();
            cmbUsername.ItemsSource = UserManager.UserList;
            cmbUsername.SelectedIndex = 0;
        }
        private void BtnLogin_Click(object sender, RoutedEventArgs e)
        {
            var selectedUser = cmbUsername.SelectedItem as User;
            if (selectedUser == null) return;
            if (UserManager.Authenticate(selectedUser.Username, txtPassword.Password))
            {
                DialogResult = true;
                Close();
            }
            else
            {
                MessageBox.Show("用户名或密码错误", "登录失败", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private void BtnCancel_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }
    }
}
IDViewer_2D/MainWindow.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,915 @@
<Window x:Class="SmartScanner.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmartScanner"
        xmlns:Properties="clr-namespace:SmartScanner.Properties"
        mc:Ignorable="d"
        Title="SmartScanner" Height="768" Width="1240">
    <Grid Background="#3C3C3C">
        <Grid.Resources>
            <Style x:Key="SimpleLabeledToggleSwitchStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Background" Value="#E0E0E0"/>
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Grid>
                                <VisualStateManager.VisualStateGroups>
                                    <!-- ä»…保留Pressed和Disabled状态 -->
                                    <VisualStateGroup x:Name="CommonStates">
                                        <VisualState x:Name="Normal"/>
                                        <VisualState x:Name="MouseOver">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="SwitchThumb"
                         Storyboard.TargetProperty="Opacity"
                         To="0.8" Duration="0:0:0.1"/>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Pressed">
                                            <Storyboard>
                                                <!-- æŒ‰ä¸‹æ—¶çš„æ»‘块放大效果 -->
                                                <DoubleAnimation Storyboard.TargetName="SwitchThumb"
                                                     Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
                                                     To="1.2" Duration="0:0:0.1"/>
                                                <DoubleAnimation Storyboard.TargetName="SwitchThumb"
                                                     Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
                                                     To="1.2" Duration="0:0:0.1"/>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Disabled">
                                            <Storyboard>
                                                <ColorAnimation Storyboard.TargetName="SwitchTrack"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="#EEEEEE" Duration="0"/>
                                                <ColorAnimation Storyboard.TargetName="SwitchThumb"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="#BDBDBD" Duration="0"/>
                                                <ColorAnimation Storyboard.TargetName="TextLabel"
                                                    Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
                                                    To="#BDBDBD" Duration="0"/>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                    <!-- å¼€å…³çŠ¶æ€ï¼ˆä¿æŒä¸å˜ï¼‰ -->
                                    <VisualStateGroup x:Name="CheckStates">
                                        <VisualState x:Name="Checked">
                                            <Storyboard>
                                                <ThicknessAnimation Storyboard.TargetName="SwitchThumb"
                                                       Storyboard.TargetProperty="Margin"
                                                       To="26,0,0,0" Duration="0:0:0.2"/>
                                                <ColorAnimation Storyboard.TargetName="SwitchTrack"
                                                   Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                   To="#4CAF50" Duration="0:0:0.2"/>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel"
                                                                   Storyboard.TargetProperty="Text">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="单点ON"/>
                                                </ObjectAnimationUsingKeyFrames>
                                                <ColorAnimation Storyboard.TargetName="TextLabel"
                                                   Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
                                                   To="#4CAF50" Duration="0:0:0.2"/>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="Unchecked">
                                            <Storyboard>
                                                <ThicknessAnimation Storyboard.TargetName="SwitchThumb"
                                                       Storyboard.TargetProperty="Margin"
                                                       To="0,0,0,0" Duration="0:0:0.2"/>
                                                <ColorAnimation Storyboard.TargetName="SwitchTrack"
                                                   Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                   To="#E0E0E0" Duration="0:0:0.2"/>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel"
                                                                   Storyboard.TargetProperty="Text">
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="单点OFF"/>
                                                </ObjectAnimationUsingKeyFrames>
                                                <ColorAnimation Storyboard.TargetName="TextLabel"
                                                   Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
                                                   To="#757575" Duration="0:0:0.2"/>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <!-- å¼€å…³è½¨é“ -->
                                <Border x:Name="SwitchTrack"
                            Grid.Column="0"
                            Background="{TemplateBinding Background}"
                            CornerRadius="10"
                            Width="50"
                            Height="24"
                            Margin="0,0,10,0">
                                    <Border x:Name="SwitchThumb"
                                Background="{TemplateBinding Foreground}"
                                CornerRadius="10"
                                Width="24"
                                Height="24"
                                HorizontalAlignment="Left"
                                Margin="0,0,0,0">
                                        <Border.RenderTransform>
                                            <TransformGroup>
                                                <ScaleTransform/>
                                            </TransformGroup>
                                        </Border.RenderTransform>
                                    </Border>
                                </Border>
                                <!-- æ–‡å­—标签 -->
                                <TextBlock x:Name="TextLabel"
                               Grid.Column="1"
                               Text="OFF"
                               VerticalAlignment="Center"
                               Foreground="#757575"
                               FontWeight="SemiBold"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter TargetName="SwitchTrack" Property="Opacity" Value="0.6"/>
                                    <Setter TargetName="TextLabel" Property="Opacity" Value="0.6"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="TabItemStyle">
                <Style.Triggers>
                    <Trigger Property="TabItem.IsSelected" Value="True">
                        <Setter Property="TabItem.Background" Value="#6C6C6C"/>
                        <Setter Property="TabItem.Foreground" Value="Black"/>
                    </Trigger>
                    <Trigger Property="TabItem.IsSelected" Value="False">
                        <Setter Property="TabItem.Background" Value="#6C6C6C"/>
                        <Setter Property="TabItem.Foreground" Value="White"/>
                    </Trigger>
                    <Trigger Property="TabItem.IsMouseOver" Value="True">
                        <Setter Property="TabItem.Background" Value="#6C6C6C"/>
                        <Setter Property="TabItem.Foreground" Value="Black"/>
                    </Trigger>
                    <!--<Trigger Property="TabItem.IsMouseOver" Value="False">
                        <Setter Property="TabItem.Background" Value="#6C6C6C"/>
                        <Setter Property="TabItem.Foreground" Value="White"/>
                    </Trigger>-->
                    <!--<Trigger Property="TabItem.IsFocused" Value="True">
                        <Setter Property="TabItem.Background" Value="#4D0000"/>
                        <Setter Property="TabItem.Foreground" Value="#930000"/>
                    </Trigger>-->
                    <!--<Trigger Property="TabItem.IsFocused" Value="False">
                        <Setter Property="TabItem.Background" Value="#6C6C6C"/>
                        <Setter Property="TabItem.Foreground" Value="White"/>
                    </Trigger>-->
                </Style.Triggers>
            </Style>
            <Style x:Key="FocusVisual">
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle Margin="2" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <!--按钮静态时背景颜色-->
            <SolidColorBrush x:Key="Button.Static.Background" Color="#4F4F4F"/>
            <!--按钮静态时边框颜色-->
            <SolidColorBrush x:Key="Button.Static.Border" Color="#2F0000"/>
            <!--按钮静态时文字颜色-->
            <SolidColorBrush x:Key="Button.Static.Foreground" Color="White"/>
            <!--鼠标移入时背景颜色-->
            <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#4D0000"/>
            <!--鼠标移入时边框颜色-->
            <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#2F0000"/>
            <!--鼠标按下时背景颜色-->
            <SolidColorBrush x:Key="Button.Pressed.Background" Color="#4D0000"/>
            <!--鼠标按下时边框颜色-->
            <SolidColorBrush x:Key="Button.Pressed.Border" Color="#2F0000"/>
            <!--按钮不使用时背景颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Background" Color="Gray"/>
            <!--按钮不使用时边框颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
            <!--按钮不使用时文字颜色-->
            <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="White"/>
            <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
                <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
                <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
                <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="BorderThickness" Value="1"/>
                <!--边框宽度,设置为0 å³ï¼šæ— è¾¹æ¡†-->
                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="Padding" Value="1"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border x:Name="border" CornerRadius="5" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
                                <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <!--触发器:根据依赖属性的值去控制控件的状态-->
                            <ControlTemplate.Triggers>
                                <!--默认属性-->
                                <Trigger Property="IsDefaulted" Value="true">
                                    <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                </Trigger>
                                <!--鼠标移入属性-->
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
                                </Trigger>
                                <!--鼠标按下属性-->
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
                                </Trigger>
                                <!--按钮可用状态属性-->
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
                                    <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
                                    <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <!--文本框样式-->
            <SolidColorBrush x:Key="TextBox.Background" Color="#6C6C6C"/>
            <SolidColorBrush x:Key="TextBox.BorderBrush" Color="#1F0000"/>
            <SolidColorBrush x:Key="TextBox.Foreground" Color="White"/>
            <Style x:Key="TextStyle" TargetType="{x:Type TextBox}">
                <Setter Property="Background" Value="{StaticResource TextBox.Background}"/>
                <Setter Property="BorderBrush" Value="{StaticResource TextBox.BorderBrush}"/>
                <Setter Property="Foreground" Value="{StaticResource TextBox.Foreground}"/>
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="HorizontalContentAlignment" Value="Right"/>
            </Style>
            <!-- è¿™ä¼šå½±å“æ‰€æœ‰å·¥å…·æ çš„æº¢å‡ºèœå• -->
            <SolidColorBrush x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type ToolBar}, ResourceId=ToolBarMenuBackground}"
                    Color="#3C3C3C"/>
        </Grid.Resources>
        <!--<Grid.ColumnDefinitions>
            <ColumnDefinition Width="231*"/>
            <ColumnDefinition Width="169*"/>
        </Grid.ColumnDefinitions>-->
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="15*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Grid.ColumnSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="160"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <StackPanel  Grid.Column="0" Height="50" Width="150" Margin="5,0,5,0.4" Grid.RowSpan="2">
                <Image Stretch="Fill" Source="/Image/Currency/logo_01.png"/>
            </StackPanel>
            <ToolBarTray Grid.Column="1" Orientation="Horizontal" Background="#3C3C3C" Margin="0,0,-0.4,0.4" Grid.RowSpan="2">
                <ToolBar Grid.Column="1" Margin="0,0,-0.4,0.4" Grid.RowSpan="2" Background="#3C3C3C" Height="50">
                    <Button x:Name="Refresh_Btn" Background="#7B7B7B" BorderThickness="0" ToolTip="刷新设备列表并连接设备" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="Refresh_Btn_Click" Margin="5,0,5,0">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <Image x:Name="Refresh_BtnImage" Stretch="Fill" RenderOptions.BitmapScalingMode="HighQuality" Source="\Image\ICON\link-m.png"/>
                            <TextBlock Text="刷新连接" VerticalAlignment="Center" Foreground="white"/>
                        </StackPanel>
                    </Button>
                    <!--<Button x:Name="IsConnect_Btn" Click="IsConnect_Btn_Click" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0">
                    <Label Content="连接" Foreground="White" />
                </Button>-->
                    <Button x:Name="ProductMaanager_Btn" Click="ProductMaanager_Btn_Click" ToolTip="打开设备管理列表" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <Image x:Name="ProductMaanager_BtnImage" Source="\Image\ICON\camera-switch-fill.png" RenderOptions.BitmapScalingMode="HighQuality" Stretch="Fill"/>
                            <TextBlock Text="设备管理" VerticalAlignment="Center" Foreground="White" />
                        </StackPanel>
                    </Button>
                    <!--<Button x:Name="Disconnect_Btn" Click="Disconnect_Btn_Click" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" IsEnabled="False" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0" Visibility="Collapsed">
                    <Label Content="断开连接" Foreground="White" />
                </Button>-->
                    <Button x:Name="ResultJudge_Btn" Click="ResultJudge_Btn_Click" ToolTip="打开检测方案配置器" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <Image x:Name="ResultJudge_BtnImage" Source="\Image\ICON\folder-2-fill.png" RenderOptions.BitmapScalingMode="HighQuality" Stretch="Fill"/>
                            <TextBlock Text="检测方案" VerticalAlignment="Center" Foreground="White" />
                        </StackPanel>
                    </Button>
                    <Button x:Name="ImageSetup_Btn" Click="ImageSetup_Btn_Click" ToolTip="打开图像存储设置" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <Image x:Name="ImageSetup_BtnImage" Source="\Image\ICON\import-fill.png" RenderOptions.BitmapScalingMode="HighQuality" Stretch="Fill"/>
                            <TextBlock Text="存图设置" VerticalAlignment="Center" Foreground="White"/>
                        </StackPanel>
                    </Button>
                    <CheckBox Name="OutputCheckBox" Content="单点输出" VerticalAlignment="Center" Foreground="White" HorizontalAlignment="Center" IsChecked="{Binding Source={x:Static Properties:Settings.Default}, Path=OutputCheckBoxEnable, Mode=TwoWay}"
                              Checked="OutputCheckBox_Checked" Unchecked="OutputCheckBox_Unchecked" Style="{DynamicResource SimpleLabeledToggleSwitchStyle}"/>
                    <!--<Button x:Name="Start_Detector_Btn" Visibility="Hidden" Click="Start_Detector_Btn_Click" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Margin="5,0,5,0">
                        <Label Content="开始检测" Foreground="White" />
                    </Button>-->
                    <Button x:Name="Write" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="Write_Click" Margin="5,0,5,0">
                        <Label Content="通讯测试" Foreground="White" />
                    </Button>
                    <Button x:Name="Read" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="Read_Click" Margin="5,0,5,0">
                        <Label Content="手动采集" Foreground="White" />
                    </Button>
                    <Button x:Name="Reset" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="ReSet_Click" Margin="5,0,5,0">
                        <Label Content="界面重置" Foreground="White" />
                    </Button>
                    <Button x:Name="btnViewReports" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="btnViewReports_Click" Margin="5,0,5,0">
                        <Label Content="查看检测报告" Foreground="White" />
                    </Button>
                    <Button x:Name="btnViewLogs" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="btnViewLogs_Click" Margin="5,0,5,0">
                        <Label Content="查看日志" Foreground="White" />
                    </Button>
                    <Button x:Name="RestartButton"  Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="RestartButton_Click" Margin="5,0,5,0">
                        <Label Content="一键重启" Foreground="White" />
                    </Button>
                    <Button x:Name="VersionButton" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="VersionButton_Click" Margin="5,0,5,0">
                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                            <Label Content="版本说明" VerticalAlignment="Center" Foreground="White" Margin="5,0,0,0"/>
                        </StackPanel>
                    </Button>
                    <!--<Button x:Name="LogTest" Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="AddTestLog_Click" Margin="5,0,5,0">
                    <Label Content="日志测试" Foreground="White" />
                </Button>-->
                </ToolBar>
            </ToolBarTray>
        </Grid>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"></ColumnDefinition>
                <ColumnDefinition Width="0.05*"></ColumnDefinition>
                <ColumnDefinition Width="5*"></ColumnDefinition>
                <ColumnDefinition Width="0.05*"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.11*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="0.11*"/>
                    <RowDefinition Height="1*"/>
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
                    <!--<Button x:Name="IPSet" Content="IP设置" Foreground="White"  Background="#7B7B7B" BorderThickness="0" Height="30" Width="100" Style="{DynamicResource ButtonStyle}" Click="IPSet_Click"></Button>-->
                    <Label  Content="设备列表" HorizontalAlignment="Center"  FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                </StackPanel>
                <Grid Grid.Row="1">
                    <Border Grid.Row="0" BorderBrush="Black" BorderThickness="1" CornerRadius="5" Background="White">
                        <ListBox x:Name="DeviceListBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="20" FontFamily="Yu Gothic UI" SelectionChanged="DeviceListBox_SelectionChanged">
                        </ListBox>
                    </Border>
                </Grid>
                <StackPanel Grid.Row="2">
                    <Label  Content="设备信息" HorizontalAlignment="Center" FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                </StackPanel>
                <Border Grid.Row="3" BorderBrush="Black" BorderThickness="1" CornerRadius="5"  Background="White">
                    <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                        <Grid x:Name="ProductInformation">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <StackPanel Orientation="Horizontal" Grid.Row="0" VerticalAlignment="Center">
                                <TextBlock Text="IP地址:" Foreground="Black" FontSize="14"/>
                                <TextBlock Name="CameraIP" Text="" Margin="5,0,0,0" Foreground="Black" FontSize="14"/>
                            </StackPanel>
                            <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" >
                                <TextBlock Text="子网:"  Foreground="Black" FontSize="14"/>
                                <TextBlock Name="CameraNetMask" Text="" Margin="5,0,0,0" Foreground="Black" FontSize="14"/>
                            </StackPanel>
                            <StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Center">
                                <TextBlock Text="网关:" Foreground="Black"  FontSize="14"/>
                                <TextBlock Name="CameraGateWay" Text="" Margin="5,0,0,0" Foreground="Black"  FontSize="14"/>
                            </StackPanel>
                            <StackPanel Grid.Row="3" Orientation="Horizontal" VerticalAlignment="Center">
                                <TextBlock Text="固件版本:" Foreground="Black"  FontSize="14"/>
                                <TextBlock Name="CameraFirmwareVersion" Text="" Margin="5,0,0,0" Foreground="Black" FontSize="14"/>
                            </StackPanel>
                            <StackPanel Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Center">
                                <TextBlock Text="设备型号:" Foreground="Black"  FontSize="14"/>
                                <TextBlock Name="CameraModel" Text="" Margin="5,0,0,0" Foreground="Black"  FontSize="14"/>
                            </StackPanel>
                            <StackPanel Grid.Row="5" Orientation="Horizontal" VerticalAlignment="Center">
                                <TextBlock Text="设备名:" Foreground="Black"  FontSize="14"/>
                                <TextBlock Name="CameraAlias" Text="" Margin="5,0,0,0" Foreground="Black"  FontSize="14"/>
                            </StackPanel>
                        </Grid>
                    </ScrollViewer>
                </Border>
            </Grid>
            <Grid Grid.Column="2">
                <!--结果显示-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="11.5*"/>
                    <RowDefinition Height="3.5*"/>
                </Grid.RowDefinitions>
                <DockPanel Grid.Row="0" VerticalAlignment="Center">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                    <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" DockPanel.Dock="Left">
                        <TextBlock Text="检测状态:" Foreground="White" FontSize="23"/>
                        <TextBlock x:Name="DetectState" Text="未在检测" FontSize="23" Foreground="red"/>
                    </StackPanel>
                        <StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal" >
                        <TextBlock Text="通讯状态:" Foreground="White" FontSize="23"/>
                        <TextBlock x:Name="LinkState" Text="未连接" FontSize="23" Foreground="red"/>
                    </StackPanel>
                        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
                            <TextBlock Text="检测方案:" Foreground="White" FontSize="23"/>
                            <TextBlock x:Name="ProjectState" Text="未加载" FontSize="23" Foreground="red"/>
                        </StackPanel>
                        <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
                            <TextBlock Text="检测模型:" Foreground="White" FontSize="23"/>
                            <TextBlock x:Name="ModelState" Text="未加载" FontSize="23" Foreground="red"/>
                        </StackPanel>
                    </Grid>
                </DockPanel>
                <Grid Grid.Row="1">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Border x:Name="finall_result0" MouseLeftButtonDown="finall_result0_MouseLeftButtonDown"  Grid.Row="0" Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <StackPanel Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias0" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName0" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                                <!--<Button x:Name="finall_result0_Btn" Click="finall_result0_Btn_Click" Background="#7B7B7B"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result0" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                        <!--结果显示1-->
                    </Border>
                    <Border x:Name="finall_result1" MouseLeftButtonDown="finall_result1_MouseLeftButtonDown"  Grid.Row="0" Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示2-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias1" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName1" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result1" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result2" MouseLeftButtonDown="finall_result2_MouseLeftButtonDown"  Grid.Row="0" Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示3-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias2" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName2" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result2" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result3" MouseLeftButtonDown="finall_result3_MouseLeftButtonDown"  Grid.Row="0" Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示4-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias3" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName3" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result3" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result4" MouseLeftButtonDown="finall_result4_MouseLeftButtonDown"  Grid.Row="1"  Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示5-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias4" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName4" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result4" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result5" Grid.Row="1" MouseLeftButtonDown="finall_result5_MouseLeftButtonDown"  Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示6-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias5" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName5" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result5" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result6" Grid.Row="1" MouseLeftButtonDown="finall_result6_MouseLeftButtonDown"  Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示7-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias6" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName6" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result6" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result7" Grid.Row="1" MouseLeftButtonDown="finall_result7_MouseLeftButtonDown"  Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示8-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias7" Text="" Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName7" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result7" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result8" MouseLeftButtonDown="finall_result8_MouseLeftButtonDown"  Grid.Row="2" Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示9-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias8" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName8" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result8" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result9" MouseLeftButtonDown="finall_result9_MouseLeftButtonDown"  Grid.Row="2" Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示10-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias9" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName9" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result9" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result10" MouseLeftButtonDown="finall_result10_MouseLeftButtonDown"  Grid.Row="2" Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示11-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias10" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName10" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result10" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result11" MouseLeftButtonDown="finall_result11_MouseLeftButtonDown"  Grid.Row="2" Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示12-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias11" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName11" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result11" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result12" MouseLeftButtonDown="finall_result12_MouseLeftButtonDown"  Grid.Row="3" Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示13-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias12" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName12" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result12" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result13" MouseLeftButtonDown="finall_result13_MouseLeftButtonDown"  Grid.Row="3" Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示14-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias13" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName13" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result13" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result14" MouseLeftButtonDown="finall_result14_MouseLeftButtonDown"  Grid.Row="3" Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示15-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias14" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName14" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result14" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result15" MouseLeftButtonDown="finall_result15_MouseLeftButtonDown"  Grid.Row="3" Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示16-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias15" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName15" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result15" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result16" MouseLeftButtonDown="finall_result16_MouseLeftButtonDown"  Grid.Row="4" Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示17-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias16" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName16" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result16" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result17" MouseLeftButtonDown="finall_result17_MouseLeftButtonDown"  Grid.Row="4" Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示18-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias17" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName17" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result17" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result18" MouseLeftButtonDown="finall_result18_MouseLeftButtonDown"  Grid.Row="4" Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示19-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias18" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName18" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result18" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result19" MouseLeftButtonDown="finall_result19_MouseLeftButtonDown"  Grid.Row="4" Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示20-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias19" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName19" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result19" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result20" MouseLeftButtonDown="finall_result20_MouseLeftButtonDown"  Grid.Row="5" Grid.Column="0" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示21-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias20" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName20" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result20" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result21" MouseLeftButtonDown="finall_result21_MouseLeftButtonDown"  Grid.Row="5" Grid.Column="1" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示22-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias21" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName21" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result21" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result22" MouseLeftButtonDown="finall_result22_MouseLeftButtonDown"  Grid.Row="5" Grid.Column="2" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示23-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias22" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName22" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result22" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                    <Border x:Name="finall_result23" MouseLeftButtonDown="finall_result23_MouseLeftButtonDown"  Grid.Row="5" Grid.Column="3" Background="#7B7B7B" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                        <!--结果显示24-->
                        <StackPanel  Orientation="Vertical">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                <TextBlock x:Name="cameraAlias23" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></TextBlock>
                                <!--<TextBlock x:Name="deviceName23" Text=" " Height="30" Foreground="White" FontSize="15" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"/>-->
                            </StackPanel>
                            <Label x:Name="Finall_result23" Content="" Foreground="White" FontSize="30" FontFamily="Microsoft YaHei UI" FontWeight="Bold" HorizontalAlignment="Center"></Label>
                        </StackPanel>
                    </Border>
                </Grid>
                <Grid Grid.Row="2">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="1*"/>
                        <RowDefinition Height="3*"/>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Row="0" >
                        <Label Content="检测日志" HorizontalAlignment="Center" FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                    </StackPanel >
                    <Border Grid.Row="1" BorderBrush="White" BorderThickness="2" CornerRadius="5">
                        <ListView x:Name="LogListView" ItemsSource="{Binding LogEntries}"  VirtualizingStackPanel.IsVirtualizing="True" BorderThickness="0" >
                            <!--<ListView.Template>
                                <ControlTemplate TargetType="ListView">
                                    <ScrollViewer x:Name="ScrollViewer" VerticalScrollBarVisibility="Auto">
                                        <ItemsPresenter/>
                                    </ScrollViewer>
                                </ControlTemplate>
                            </ListView.Template>-->
                            <ListView.View>
                                <GridView>
                                    <GridViewColumn Header="时间" Width="80">
                                        <GridViewColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding Timestamp, StringFormat='HH:mm:ss'}"
                                   Foreground="{Binding Foreground}"/>
                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>
                                    <GridViewColumn Header="级别" Width="80">
                                        <GridViewColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding Level}" Foreground="{Binding Foreground}"/>
                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>
                                    <GridViewColumn Header="消息" Width="600">
                                        <GridViewColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding Message}"
                                   TextWrapping="Wrap"
                                   Foreground="{Binding Foreground}"/>
                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>
                                </GridView>
                            </ListView.View>
                        </ListView>
                    </Border>
                    <!--<Border Grid.Row="1" BorderBrush="White" BorderThickness="2" CornerRadius="5"  Background="#3C3C3C">
                        <TextBox Name="Log1" VerticalScrollBarVisibility="Hidden" Foreground="Black" BorderThickness="0"/>
                    </Border>-->
                </Grid>
            </Grid>
            <Grid Grid.Column="4">
                <!--参数设置-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="1.5*"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="1.5*"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="1.5*"/>
                    <RowDefinition Height="5*"/>
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0">
                    <Label  Content="工程设置" HorizontalAlignment="Center" FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                </StackPanel>
                <Grid Grid.Row="1">
                    <Border Grid.Row="0" BorderBrush="White" BorderThickness="2" CornerRadius="5"  Background="#3C3C3C">
                        <ScrollViewer VerticalScrollBarVisibility="Hidden"  HorizontalScrollBarVisibility="Hidden">
                            <StackPanel>
                                <!-- è¾“出设置 -->
                                <GroupBox Header="第①步:检测方案选择" Foreground="White"  Margin="0,0,0,10" FontSize="14">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <ComboBox Name="cmbDetectionPlans" DisplayMemberPath="FileName" SelectedValuePath="FullPath" Height="20" Width="100" HorizontalContentAlignment="Left" FontSize="12"/>
                                        <Button Name="ResultJudge_Path" Content="选择" Click="BtnSelectParam_Click" Width="50" Height="30" Margin="5,0,0,0" Style="{DynamicResource ButtonStyle}"/>
                                    </StackPanel>
                                </GroupBox>
                                <!-- æŽ¨ç†å¼•擎选择 -->
                                <GroupBox Header="第②步:模型选择" Margin="0,0,0,10" Foreground="White" FontSize="14">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <ComboBox Name="cmbModels" DisplayMemberPath="FileName" SelectedValuePath="FullPath" Height="20" Width="100" HorizontalContentAlignment="Left" FontSize="12"/>
                                        <Button Name="Model_Path" Click="BtnConfirmModel_Click" Content="确定" Width="50" Height="30" Margin="5,0,0,0" Style="{DynamicResource ButtonStyle}"/>
                                    </StackPanel>
                                </GroupBox>
                                <!-- å·¥ç¨‹æ–‡ä»¶å¯¼å‡º -->
                                <GroupBox Header="第③步:工程文件导出" Foreground="White" FontSize="14">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <Button Name="Proj" Content="导出" Click="BtnExport_Click" Width="60" Height="30" Style="{DynamicResource ButtonStyle}"/>
                                    </StackPanel>
                                </GroupBox>
                                <!-- å·¥ç¨‹æ–‡ä»¶åŠ è½½ -->
                                <GroupBox Header="第④步:工程文件加载" Foreground="White" FontSize="14">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <ComboBox Name="cmbProjects" DisplayMemberPath="FileName" SelectedValuePath="FullPath" Height="20" Width="100" HorizontalContentAlignment="Left" FontSize="12" Margin="0,0,5,0"/>
                                        <Button Content="加载" Click="BtnLoad_Click" Width="60" Height="30" Style="{DynamicResource ButtonStyle}"/>
                                    </StackPanel>
                                </GroupBox>
                                <!-- åˆ·æ–°æŒ‰é’® -->
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,10,0,0">
                                    <Button Content="刷新" Click="BtnRefreshModels_Click" Width="60" Height="30" Style="{DynamicResource ButtonStyle}"/>
                                </StackPanel>
                            </StackPanel>
                        </ScrollViewer>
                    </Border>
                </Grid>
                <StackPanel Grid.Row="2">
                    <Label  Content="通讯设置" HorizontalAlignment="Center" FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                </StackPanel>
                <Border Grid.Row="3" BorderBrush="White" BorderThickness="2" CornerRadius="5"  Background="#3C3C3C">
                    <Grid>
                        <Grid.RowDefinitions>
                            <!--<RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>-->
                        </Grid.RowDefinitions>
                        <TabControl HorizontalAlignment="Center" Background="#3C3C3C" BorderThickness="0">
                            <TabItem Header="ModBus" IsSelected="True" Width="80" Background="#7B7B7B" Style="{StaticResource  TabItemStyle}">
                                <StackPanel Margin="10">
                                    <TextBlock Text="服务器IP:" HorizontalAlignment="Center" Foreground="White"/>
                                    <ComboBox x:Name="Client_ServerIpComboBox" Width="140" IsEditable="True" SelectedIndex="0">
                                        <ComboBoxItem Content="192.168.0.20" Width="120"/>
                                    </ComboBox>
                                    <TextBlock Text="端口号:" HorizontalAlignment="Center" Foreground="White"/>
                                    <ComboBox x:Name="Client_PortComboBox" Width="140" SelectedIndex="0">
                                        <ComboBoxItem Content="502" Width="120" />
                                    </ComboBox>
                                    <TextBlock Background="#3C3C3C" Height="10"></TextBlock>
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <Button x:Name="Client_connect" Content="连接" Click="Client_Connect_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B"/>
                                        <!--<Button x:Name="Client_disconnect"  Content="断开" Click="Client_Disconnect_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B"/>-->
                                        <Button Content="清空" Click="Client_ClearClientLogs_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B"/>
                                    </StackPanel>
                                    <!--<TextBlock Text="数据发送:" HorizontalAlignment="Center" />
                                    <TextBox x:Name="Client_DataToSendTextBox" Width="200"/>
                                    <Button Content="发送" Click="Client_SendData_Click" />-->
                                    <!--<TextBlock Text="消息:" HorizontalAlignment="Center" Foreground="White"/>-->
                                    <ScrollViewer VerticalScrollBarVisibility="Hidden">
                                        <TextBox x:Name="Client_LogsTextBox" Height="80" IsReadOnly="True" TextWrapping="Wrap" FontSize="11"/>
                                    </ScrollViewer>
                                </StackPanel>
                            </TabItem>
                            <TabItem Header="TCP/IP" Width="80" Background="#7B7B7B" Style="{StaticResource TabItemStyle}" >
                                <ScrollViewer VerticalScrollBarVisibility="Hidden"  HorizontalScrollBarVisibility="Hidden">
                                    <StackPanel Margin="10">
                                        <TextBlock Text="服务器IP:" HorizontalAlignment="Center" Foreground="White"/>
                                        <ComboBox x:Name="TCPServer_IpComboBox" SelectedIndex="0">
                                            <ComboBoxItem Content="127.0.0.1" />
                                            <ComboBoxItem Content="0.0.0.0" />
                                        </ComboBox>
                                        <TextBlock Text="端口号:" HorizontalAlignment="Center" Foreground="White"/>
                                        <ComboBox x:Name="TCPServer_PortComboBox" SelectedIndex="0" IsEditable="True"
                                                  Text="{Binding Source={x:Static Properties:Settings.Default}, Path=DefaultPort, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                  SelectedValue="{Binding Source={x:Static Properties:Settings.Default}, Path=SelectedPort, Mode=TwoWay}">
                                            <ComboBoxItem Content="5011" Width="120"/>
                                            <ComboBoxItem Content="8080" Width="120"/>
                                        </ComboBox>
                                        <CheckBox x:Name="TCPServer_EnableHeartbeat" Content="开启心跳检测" Checked="TCPServer_EnableHeartbeat_Checked" Unchecked="TCPServer_EnableHeartbeat_Unchecked" Foreground="White" Margin="0,10,0,0"/>
                                        <StackPanel x:Name="TCPServer_HeartbeatPanel" Margin="0,5,0,0" Visibility="Collapsed">
                                            <TextBlock Text="心跳指令:" HorizontalAlignment="Center" Foreground="White"/>
                                            <TextBox x:Name="TCPServer_HeartbeatCommand" Text="heartBeat" HorizontalAlignment="Center"/>
                                            <TextBlock Text="心跳周期(ms):" HorizontalAlignment="Center" Foreground="White" Margin="0,5,0,0"/>
                                            <TextBox x:Name="TCPServer_HeartbeatInterval" Text="1000" HorizontalAlignment="Center"/>
                                        </StackPanel>
                                        <TextBlock Background="#3C3C3C" Height="10"></TextBlock>
                                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                            <Button x:Name="TCPServer_Start" Content="开启" ToolTip="服务器开启侦听" Click="TCPServer_Start_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B"/>
                                            <Button x:Name="TCPServer_Stop" Content="停止" ToolTip="服务器停止侦听" Click="TCPServer_Stop_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B" Margin="5,0,0,0"/>
                                        </StackPanel>
                                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                            <Button x:Name="RefreshIpButton" Content="刷新" ToolTip="刷新可用IP列表" Click="RefreshIpButton_Click" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B"/>
                                            <Button Content="清空" Click="TCPServer_ClearLogs_Click" ToolTip="清空日志栏" Style="{DynamicResource ButtonStyle}" Width="50" Height="25" Background="#7B7B7B" Margin="5,0,0,0"/>
                                        </StackPanel>
                                        <ScrollViewer VerticalScrollBarVisibility="Disabled"  Height="80" Margin="0,5,0,0">
                                            <TextBox x:Name="TCPServer_LogsTextBox" IsReadOnly="True" TextWrapping="Wrap" FontSize="11" MaxWidth="150"/>
                                        </ScrollViewer>
                                    </StackPanel>
                                </ScrollViewer>
                            </TabItem>
                        </TabControl>
                    </Grid>
                </Border>
                <StackPanel Grid.Row="4">
                    <Label  Content="日志" HorizontalAlignment="Center" FontSize="20"  FontFamily="Yu Gothic UI" Foreground="White"/>
                </StackPanel>
                <Border Grid.Row="5" BorderBrush="White" BorderThickness="2" CornerRadius="5"  Background="#3C3C3C">
                    <TextBox  Name="Log" VerticalScrollBarVisibility="Hidden" Foreground="Black" BorderThickness="0"/>
                </Border>
            </Grid>
        </Grid>
    </Grid>
</Window>
IDViewer_2D/MainWindow.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3494 @@

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using static SmartScanner.IDViewerDefines;
using static SmartScanner.IDViewerSDK;
using static SmartScanner.IDViewerSDK2;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
using System.IO;
using System.Runtime;
using OpenCvSharp;
using System.Windows.Media.Media3D;
using System.Collections.Generic;
using System.Threading;
using System.Net.Sockets;
using System.Text;
using static System.Net.Mime.MediaTypeNames;
using System.Net;
using System.Threading.Tasks;
using static OpenCvSharp.XImgProc.CvXImgProc;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using SmartScanner.ViewModel;
using SmartScanner.OperateLog;
using System.Windows.Input;
using System.Timers;
using System.Net.NetworkInformation;
namespace SmartScanner
{
    /// <summary>
    /// MainWindow.xaml çš„交互逻辑
    /// </summary>
    ///
    public partial class MainWindow : System.Windows.Window
    {
        //设备的句柄
        private readonly Dictionary<int, IntPtr> _deviceHandles = new Dictionary<int, IntPtr>();
        //图像句柄
        private readonly Dictionary<int, IntPtr> _imagePtr = new Dictionary<int, IntPtr>();
        //模型匹配
        private readonly Dictionary<int, IntPtr> _DetectorSelect = new Dictionary<int, IntPtr>();
        //选择的设备
        public int selectedIndex;
        //设备编号
        public int[] deviceIndex = new int[100];
        //连接设备个数
        int IsConnected = 0;
        public IntPtr devicesListHandle;
        //耗时计算
        Stopwatch stopwatch = new Stopwatch();
        ModbusTCPClient modbusTCPClient = new ModbusTCPClient();
        //实例化logç±»
        //EnhancedLogViewModel EnhancedLogViewModel.Instance = new EnhancedLogViewModel();
        //设备信息结构体句柄
        IDDeviceInfo[] deviceInfo = new IDDeviceInfo[100];
        delegate void IDViewerCallBack(IntPtr device, IntPtr image);
        delegate void IDViewerCallBack1(IntPtr device, IntPtr image);
        //检测连接状态定时器
        private System.Threading.Timer deviceStatusTimer;
        private int deviceStatusInterval = 3000; // 3秒
        //回调委托
        static IDViewerCallBack[] callbackDelegate;
        IDNodeParam iDNodeParam;
        //创建检测器
        public IntPtr detector = new IntPtr();
        public static string filePath = ".\\detector.txt";
        string Detector_Device = File.ReadAllText(filePath);
        //信号保持时间
        public static string holdtime = ".\\HoldTime.txt";
        public string Hold_Time = File.ReadAllText(holdtime);
        //信号保持时间
        public static string selflockingtime = ".\\SelflockingTime.txt";
        public string Selflocking_Time = File.ReadAllText(holdtime);
        //string Detector_Device = "CPU";
        //string modelPath = ".\\model\\best.onnx";
        //TCP通讯参数
        //private TcpListener _server;
        //private TcpClient _client;
        //private NetworkStream _stream;
        private TcpServerManager _tcpServerManager;
        //图像字节数组
        int batchSize = 2;
        byte[] imgBatch1 = null;
        byte[] imgBatch2 = null;
        //输出结果数组
        public bool[] outputs = new bool[20];
        private TextBlock[] cameraAliasLabels;
        private TextBlock[] deviceNames;
        //NG图片路径集合
        public List<string> Image_NG = new List<string>();
        //寄存器控制变量
        public int[] usOutput = new int[16];
        public int[] usOutput2 = new int[4];
        public bool USOUT = true;
        public int[] usOutput_tcp;
        //输出模式控制
        bool IsSignleOutput = false;
        //方案配置参数
        public string json;
        public ResultJudge.JudgmentConfiguration config = new ResultJudge.JudgmentConfiguration();
        //ModBus心跳定时器
        private System.Threading.Timer heartbeatTimer;
        private int heartbeatInterval = 30000; // 30秒
        //Modbus重连参数
        private int _reconnectAttempts = 0;//重连尝试次数
        private const int MAX_RECONNECT_ATTEMPTS = 5; //最大重连尝试次数
        private bool _isReconnecting = false;//是否正在重连
        private System.Threading.Timer _reconnectTimer;//重连定时器
        private const int RECONNECT_INTERVAL = 2000; // é‡è¿žé—´é𔿗¶é—´(毫秒)
        private string _lastIpAddress = ""; // æœ€åŽè¿žæŽ¥çš„IP地址
        private int _lastPort = 502; // æœ€åŽè¿žæŽ¥çš„端口
        //结果信号定时器
        private System.Timers.Timer OutputTimer;
        //定期删除图像
        private ImageCleanupService _cleanupService;
        public MainWindow()
        {
            if (!LBProtect.ValidateFingerprint())
            {
                MessageBox.Show("软件未授权在此硬件上运行!");
                Close();
                return;
            }
            InitializeComponent();
            DataContext = EnhancedLogViewModel.Instance;
            // å®šæœŸæ¸…图服务初始化
            InitializeCleanupService();
            LoadDataAsync();
            // SDK初始化
            InitSDK();
            // ç»“果显示界面初始化
            InitUI();
            // ç”¨æˆ·åå¥½è®¾ç½®åˆå§‹åŒ–
            InitUserConfig();
            for (int i = 0; i < outputs.Length; i++)
            {
                outputs[i] = false;
            }
            // é»˜è®¤åŠ è½½ä¸Šæ¬¡æ£€æµ‹æ–¹æ¡ˆ
            LoadLastUsedConfiguration(true);
            this.Closing += MainWindow_Closing;
            // èŽ·å–ListView中的ScrollViewer引用
            // èŽ·å–ScrollViewer引用并传递给ViewModel
            Loaded += (sender, e) =>
            {
                if (FindVisualChild<ScrollViewer>(LogListView) is ScrollViewer scrollViewer)
                {
                    EnhancedLogViewModel.Instance.LogScrollViewer = scrollViewer;
                }
            };
            this.WindowState = WindowState.Maximized;
            Loaded += (s, e) => RefreshIpButton_Click(null, null); // è‡ªåŠ¨åŠ è½½IP
            RefreshModelList(); // è‡ªåŠ¨åŠ è½½æ¨¡åž‹åˆ—è¡¨
            RefreshDetectionPlanList(); // è‡ªåŠ¨åŠ è½½æ£€æµ‹æ–¹æ¡ˆåˆ—è¡¨
            RefreshProjectList(); // è‡ªåŠ¨åŠ è½½å·¥ç¨‹æ–‡ä»¶åˆ—è¡¨
        }
        private async void LoadDataAsync()
        {
            LoadingWindow loadingWindow = new LoadingWindow();
            loadingWindow.Show();
            await Task.Delay(2000);
            loadingWindow.Close();
        }
        #region åˆå§‹åŒ–
        //SDK初始化
        private void InitSDK()
        {
            try
            {
                long result = IDVIEWER_Init_();
                if (result != 0)
                {
                    MessageBox.Show("SDK初始化失败,错误码:" + result);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        //界面初始化
        private void InitUI()
        {
            cameraAliasLabels = new TextBlock[30];
            //deviceNames = new TextBlock[30];
            cameraAliasLabels[0] = cameraAlias0;
            cameraAliasLabels[1] = cameraAlias1;
            cameraAliasLabels[2] = cameraAlias2;
            cameraAliasLabels[3] = cameraAlias3;
            cameraAliasLabels[4] = cameraAlias4;
            cameraAliasLabels[5] = cameraAlias5;
            cameraAliasLabels[6] = cameraAlias6;
            cameraAliasLabels[7] = cameraAlias7;
            cameraAliasLabels[8] = cameraAlias8;
            cameraAliasLabels[9] = cameraAlias9;
            cameraAliasLabels[10] = cameraAlias10;
            cameraAliasLabels[11] = cameraAlias11;
            cameraAliasLabels[12] = cameraAlias12;
            cameraAliasLabels[13] = cameraAlias13;
            cameraAliasLabels[14] = cameraAlias14;
            cameraAliasLabels[15] = cameraAlias15;
            cameraAliasLabels[16] = cameraAlias16;
            cameraAliasLabels[17] = cameraAlias17;
            cameraAliasLabels[18] = cameraAlias18;
            cameraAliasLabels[19] = cameraAlias19;
            cameraAliasLabels[20] = cameraAlias20;
            cameraAliasLabels[21] = cameraAlias21;
            cameraAliasLabels[22] = cameraAlias22;
            cameraAliasLabels[23] = cameraAlias23;
            //deviceNames[0] = deviceName0;
            //deviceNames[1] = deviceName1;
            //deviceNames[2] = deviceName2;
            //deviceNames[3] = deviceName3;
            //deviceNames[4] = deviceName4;
            //deviceNames[5] = deviceName5;
            //deviceNames[6] = deviceName6;
            //deviceNames[7] = deviceName7;
            //deviceNames[8] = deviceName8;
            //deviceNames[9] = deviceName9;
            //deviceNames[10] = deviceName10;
            //deviceNames[11] = deviceName11;
            //deviceNames[12] = deviceName12;
            //deviceNames[13] = deviceName13;
            //deviceNames[14] = deviceName14;
            //deviceNames[15] = deviceName15;
            //deviceNames[16] = deviceName16;
            //deviceNames[17] = deviceName17;
            //deviceNames[18] = deviceName18;
            //deviceNames[19] = deviceName19;
            //deviceNames[20] = deviceName20;
            //deviceNames[21] = deviceName21;
            //deviceNames[22] = deviceName22;
            //deviceNames[23] = deviceName23;
        }
        //用户配置初始化
        private void InitUserConfig()
        {
            DownloadData downloadData = new DownloadData();
            downloadData.Init();
            if (DownloadData.MemoryAlarm_main)
            {
                downloadData.CheckStorage();
            }
            IsSignleOutput = (bool)OutputCheckBox.IsChecked;
            //TCP端口初始化
            // å¦‚果从未设置过,使用默认值
            if (string.IsNullOrEmpty(Properties.Settings.Default.DefaultPort))
            {
                Properties.Settings.Default.DefaultPort = "8080";
                Properties.Settings.Default.SelectedPort = 8080;
            }
            // ç¡®ä¿ç«¯å£åœ¨åˆæ³•范围内
            if (Properties.Settings.Default.SelectedPort < 1 ||
                Properties.Settings.Default.SelectedPort > 65535)
            {
                Properties.Settings.Default.SelectedPort = 8080;
            }
            // å°è¯•选中已保存的端口
            foreach (ComboBoxItem item in TCPServer_PortComboBox.Items)
            {
                if (int.TryParse(item.Content.ToString(), out int port) &&
                    port == Properties.Settings.Default.SelectedPort)
                {
                    TCPServer_PortComboBox.SelectedItem = item;
                    return;
                }
            }
            // å¦‚果保存的端口不在预设列表中,显示在编辑框
            TCPServer_PortComboBox.Text = Properties.Settings.Default.SelectedPort.ToString();
        }
        //定期清图服务初始化
        private void InitializeCleanupService()
        {
            // ä»Žè®¾ç½®ä¸­èŽ·å–å‚æ•°
            string imageDir = Properties.Settings.Default.DataSavingRoad;
            int retentionDays = Properties.Settings.Default.DeleteImageDays;
            bool isEnabled = Properties.Settings.Default.ImageDeleteEnabled;
            if (isEnabled && !string.IsNullOrWhiteSpace(imageDir))
            {
                _cleanupService = new ImageCleanupService(imageDir, retentionDays);
                _cleanupService.Start();
            }
        }
        protected override void OnClosed(EventArgs e)
        {
            _cleanupService?.Stop();
            ExcelResultRecorder.FlushRecords();
            base.OnClosed(e);
        }
        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            DownloadData.isOP = false; // çª—口关闭时执行操作
                                       // å¯é€‰ï¼šå–消关闭(通过 e.Cancel = true)
            deviceStatusTimer?.Dispose();
            deviceStatusTimer = null;
            // æ¸…理Modbus相关定时器
            heartbeatTimer?.Dispose();
            heartbeatTimer = null;
            _reconnectTimer?.Dispose();
            _reconnectTimer = null;
            // åœæ­¢æ—¥å¿—自动保存服务
            EnhancedLogViewModel.Instance?.StopAutoSaveService();
            DisposeDetector_CPU(detector);
            if (devicesListHandle != IntPtr.Zero)
            {
                long result = IDVIEWER_UnInit_(devicesListHandle);
            }
            //TCP端口配置
            // éªŒè¯å½“前端口值
            if (int.TryParse(TCPServer_PortComboBox.Text, out int port) &&
                port >= 1 && port <= 65535)
            {
                Properties.Settings.Default.SelectedPort = port;
                Properties.Settings.Default.DefaultPort = port.ToString();
            }
            else
            {
                // æ¢å¤ä¸ºé»˜è®¤å€¼
                Properties.Settings.Default.SelectedPort = 8080;
                Properties.Settings.Default.DefaultPort = "8080";
            }
            Properties.Settings.Default.Save();
            foreach (System.Windows.Window window in System.Windows.Application.Current.Windows.OfType<DownloadData>().ToList())
            {
                window.Close();
            }
            Process.GetCurrentProcess().Kill();
        }
        // å½“设置变更时重新初始化服务
        private void OnSettingsChanged(object sender, EventArgs e)
        {
            _cleanupService?.Stop();
            InitializeCleanupService();
        }
        // è¾…助方法:查找视觉树中的子元素
        private static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child is T result)
                    return result;
                var childResult = FindVisualChild<T>(child);
                if (childResult != null)
                    return childResult;
            }
            return null;
        }
        #endregion
        #region è®¾å¤‡åˆ·æ–°ä¸Žè¿žæŽ¥
        private async void Refresh_Btn_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Refresh_Btn.IsEnabled = false;
                IsConnected = 0;
                // åŠ è½½ç›¸æœºè¿žæŽ¥é¡ºåºæ˜ å°„è¡¨
                var productManager = new ProductManager();
                var mapping = productManager.LoadConfig();
                bool Bl = true;
                if (mapping.Count == 0)
                {
                    MessageBox.Show("映射表为空,请先配置顺序和IP", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
                LoadingWindow loadingWindow = new LoadingWindow();
                loadingWindow.Show();
                loadingWindow.Loading.Text = "设备连接中,请稍候";
                await Task.Run(() =>
                {
                    // åˆ·æ–°ç›¸æœºåˆ—表
                    RefreshDeviceList();
                    // æŒ‰ç…§æ˜ å°„表顺序连接相机
                    foreach (var item in mapping.OrderBy(x => x.Key))
                    {
                        int sequence = item.Key;
                        string ip = item.Value;
                        ConnectDeviceByIP(sequence, ip);
                    }
                    Bl = false;
                });
                await Task.Run(() =>
                    {
                        while (true)
                        {
                            if (!Bl)
                            {
                                this.Dispatcher.Invoke(new Action(() =>
                            {
                                Refresh_Btn.IsEnabled = true;
                            }));
                                break;
                            }
                        }
                    });
                loadingWindow.Close();
                // åˆ›å»ºå®šæ—¶å™¨ï¼Œå®šæ—¶æ£€æµ‹è®¾å¤‡è¿žæŽ¥çŠ¶æ€
                deviceStatusTimer = new System.Threading.Timer(DeviceConnectbeatCallback, null, Timeout.Infinite, deviceStatusInterval);
                // å¯åŠ¨å®šæ—¶å™¨ï¼Œç«‹å³å¼€å§‹å¹¶æ¯éš”MemoryAlarmInterval毫秒执行一次
                deviceStatusTimer.Change(0, deviceStatusInterval);
                GetMessage($"设备已全部连接完成\n连接台数:{IsConnected}");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"请先配置相机连接顺序:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        // åˆ·æ–°ç›¸æœºåˆ—表
        private void RefreshDeviceList()
        {
            try
            {
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    DeviceListBox.Items.Clear();
                }));
                // èŽ·å–è®¾å¤‡åˆ—è¡¨å¥æŸ„
                devicesListHandle = IDVIEWER_DiscoveryDevices_(500);
                Console.WriteLine($"获取设备列表句柄");
                // èŽ·å–è®¾å¤‡æ€»æ•°
                int deviceCount = (int)IDVIEWER_GetDevicesLength_(devicesListHandle);
                Console.WriteLine($"获取设备总数:{deviceCount}");
                Task.Run(() => GetMessage($"检测到 {deviceCount} å°è®¾å¤‡"));
                // èŽ·å–ç›¸æœºIP列表
                for (int i = 0; i < deviceCount; i++)
                {
                    IDViewerSDK.IDVIEWER_SelectIDDeviceInfo_(devicesListHandle, ref deviceInfo[i], (uint)i);
                    string deviceIP = deviceInfo[i].cameraIP.Trim();
                    // å°†ç›¸æœºæ·»åŠ åˆ°ç•Œé¢åˆ—è¡¨
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        DeviceListBox.Items.Add(deviceIP);
                    }));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"设备检测失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        // é€šè¿‡IP连接相机
        private void ConnectDeviceByIP(int sequence, string ip)
        {
            IntPtr deviceHandle = IntPtr.Zero;
            IntPtr imagePtr = IntPtr.Zero;
            try
            {
                // åˆ›å»ºè®¾å¤‡å¥æŸ„
                IDVIEWER_CreateDeviceByIP_(ip, ref deviceHandle);
                if (deviceHandle == IntPtr.Zero)
                {
                    MessageBox.Show($"未搜索到该设备:{ip}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
                // æ‰“开设备
                IDDevice_Open(deviceHandle);
                // è¯»è®¾å¤‡å½“前各项参数
                double getGain = 0.0;
                long resultGetGain_1330 = IDDevice_GetGain_1330(deviceHandle, 0, ref getGain);
                IDDeviceHarewareParams iDDeviceHarewareParams;
                iDDeviceHarewareParams = IDDevice_GetHardWareParams(deviceHandle);
                IDNodeParam focusingLocation1 = iDDeviceHarewareParams.exposure;
                IDNodeParam focusingLocation2 = iDDeviceHarewareParams.gamma;
                float getexposure = focusingLocation1.value;
                float getgamma = focusingLocation2.value;
                Console.WriteLine($"{sequence}号设备当前曝光:{getexposure}");
                Console.WriteLine($"{sequence}号设备当前增益:{getGain}");
                Console.WriteLine($"{sequence}号设备当前伽马:{getgamma}");
                Console.WriteLine($"设备{sequence}连接成功");
                // æ£€æŸ¥è®¾å¤‡æ˜¯å¦è¿žæŽ¥æˆåŠŸ
                long isConnected = IDDevice_IsConnected(deviceHandle);
                if (isConnected != 1)
                {
                    MessageBox.Show($"设备连接失败:{ip}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        DeviceListBox.Items.Remove(ip);
                    }));
                    return;
                }
                // åˆå§‹åŒ–图像句柄
                long result = IDImage_Init(ref imagePtr);
                // å­˜å‚¨è®¾å¤‡å’Œå›¾åƒå¥æŸ„
                _deviceHandles[sequence] = deviceHandle;
                _imagePtr[sequence] = imagePtr;
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    cameraAliasLabels[sequence - 1].Text = sequence.ToString();
                    //deviceNames[sequence - 1].Text = deviceInfo[sequence - 1].cameraAlias;
                }));
                IsConnected++;
                // SDK存在BUG,相机连接后取的前几张图异常,临时解决方案
                // è¿žæŽ¥åŽå–3张图丢弃
                //for (int i = 0; i <= 3; i++)
                //{
                //    IDDevice_CaptureImage(deviceHandle, imagePtr);
                //}
                Refresh_ImageParameter(deviceHandle);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"连接设备时出错:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    DeviceListBox.Items.Remove(ip);
                }));
            }
        }
        static List<double> gainList = new List<double>();
        static IDDOParamsCreate iDDOParamsCreate = new IDDOParamsCreate();
        static IDDOParams iDDOParams = iDDOParamsCreate.create();
        static void Refresh_ImageParameter(IntPtr device)
        {
            /******获取增益******/
            int count = 0;
            long resultCount = IDDevice_GetGainCount(device, ref count);
            double getAtGain = 0.0;
            IDDevice_GetGain_1330(device, 0, ref getAtGain);
            double Gain = 0.0;
            for (int i = 0; i < count; i++)
            {
                IDDevice_SetGain(device, 0, i);
                long ii = IDDevice_GetGain_1330(device, 0, ref Gain);
                if (ii == 0)
                {
                    gainList.Add(Gain);
                }
            }
            double searchValue = getAtGain;
            // åœ¨ List ä¸­æŸ¥æ‰¾è¯¥å¢žç›Šå€¼
            int index = gainList.IndexOf(searchValue);
            if (index >= 0)
            {
                IDDevice_SetGain(device, 0, index);
            }
            IDDeviceHarewareParams iDDeviceHarewareParams;
            iDDeviceHarewareParams = IDDevice_GetHardWareParams(device);
            IDNodeParam focusingLocation = iDDeviceHarewareParams.focusingLocation;
            IDNodeParam focusingLocation1 = iDDeviceHarewareParams.exposure;
            IDNodeParam focusingLocation2 = iDDeviceHarewareParams.gamma;
            float maxValue = focusingLocation.maxValue;
            float CurrentValue = focusingLocation.value;
            float getexposure = focusingLocation1.value;
            float getgamma = focusingLocation2.value;
            //添加DO到方案,只需执行一次。
            for (int i = 0; i <= 2; i++)
            {
                iDDOParams.pin = (uint)i;
                iDDOParams.status = 0;
                iDDOParams.doModel = 0;
                iDDOParams.durationTime = 2000;
                iDDOParams.doSource = IDDoEventSource.EVENT_SOURCE_OFF_C;
                long retm8 = addDOParam(device, ref iDDOParams);
                Console.WriteLine("当前添加第" + i + "组,ret:" + retm8);
            }
            /******将获取的参数设置一次******/
            //double getexposure1 = getexposure;
            //double getgamma1 = getgamma;
            //int CurrentValue1 = (int)CurrentValue;
            //long g1 = IDDevice_SetExposure(device, 0, getexposure1);
            //long g3 = IDDevice_SetGamma(device, 0, getgamma1);
            //long g4 = IDDevice_SetFocusLocation(device, 0, CurrentValue1);
        }
        #endregion
        #region è®¾å¤‡ä¿¡æ¯æ˜¾ç¤º
        private void DeviceListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (DeviceListBox.SelectedIndex != -1)
            {
                CameraIP.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraIP.Trim();
                CameraNetMask.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraNetMask.Trim();
                CameraGateWay.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraGateWay.Trim();
                CameraFirmwareVersion.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraFirmwareVersion.Trim();
                CameraAlias.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraAlias;
                CameraModel.Text = deviceInfo[DeviceListBox.SelectedIndex].cameraModel.Trim();
            }
            else { return; }
        }
        #endregion
        #region æ—¥å¿—显示
        //日志显示
        private void GetMessage(string obj)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                Log.AppendText(obj + Environment.NewLine);
                Log.ScrollToEnd();
            }));
        }
        //ModBus日志显示
        private void GetMessage_Modbus(string obj)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                Client_LogsTextBox.AppendText(obj + Environment.NewLine);
                Client_LogsTextBox.ScrollToEnd();
            }));
        }
        #endregion
        //深度学习模型推理模块
        private void Reasoning_AI(IntPtr detector, byte[] ImageBath, int Image_Width, int Image_Height, out int[] classIds, out int[] numBoxes, out float[] prob,
            out float[] x1, out float[] y1, out float[] x2, out float[] y2, int sequence)
        {
            // åˆå§‹åŒ–输出参数
            batchSize = 1;
            x1 = new float[100];
            y1 = new float[100];
            x2 = new float[100];
            y2 = new float[100];
            prob = new float[100];
            classIds = new int[100];
            numBoxes = new int[batchSize];
            try
            {
                // æ£€æŸ¥ detector æŒ‡é’ˆæ˜¯å¦æœ‰æ•ˆ
                if (detector == IntPtr.Zero)
                {
                    throw new ArgumentNullException(nameof(detector), "Detector pointer is null (IntPtr.Zero)");
                }
                // æ£€æŸ¥ ImageBath æ˜¯å¦ä¸ºç©ºæˆ–大小不正确
                if (ImageBath == null || ImageBath.Length == 0)
                {
                    throw new ArgumentException("Image batch data is null or empty", nameof(ImageBath));
                }
                // æ£€æŸ¥å›¾åƒå°ºå¯¸æ˜¯å¦åˆç†
                if (Image_Width <= 0 || Image_Height <= 0)
                {
                    throw new ArgumentException($"Invalid image dimensions: Width={Image_Width}, Height={Image_Height}");
                }
                // æ£€æŸ¥ batchSize æ˜¯å¦åˆç†
                if (batchSize <= 0)
                {
                    throw new InvalidOperationException($"Invalid batch size: {batchSize}");
                }
                // æ£€æŸ¥è¾“出缓冲区是否足够大
                if (x1.Length < 100 || y1.Length < 100 || x2.Length < 100 || y2.Length < 100 || prob.Length < 100 || classIds.Length < 100)
                {
                    throw new InvalidOperationException("Output buffer size is too small (must be at least 100)");
                }
                // è°ƒç”¨ C++ API
                PredictDetector_CPU(
                    detector,
                    ImageBath,
                    x1, y1, x2, y2,
                    prob,
                    classIds,
                    numBoxes,
                    100,
                    Image_Width,
                    Image_Height,
                    batchSize,
                    0.25f,
                    0.3f,
                    1,
                    sequence
                );
            }
            catch (SEHException ex)
            {
                // è®°å½•详细的错误信息
                Console.Error.WriteLine($"SEHException in PredictDetector_CPU: {ex.Message}");
                Console.Error.WriteLine($"Detector: {detector}");
                Console.Error.WriteLine($"ImageBatch Length: {ImageBath?.Length ?? 0}");
                Console.Error.WriteLine($"Image Size: {Image_Width}x{Image_Height}");
                Console.Error.WriteLine($"Batch Size: {batchSize}");
                // å¯ä»¥é€‰æ‹©é‡æ–°æŠ›å‡ºæˆ–返回默认值
                throw new InvalidOperationException("Failed to run AI reasoning due to native code error", ex);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error in Reasoning_AI: {ex.Message}");
                throw;
            }
        }
        // æµ‹è¯•方法
        private void Start_Detector_Btn_Click(object sender, RoutedEventArgs e)
        {
            string images_path = "D:\\01 LBImage\\20241010\\10_59_24_2.bmp";
            Mat mat = Cv2.ImRead(images_path);
            int width = mat.Width;
            int height = mat.Height;
            int channel = mat.Channels();
            byte[] imgBatch = new byte[width * height * channel];
            int batchSize = 1;
            float[] x1 = new float[1000], y1 = new float[1000], x2 = new float[1000], y2 = new float[1000];
            float[] prob = new float[1000];
            int[] classIds = new int[1000];
            int[] numBoxes = new int[batchSize];
            Marshal.Copy(mat.Data, imgBatch, 0, imgBatch.Length);
            PredictDetector_CPU(detector, imgBatch, x1, y1, x2, y2, prob, classIds, numBoxes, 100, width, height, batchSize, 0.25f, 0.3f, 1, 1);
            for (int i = 0; i < batchSize; i++)
            {
                for (int j = 0; j < numBoxes[i]; j++)
                {
                    float x1Val = x1[j];
                    float y1Val = y1[j];
                    float x2Val = x2[j];
                    float y2Val = y2[j];
                    float probVal = prob[j];
                    int classId = classIds[j];
                }
            }
        }
        #region ModBus通讯设置与检测模块
        #region åŠ è½½ç«¯å£
        private void LoadPorts()
        {
            //Server_PortComboBox.ItemsSource = new[] { "8000", "8001", "8002" };
            //Client_PortComboBox.ItemsSource = new[] { "8000", "8001", "8002" };
            Client_PortComboBox.ItemsSource = new[] { "502" };
        }
        #endregion
        #region ModBus通讯模块
        private void Client_Connect_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (Client_ServerIpComboBox.Text != "" && Client_PortComboBox.SelectedItem != null)
                {
                    string ipAddress = Client_ServerIpComboBox.Text;
                    int port = int.Parse(Client_PortComboBox.Text);
                    // ä¿å­˜è¿žæŽ¥ä¿¡æ¯ç”¨äºŽé‡è¿ž
                    _lastIpAddress = ipAddress;
                    _lastPort = port;
                    modbusTCPClient.ModbudTCP_Connect(ipAddress, port);
                    if (modbusTCPClient._client == null)
                    {
                        //MessageBox.Show("连接到服务器失败,请检查连接后重试");
                        return;
                    }
                    // åˆå§‹åŒ–重连定时器
                    InitializeReconnectTimer();
                    // åˆ›å»ºå®šæ—¶å™¨ï¼Œä½œä¸ºModBus心跳信号
                    heartbeatTimer = new System.Threading.Timer(HeartbeatCallback, null, Timeout.Infinite, heartbeatInterval);
                    // å¯åŠ¨å®šæ—¶å™¨ï¼Œç«‹å³å¼€å§‹å¹¶æ¯éš”heartbeatInterval毫秒执行一次
                    heartbeatTimer.Change(0, heartbeatInterval);
                    // å¼€å§‹ä¾¦å¬å®¢æˆ·ç«¯è§¦å‘信号
                    Task.Run(() => ClientListen());
                    GetMessage_Modbus($"连接成功 {ipAddress}:{port}\n");
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LinkState.Text = "ModBus已连接";
                        LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
                    }));
                }
                else
                {
                    MessageBox.Show("请输入正确的IP和端口");
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LinkState.Text = "未连接";
                        LinkState.Foreground = System.Windows.Media.Brushes.Red;
                    }));
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("地址和端口已被占用");
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    LinkState.Text = "未连接";
                    LinkState.Foreground = System.Windows.Media.Brushes.Red;
                }));
                return;
            }
        }
        //ModBus断开连接
        private void Client_Disconnect_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // åœæ­¢æ‰€æœ‰å®šæ—¶å™¨
                heartbeatTimer?.Change(Timeout.Infinite, Timeout.Infinite);
                _reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
                if (modbusTCPClient._client != null && modbusTCPClient._client.Connected)
                {
                    modbusTCPClient._client?.Close();
                    modbusTCPClient._client = null;
                    GetMessage_Modbus("连接已断开\n");
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LinkState.Text = "未连接";
                        LinkState.Foreground = System.Windows.Media.Brushes.Red;
                    }));
                }
                // é‡ç½®é‡è¿žçŠ¶æ€
                _reconnectAttempts = 0;
                _isReconnecting = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接断开");
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    LinkState.Text = "未连接";
                    LinkState.Foreground = System.Windows.Media.Brushes.Red;
                }));
            }
        }
        private void Client_ClearClientLogs_Click(object sender, RoutedEventArgs e)
        {
            Client_LogsTextBox.Clear();
        }
        #endregion
        #region å›¾åƒé‡‡é›†ä¸Žå¤„理模块
        //获取图像并处理
        private void GetImage()
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                DetectState.Text = "正在检测中。。。";
                DetectState.Foreground = System.Windows.Media.Brushes.LightGreen;
            }));
            //计时器启动
            stopwatch.Reset();
            stopwatch.Start();
            Console.WriteLine($"计时器启动!");
            //加载上次解决方案
            bool isL = LoadLastUsedConfiguration(false);
            if (!isL)
            {
                stopwatch.Stop();
                long F_elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
                Console.WriteLine($"系统响应时间为:{F_elapsedMilliseconds}ms");
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    DetectState.Text = "未在检测";
                    DetectState.Foreground = System.Windows.Media.Brushes.Red;
                }));
                return;
            }
            for (int i = 0; i < DeviceListBox.Items.Count; i++)
            {
                //采集图像
                GetIDDevice_CaptureImage(i + 1);
            }
            for (int i = 0; i < DeviceListBox.Items.Count; i++)
            {
                //处理图像
                Reasoning_Image(i + 1);
            }
            stopwatch.Stop();
            long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
            Console.WriteLine($"系统响应时间为:{elapsedMilliseconds}ms");
            EnhancedLogViewModel.Instance.AddLog($"系统响应时间为:{elapsedMilliseconds}ms");
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                DetectState.Text = "未在检测";
                DetectState.Foreground = System.Windows.Media.Brushes.Red;
            }));
            //NG图像弹窗显示与保存
            if (Image_NG.Count != 0)
            {
                Task.Run(() =>
                {
                    List<string> Image_NG_Save = new List<string>(Image_NG);
                    // NG图像弹窗显示
                    OnDetectionCompleted(Image_NG);
                    // NG图像自动保存
                    int savedCount = AutoSaveNGImages(Image_NG_Save);
                    EnhancedLogViewModel.Instance.AddLog($"成功保存了 {savedCount} å¼ NG图片");
                    Image_NG_Save.Clear();
                });
            }
            //检测结果通过ModBus存入寄存器
            try
            {
                if (modbusTCPClient._client != null)
                {
                    if (!IsSignleOutput)
                    {
                        // å°†äºŒè¿›åˆ¶æ•°ç»„转换为ushort
                        ushort value = BinaryToUshort_MSBFirst(usOutput);//1号-16号相机
                        ushort value2 = BinaryToUshort_MSBFirst(usOutput2);//17-20号相机
                        // å°†ushort存储在ushort数组中
                        ushort[] test = new ushort[] { value };
                        ushort[] test2 = new ushort[] { value2 };
                        modbusTCPClient.MultipleRegistersWrite(3, test);//1号-16号相机
                        modbusTCPClient.MultipleRegistersWrite(4, test2);//17-20号相机
                        EnhancedLogViewModel.Instance.AddLog($"检测结果保持{Hold_Time}秒");
                        if (double.TryParse(Hold_Time, out double interval))
                        {
                            OutputTimer = new System.Timers.Timer(interval * 1000);
                        }
                        else
                        {
                            MessageBox.Show("保持时间格式错误,请检查配置", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                            return;
                        }
                        OutputTimer.Elapsed += OnTimedEvent;
                        OutputTimer.AutoReset = false; // è®¾ç½®ä¸ºfalse表示只触发一次
                        OutputTimer.Start();
                    }
                    else
                    {
                        if (USOUT)
                        {
                            modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 1 });
                            EnhancedLogViewModel.Instance.AddLog($"检测结果保持5秒");
                            OutputTimer = new System.Timers.Timer(5000);
                            OutputTimer.Elapsed += OnTimedEvent;
                            OutputTimer.AutoReset = false; // è®¾ç½®ä¸ºfalse表示只触发一次
                            OutputTimer.Start();
                        }
                        else
                        {
                            modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
                        }
                    }
                }
                else if (TcpServerManager._isRunning)
                {
                    //usOutput_tcp
                }
                else
                {
                    // èŽ·å–å½“å‰æ—¥æœŸ
                    DateTime currentDate = DateTime.Now;
                    // æ ¼å¼åŒ–时间为 "HHmmss"
                    string timeFileName = currentDate.ToString("HH:mm:ss");
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LinkState.Text = "未连接";
                        LinkState.Foreground = System.Windows.Media.Brushes.Red;
                    }));
                    //MessageBox.Show($"ModBus未连接", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    GetMessage_Modbus($"{timeFileName} ModBus未连接");
                }
                USOUT = true;
            }
            catch (NullReferenceException ex)
            {
                MessageBox.Show($"ModBus未连接:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            USOUT = true;
        }
        private ImageDisplayWindow _imageDisplayWindow;
        //NG图像弹窗显示
        private void OnDetectionCompleted(List<string> imagePath)
        {
            if (imagePath.Count != 0)
            {
                // ä½¿ç”¨Dispatcher确保UI线程操作
                Dispatcher.Invoke(() =>
                {
                    // æ£€æŸ¥çª—口是否已存在
                    if (_imageDisplayWindow == null || !_imageDisplayWindow.IsLoaded)
                    {
                        _imageDisplayWindow = new ImageDisplayWindow();
                        _imageDisplayWindow.Closed += (s, e) => { _imageDisplayWindow = null; };
                        _imageDisplayWindow.Show();
                        _imageDisplayWindow.Topmost = true;
                    }
                    // æ·»åŠ å›¾ç‰‡åˆ°æŸ¥çœ‹å™¨
                    _imageDisplayWindow.AddImage(imagePath);
                });
                Image_NG.Clear();
            }
        }
        //图像处理
        private void Reasoning_Image(int Sequence)
        {
            IntPtr deviceHandle = _deviceHandles[Sequence];
            IntPtr imagePtr = _imagePtr[Sequence];
            int[] classIds;     //目标物类别
            int[] numBoxes;     //目标物数量
            float[] prob;       //目标物得分
            float[] x1 = new float[100], y1 = new float[100], x2 = new float[100], y2 = new float[100];
            if (imagePtr == IntPtr.Zero)
            {
                GetMessage($"设备{Sequence}连接已断开");
                EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}连接已断开", "ERROR");
                return;
            }
            long Image_Width = IDImage_Width(imagePtr);
            long Image_Height = IDImage_Height(imagePtr);
            long Image_Channels = IDImage_Channels(imagePtr);
            long dataLength = Image_Width * Image_Height * Image_Channels;
            byte[] Imagedata = new byte[dataLength];
            byte[] bytes = new byte[Image_Width * Image_Height * 3];
            IntPtr Image_ImageData = IDImage_ImageData(imagePtr);
            if (imagePtr == IntPtr.Zero)
            {
                MessageBox.Show("图像句柄无效");
            }
            if (dataLength != 0)
            {
                Console.WriteLine($"获取日期");
                // èŽ·å–å½“å‰æ—¥æœŸ
                DateTime currentDate = DateTime.Now;
                // æ ¼å¼åŒ–日期为 "yyyyMMdd"
                string datePath = currentDate.ToString("yyyyMMdd");
                // æ ¼å¼åŒ–时间为 "HHmmss"
                string timeFileName = currentDate.ToString("HH_mm_ss");
                // æž„建完整路径
                string folderPath = $@"{DownloadData.ImageSavingPath}\{datePath}";
                string filePath = Path.Combine(folderPath, $"{timeFileName + "_" + Sequence + DownloadData.ImageFormat_main}");
                // æ£€æŸ¥æ–‡ä»¶å¤¹æ˜¯å¦å­˜åœ¨ï¼Œå¦‚果不存在则创建
                if (!Directory.Exists(folderPath))
                {
                    Directory.CreateDirectory(folderPath);
                }
                Console.WriteLine($"图像句柄转换为字节数据");
                Marshal.Copy(Image_ImageData, Imagedata, 0, (int)dataLength);           //图像句柄转换为字节数据
                ConvertSingletoThreeChannels(detector, Imagedata, (int)Image_Width, (int)Image_Height, bytes);
                //原图保存至本地
                if (DownloadData.ImageSave)
                {
                    IDImage_SaveImage(imagePtr, filePath, DownloadData.ImageCompressionRatio_main);
                    EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}图像已保存至{filePath}");
                }
                EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备图像预处理完成,开始进行算法推理");
                //深度学习推理模型
                Reasoning_AI(detector, bytes, (int)Image_Width, (int)Image_Height, out classIds, out numBoxes, out prob, out x1, out y1, out x2, out y2, Sequence);
                EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备算法推理完成,开始进行结果判断");
                //结果判断
                switch (Sequence)
                {
                    case 1:
                        int isPass1 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass1;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass1;
                        if (isPass1 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result0.Content = "OK";
                                finall_result0.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result0.Content = "NG";
                                finall_result0.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 2:
                        int isPass2 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass2;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass2;
                        if (isPass2 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result1.Content = "OK";
                                finall_result1.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result1.Content = "NG";
                                finall_result1.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 3:
                        int isPass3 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass3;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass3;
                        if (isPass3 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result2.Content = "OK";
                                finall_result2.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result2.Content = "NG";
                                finall_result2.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 4:
                        int isPass4 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass4;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass4;
                        if (isPass4 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result3.Content = "OK";
                                finall_result3.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result3.Content = "NG";
                                finall_result3.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 5:
                        int isPass5 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass5;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass5;
                        if (isPass5 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result4.Content = "OK";
                                finall_result4.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result4.Content = "NG";
                                finall_result4.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 6:
                        int isPass6 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass6;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass6;
                        if (isPass6 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result5.Content = "OK";
                                finall_result5.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result5.Content = "NG";
                                finall_result5.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 7:
                        int isPass7 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass7;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass7;
                        if (isPass7 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result6.Content = "OK";
                                finall_result6.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result6.Content = "NG";
                                finall_result6.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 8:
                        int isPass8 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass8;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass8;
                        if (isPass8 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result7.Content = "OK";
                                finall_result7.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result7.Content = "NG";
                                finall_result7.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 9:
                        int isPass9 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass9;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass9;
                        if (isPass9 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result8.Content = "OK";
                                finall_result8.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result8.Content = "NG";
                                finall_result8.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 10:
                        int isPass10 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass10;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass10;
                        if (isPass10 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result9.Content = "OK";
                                finall_result9.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result9.Content = "NG";
                                finall_result9.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 11:
                        int isPass11 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass11;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass11;
                        if (isPass11 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result10.Content = "OK";
                                finall_result10.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result10.Content = "NG";
                                finall_result10.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 12:
                        int isPass12 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass12;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass12;
                        if (isPass12 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result11.Content = "OK";
                                finall_result11.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                            //Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result11.Content = "NG";
                                finall_result11.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 13:
                        int isPass13 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass13;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass13;
                        if (isPass13 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result12.Content = "OK";
                                finall_result12.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result12.Content = "NG";
                                finall_result12.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 14:
                        int isPass14 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass14;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass14;
                        if (isPass14 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result13.Content = "OK";
                                finall_result13.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result13.Content = "NG";
                                finall_result13.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 15:
                        int isPass15 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass15;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass15;
                        if (isPass15 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result14.Content = "OK";
                                finall_result14.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result14.Content = "NG";
                                finall_result14.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 16:
                        int isPass16 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput[Sequence - 1] = isPass16;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass16;
                        if (isPass16 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result15.Content = "OK";
                                finall_result15.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result15.Content = "NG";
                                finall_result15.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 17:
                        int isPass17 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput2[Sequence - 17] = isPass17;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass17;
                        if (isPass17 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result16.Content = "OK";
                                finall_result16.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result16.Content = "NG";
                                finall_result16.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 18:
                        int isPass18 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput2[Sequence - 17] = isPass18;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass18;
                        if (isPass18 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result17.Content = "OK";
                                finall_result17.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result17.Content = "NG";
                                finall_result17.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 19:
                        int isPass19 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput2[Sequence - 17] = isPass19;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass19;
                        if (isPass19 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result18.Content = "OK";
                                finall_result18.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result18.Content = "NG";
                                finall_result18.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                    case 20:
                        int isPass20 = config.JudgeDetectionResult(Sequence, numBoxes, classIds, prob);
                        usOutput2[Sequence - 17] = isPass20;
                        if (TcpServerManager._isRunning && usOutput_tcp != null) usOutput_tcp[Sequence - 1] = isPass20;
                        if (isPass20 == 1)
                        {
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result19.Content = "OK";
                                finall_result19.Background = System.Windows.Media.Brushes.Green;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹é€šè¿‡");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "OK");
                            });
                        }
                        else
                        {
                            USOUT = false;
                            this.Dispatcher.BeginInvoke(new Action(() =>
                            {
                                Finall_result19.Content = "NG";
                                finall_result19.Background = System.Windows.Media.Brushes.Red;
                            }));
                            Console.WriteLine($"点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡");
                            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:点位 {Sequence} æ£€æµ‹ä¸é€šè¿‡", "ERROR");
                            Image_NG.Add($".\\vino_res\\result_{Sequence}.jpg");
                            Task.Run(() =>
                            {
                                // è®°å½•到Excel(批量写入)
                                ExcelResultRecorder.RecordDetectionResult(Sequence, "NG");
                            });
                        }
                        break;
                }
            }
        }
        //图像采集
        private void GetIDDevice_CaptureImage(int Sequence)
        {
            IntPtr deviceHandle = _deviceHandles[Sequence];
            IntPtr imagePtr = _imagePtr[Sequence];
            // å¼€å§‹é‡‡é›†å›¾åƒ
            Console.WriteLine($"{Sequence}号设备开始采集图像");
            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备开始采集图像");
            long rel = IDDevice_IsOpen(deviceHandle);
            if (rel == 0)
            {
                MessageBox.Show($"设备{Sequence}连接已断开", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                EnhancedLogViewModel.Instance.AddLog($"设备{Sequence}连接已断开", "ERROR");
                _imagePtr[Sequence] = IntPtr.Zero;
                return;
            }
            IDDevice_CaptureImage(deviceHandle, imagePtr);
            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:{Sequence}号设备图像采集结束,开始进行图像预处理");
        }
        #endregion
        // æ•°æ®è½¬æ¢
        static ushort BinaryToUshort_MSBFirst(int[] binaryArray)
        {
            if (binaryArray.Length > 16)
                throw new ArgumentException("Binary array cannot exceed 16 bits.");
            ushort result = 0;
            for (int i = 0; i < binaryArray.Length; i++)
            {
                if (binaryArray[i] == 1)
                    result |= (ushort)(1 << i); // ä½Žä½åœ¨å‰
                else if (binaryArray[i] != 0)
                    throw new ArgumentException("Binary array can only contain 0s and 1s.");
            }
            return result;
        }
        /// <summary>
        /// è‡ªåŠ¨ä¿å­˜NG图片到指定日期目录
        /// ä¿å­˜è·¯å¾„格式:D:\01 LBImage_NG\(当前日期)\
        /// å¦‚果目录不存在会自动创建,支持批量保存操作
        /// </summary>
        /// <param name="ngImagePaths">NG图片路径集合</param>
        /// <returns>成功保存的图片数量</returns>
        public int AutoSaveNGImages(List<string> ngImagePaths)
        {
            // æ ¡éªŒè¾“入参数
            if (ngImagePaths == null || ngImagePaths.Count == 0)
            {
                EnhancedLogViewModel.Instance.AddLog($"NG图片路径集合为空,无需保存操作。");
                return 0;
            }
            int successCount = 0;  // æˆåŠŸä¿å­˜çš„è®¡æ•°å™¨
            string baseDirectory = @"D:\01 LBImage_NG";  // åŸºç¡€ä¿å­˜ç›®å½•
            try
            {
                // èŽ·å–å½“å‰ç³»ç»Ÿæ—¥æœŸï¼Œæ ¼å¼åŒ–ä¸ºyyyyMMdd
                string dateFolderName = DateTime.Now.ToString("yyyyMMdd");
                // æž„建完整的目标目录路径
                string targetDirectory = Path.Combine(baseDirectory, dateFolderName);
                // å¦‚果目标目录不存在,则创建
                if (!Directory.Exists(targetDirectory))
                {
                    Directory.CreateDirectory(targetDirectory);
                }
                // éåŽ†æ‰€æœ‰NG图片路径
                foreach (string sourcePath in ngImagePaths)
                {
                    try
                    {
                        // æ£€æŸ¥æºæ–‡ä»¶æ˜¯å¦å­˜åœ¨
                        if (!File.Exists(sourcePath))
                        {
                            Console.WriteLine($"文件不存在,跳过: {sourcePath}");
                            continue;
                        }
                        // èŽ·å–æ–‡ä»¶åï¼ˆåŒ…å«æ‰©å±•åï¼‰
                        string fileName = Path.GetFileName(sourcePath);
                        // æž„建目标文件完整路径
                        string destinationPath = Path.Combine(targetDirectory, fileName);
                        // å¦‚果目标文件已存在,添加时间戳避免覆盖
                        if (File.Exists(destinationPath))
                        {
                            string timeStamp = DateTime.Now.ToString("HHmmss");
                            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
                            string extension = Path.GetExtension(fileName);
                            fileName = $"{fileNameWithoutExtension}_{timeStamp}{extension}";
                            destinationPath = Path.Combine(targetDirectory, fileName);
                        }
                        // å¤åˆ¶æ–‡ä»¶åˆ°ç›®æ ‡ç›®å½•
                        File.Copy(sourcePath, destinationPath, true);
                        successCount++;
                        Console.WriteLine($"成功保存: {sourcePath} -> {destinationPath}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"保存文件失败 {sourcePath}: {ex.Message}");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存过程中发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            return successCount;
        }
        //默认加载上次检测方案
        public bool LoadLastUsedConfiguration(bool bl)
        {
            bool isLoad = true;
            try
            {
                if (!string.IsNullOrEmpty(ResultJudge.AppSettings.LastConfigFilePath_Proj) && File.Exists(ResultJudge.AppSettings.LastConfigFilePath_Proj))
                {
                    bool isLoadModel;
                    //json = File.ReadAllText(ResultJudge.AppSettings.LastConfigFilePath);
                    var (modelName, configPath, configContent, message) = LBProjService.LoadLBProj(ResultJudge.AppSettings.LastConfigFilePath_Proj);
                    config = JsonConvert.DeserializeObject<ResultJudge.JudgmentConfiguration>(configContent);
                    if (bl)
                    {
                        if (detector != IntPtr.Zero)
                        {
                            DisposeDetector_CPU(detector);
                        }
                        Task.Run(() =>
                        {
                            // æ¨¡åž‹æŽ¨ç†å¼•擎选择
                            detector = CreateDetector_CPU();
                            isLoadModel = InitializeDetector_CPU(detector, Detector_Device, $".\\model\\{modelName}");
                            while (true)
                            {
                                if (isLoadModel)
                                {
                                    EnhancedLogViewModel.Instance.AddLog($"模型编译成功");
                                    break;
                                }
                            }
                        });
                        MessageBox.Show($"已自动加载上次使用的工程文件: {ResultJudge.AppSettings.LastConfigFilePath_Proj}",
                "成功", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        ProjectState.Foreground = System.Windows.Media.Brushes.LightGreen;
                        ModelState.Foreground = System.Windows.Media.Brushes.LightGreen;
                        ProjectState.Text = ResultJudge.AppSettings.LastConfigFilePath_Proj;
                        ModelState.Text = modelName;
                    }));
                    EnhancedLogViewModel.Instance.AddLog($"当前工程文件: {ResultJudge.AppSettings.LastConfigFilePath_Proj},模型:{modelName}");
                    isLoad = true;
                }
                else
                {
                    if (!string.IsNullOrEmpty(ResultJudge.AppSettings.LastConfigFilePath) && File.Exists(ResultJudge.AppSettings.LastConfigFilePath))
                    {
                        json = File.ReadAllText(ResultJudge.AppSettings.LastConfigFilePath);
                        config = JsonConvert.DeserializeObject<ResultJudge.JudgmentConfiguration>(json);
                        if (bl)
                        {
                            MessageBox.Show($"已自动加载上次使用的检测方案: {ResultJudge.AppSettings.LastConfigFilePath}",
                    "成功", MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        EnhancedLogViewModel.Instance.AddLog($"当前检测方案: {ResultJudge.AppSettings.LastConfigFilePath}");
                        isLoad = true;
                    }
                    else
                    {
                        MessageBox.Show("没有找到上次使用的检测方案,请手动加载",
                                    "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                        EnhancedLogViewModel.Instance.AddLog($"没有找到上次使用的检测方案,请手动加载", "WARN");
                        isLoad = false;
                    }
                }
            }
            catch (Exception ex)
            {
                isLoad = false;
                MessageBox.Show($"自动加载工程时出错,请手动加载: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            return isLoad;
        }
        #endregion
        #region  Modbus Tcp通讯设置
        //记录最后一次触发时间
        private DateTime _lastTriggerTime = DateTime.MinValue;
        //触发信号监听
        private void ClientListen()
        {
            try
            {
                int num = 0;
                while (modbusTCPClient._client == null || modbusTCPClient._client.Connected == false || modbusTCPClient._master == null)
                {
                    if (_isReconnecting) return; // å¦‚果正在重连,直接返回
                    modbusTCPClient.ModbudTCP_Connect(_lastIpAddress, _lastPort);
                    if (num++ > 3)
                    {
                        this.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            MessageBox.Show("Modbus master æœªåˆå§‹åŒ–。无法连接PLC");
                        }));
                        break;
                    }
                }
                while (modbusTCPClient._client != null && modbusTCPClient._client.Connected) //持续监控
                {
                    //modbusTCPClient.currentValus_ROIModel = modbusTCPClient.InputRegistersRead(3);
                    while (modbusTCPClient._client != null && modbusTCPClient._client.Connected)
                    {
                        modbusTCPClient.currentValus_trigger = modbusTCPClient.InputRegistersRead(3);
                        if (modbusTCPClient.previousValus_trigger[0] == 0 && modbusTCPClient.currentValus_trigger[0] == 1)
                        {
                            // æ£€æŸ¥è·ç¦»ä¸Šæ¬¡è§¦å‘是否超过5秒
                            if ((DateTime.Now - _lastTriggerTime).TotalSeconds >= double.Parse(Selflocking_Time))
                            {
                                _lastTriggerTime = DateTime.Now;
                                modbusTCPClient.istrigger = true;
                                Dispatcher.Invoke(() =>
                                {
                                    DateTime currentDate = DateTime.Now;
                                    string timeFileName = currentDate.ToString("HH:mm:ss");
                                    GetMessage_Modbus($"检测到触发信号:{modbusTCPClient.currentValus_trigger[0]}");
                                    GetMessage_Modbus($"{timeFileName}\n");
                                });
                                Console.WriteLine($"检测到触发信号:{modbusTCPClient.currentValus_trigger[0]}");
                                modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
                                Console.WriteLine($"寄存器置0");
                                ReSetUI();
                                Task.Run(() => GetImage());
                            }
                            else
                            {
                                Console.WriteLine($"忽略触发信号,距离上次触发不足{Selflocking_Time}秒");
                                modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
                            }
                        }
                        modbusTCPClient.previousValus_trigger = modbusTCPClient.currentValus_trigger;
                        modbusTCPClient.istrigger = false;
                        break;
                    }
                    modbusTCPClient.previousValus_ROIModel = modbusTCPClient.currentValus_ROIModel;
                }
            }
            catch (Exception e)
            {
                // å¦‚果正在重连,不显示错误消息
                if (!_isReconnecting)
                {
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        // ä¸å†å¼¹çª—,只在日志中记录
                        GetMessage_Modbus("Modbus连接断开,开始尝试重连...\n");
                    }));
                }
            }
        }
        //ModBus心跳信号
        private void HeartbeatCallback(object state)
        {
            try
            {
                // è¯»å–保持寄存器1的值
                modbusTCPClient.HoldingRegisterRead(1);
                Console.WriteLine("心跳信号收发正常");
                // å¿ƒè·³æ­£å¸¸ï¼Œé‡ç½®é‡è¿žå°è¯•次数
                _reconnectAttempts = 0;
            }
            catch (Exception ex)
            {
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    LinkState.Text = "未连接";
                    LinkState.Foreground = System.Windows.Media.Brushes.Red;
                    GetMessage_Modbus("检测到Modbus连接异常,准备重连...\n");
                }));
                Console.WriteLine($"Heartbeat failed: {ex.Message}");
                // ç«‹å³å¯åŠ¨é‡è¿žæœºåˆ¶
                StartReconnect();
            }
        }
        // ç”¨æˆ·ç‚¹å‡»ç¡®å®šè·Ÿè¸ªæ ‡å¿—位
        private bool _disconnectAlertShown = false;
        // è®¾å¤‡è¿žæŽ¥çŠ¶æ€æ£€æµ‹
        private void DeviceConnectbeatCallback(object state)
        {
            try
            {
                for (int i = 0; i < DeviceListBox.Items.Count; i++)
                {
                    IntPtr deviceHandle = _deviceHandles[i + 1];
                    long rel = IDDevice_IsOpen(deviceHandle);
                    if (rel == 0)
                    {
                        if (!_disconnectAlertShown)
                        {
                            _disconnectAlertShown = true;
                            System.Windows.Application.Current.Dispatcher.Invoke(() =>
                            {
                                MessageBox.Show($"设备{i + 1}连接断开,请重新连接", "错误",
                                    MessageBoxButton.OK, MessageBoxImage.Error);
                                _disconnectAlertShown = false; // ç”¨æˆ·ç‚¹å‡»ç¡®å®šåŽé‡ç½®æ ‡å¿—
                            });
                            _imagePtr[i + 1] = IntPtr.Zero;
                            // å½»åº•释放定时器
                            deviceStatusTimer?.Dispose();
                            deviceStatusTimer = null;
                        }
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"设备未按照映射表连接: {ex.Message}");
            }
        }
        #endregion
        #region Modbus重连机制
        // åˆå§‹åŒ–重连定时器
        private void InitializeReconnectTimer()
        {
            // å¦‚果定时器已存在,先释放
            _reconnectTimer?.Dispose();
            // åˆ›å»ºæ–°çš„重连定时器
            _reconnectTimer = new System.Threading.Timer(ReconnectCallback, null, Timeout.Infinite, RECONNECT_INTERVAL);
        }
        // å¯åŠ¨é‡è¿ž
        private void StartReconnect()
        {
            if (_isReconnecting) return;
            // åœæ­¢å¿ƒè·³å®šæ—¶å™¨
            heartbeatTimer?.Change(Timeout.Infinite, Timeout.Infinite);
            // å¯åŠ¨é‡è¿žå®šæ—¶å™¨
            _reconnectTimer?.Change(0, RECONNECT_INTERVAL);
        }
        // åœæ­¢é‡è¿ž
        private void StopReconnect()
        {
            // åœæ­¢é‡è¿žå®šæ—¶å™¨
            _reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
            // é‡å¯å¿ƒè·³å®šæ—¶å™¨
            heartbeatTimer?.Change(0, heartbeatInterval);
        }
        // é‡è¿žå›žè°ƒ
        private void ReconnectCallback(object state)
        {
            if (_isReconnecting) return;
            _isReconnecting = true;
            try
            {
                // æ£€æŸ¥æ˜¯å¦è¶…过最大重连次数
                if (_reconnectAttempts >= MAX_RECONNECT_ATTEMPTS)
                {
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        GetMessage_Modbus($"重连失败,已达到最大重连次数 ({MAX_RECONNECT_ATTEMPTS})\n");
                        // åªæœ‰è¶…过最大重连次数时才弹窗
                        MessageBox.Show("Modbus重连失败,已达到最大重连次数", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    }));
                    // åœæ­¢é‡è¿žå®šæ—¶å™¨
                    _reconnectTimer?.Change(Timeout.Infinite, Timeout.Infinite);
                    return;
                }
                _reconnectAttempts++;
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    GetMessage_Modbus($"尝试第 {_reconnectAttempts} æ¬¡é‡è¿ž...\n");
                }));
                // å°è¯•重连
                bool reconnectSuccess = modbusTCPClient.Reconnect(_lastIpAddress, _lastPort);
                if (reconnectSuccess)
                {
                    // é‡è¿žæˆåŠŸ
                    _reconnectAttempts = 0;
                    _isReconnecting = false;
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        GetMessage_Modbus("重连成功\n");
                        LinkState.Text = "ModBus已连接";
                        LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
                    }));
                    // åœæ­¢é‡è¿žï¼Œæ¢å¤å¿ƒè·³
                    StopReconnect();
                    // é‡æ–°å¯åŠ¨ç›‘å¬ä»»åŠ¡
                    Task.Run(() => ClientListen());
                }
                else
                {
                    // é‡è¿žå¤±è´¥ï¼Œç»§ç»­å°è¯•,不在UI上弹窗,只在日志中记录
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        GetMessage_Modbus($"第 {_reconnectAttempts} æ¬¡é‡è¿žå¤±è´¥\n");
                    }));
                    _isReconnecting = false;
                }
            }
            catch (Exception ex)
            {
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    GetMessage_Modbus($"重连过程中发生错误: {ex.Message}\n");
                }));
                _isReconnecting = false;
            }
        }
        #endregion
        // é€šè®¯æµ‹è¯•,debug用
        private void Write_Click(object sender, RoutedEventArgs e)
        {
            EnhancedLogViewModel.Instance.AddLog("开始ModBus通讯测试,所有寄存器写入高电平2s后置零", "DEBUG");
            if (modbusTCPClient._client == null)
            {
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    LinkState.Text = "未连接";
                    LinkState.Foreground = System.Windows.Media.Brushes.Red;
                }));
                MessageBox.Show("连接到服务器失败,请检查连接后重试");
                return;
            }
            //ushort[] test = new ushort[] { 0x8001 };
            //modbusTCPClient.MultipleRegistersWrite(3, test);
            //outputs[0] = true;
            //outputs[15] = true;
            //ushort value = BoolsToUshort(outputs);
            // å‡è®¾æœ‰ä¸€ä¸ªåŒ…含16个0和1的数组
            int[] binaryDigits = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
            int[] binaryDigits2 = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
            // å°†äºŒè¿›åˆ¶æ•°ç»„转换为ushort
            ushort value = BinaryToUshort_MSBFirst(binaryDigits);
            ushort value2 = BinaryToUshort_MSBFirst(binaryDigits2);
            // å°†ushort存储在ushort数组中
            ushort[] test = new ushort[] { value };
            ushort[] test2 = new ushort[] { value2 };
            modbusTCPClient.MultipleRegistersWrite(3, test);
            modbusTCPClient.MultipleRegistersWrite(4, test2);
            Thread.Sleep(2000);
            modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
            modbusTCPClient.MultipleRegistersWrite(4, new ushort[] { 0 });
        }
        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            // å®šæ—¶å™¨è§¦å‘时执行的代码
            modbusTCPClient.MultipleRegistersWrite(3, new ushort[] { 0 });
            modbusTCPClient.MultipleRegistersWrite(4, new ushort[] { 0 });
            EnhancedLogViewModel.Instance.AddLog($"Modbus已置零");
            Console.WriteLine("Modbus已置零");
        }
        // æ‰‹åŠ¨é‡‡é›†å›¾åƒ
        private void Read_Click(object sender, RoutedEventArgs e)
        {
            EnhancedLogViewModel.Instance.AddLog("开始手动采集图像", "DEBUG");
            ReSetUI();
            Task.Run(() =>
            {
                GetImage();
            });
        }
        private void ReSetUI()
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                Finall_result0.Content = "";
                finall_result0.Background = System.Windows.Media.Brushes.Gray;
                Finall_result1.Content = "";
                finall_result1.Background = System.Windows.Media.Brushes.Gray;
                Finall_result2.Content = "";
                finall_result2.Background = System.Windows.Media.Brushes.Gray;
                Finall_result3.Content = "";
                finall_result3.Background = System.Windows.Media.Brushes.Gray;
                Finall_result4.Content = "";
                finall_result4.Background = System.Windows.Media.Brushes.Gray;
                Finall_result5.Content = "";
                finall_result5.Background = System.Windows.Media.Brushes.Gray;
                Finall_result6.Content = "";
                finall_result6.Background = System.Windows.Media.Brushes.Gray;
                Finall_result7.Content = "";
                finall_result7.Background = System.Windows.Media.Brushes.Gray;
                Finall_result8.Content = "";
                finall_result8.Background = System.Windows.Media.Brushes.Gray;
                Finall_result9.Content = "";
                finall_result9.Background = System.Windows.Media.Brushes.Gray;
                Finall_result10.Content = "";
                finall_result10.Background = System.Windows.Media.Brushes.Gray;
                Finall_result11.Content = "";
                finall_result11.Background = System.Windows.Media.Brushes.Gray;
                Finall_result12.Content = "";
                finall_result12.Background = System.Windows.Media.Brushes.Gray;
                Finall_result13.Content = "";
                finall_result13.Background = System.Windows.Media.Brushes.Gray;
                Finall_result14.Content = "";
                finall_result14.Background = System.Windows.Media.Brushes.Gray;
                Finall_result15.Content = "";
                finall_result15.Background = System.Windows.Media.Brushes.Gray;
                Finall_result16.Content = "";
                finall_result16.Background = System.Windows.Media.Brushes.Gray;
                Finall_result17.Content = "";
                finall_result17.Background = System.Windows.Media.Brushes.Gray;
                Finall_result18.Content = "";
                finall_result18.Background = System.Windows.Media.Brushes.Gray;
                Finall_result19.Content = "";
                finall_result19.Background = System.Windows.Media.Brushes.Gray;
                Finall_result20.Content = "";
                finall_result20.Background = System.Windows.Media.Brushes.Gray;
                Finall_result21.Content = "";
                finall_result21.Background = System.Windows.Media.Brushes.Gray;
                Finall_result22.Content = "";
                finall_result22.Background = System.Windows.Media.Brushes.Gray;
                Finall_result23.Content = "";
                finall_result23.Background = System.Windows.Media.Brushes.Gray;
            }));
        }
        private void ReSet_Click(object sender, RoutedEventArgs e)
        {
            ReSetUI();
        }
        //设备管理
        SmartScanner.ProductManager productManager = null;
        private void ProductMaanager_Btn_Click(object sender, RoutedEventArgs e)
        {
            var loginWindow = new LoginWindow();
            if (loginWindow.ShowDialog() == true)
            {
                if (productManager == null || !productManager.IsLoaded)
                {
                    productManager = new ProductManager();
                    productManager.Closed += (s, args) => { productManager = null; };
                    productManager.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
                    productManager.ShowDialog();
                }
                else
                {
                    if (productManager.WindowState == WindowState.Minimized)
                    {
                        productManager.WindowState = WindowState.Normal; // æ¢å¤çª—口状态
                    }
                    productManager.Activate(); // å¦‚果窗口已存在,则激活它
                }
            }
        }
        //检测方案
        SmartScanner.ResultJudge resultJudge = null;
        private void ResultJudge_Btn_Click(object sender, RoutedEventArgs e)
        {
            var loginWindow = new LoginWindow();
            if (loginWindow.ShowDialog() == true)
            {
                if (resultJudge == null || !resultJudge.IsLoaded)
                {
                    resultJudge = new ResultJudge();
                    resultJudge.Closed += (s, args) => { resultJudge = null; };
                    resultJudge.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
                    resultJudge.ShowDialog();
                }
                else
                {
                    if (resultJudge.WindowState == WindowState.Minimized)
                    {
                        resultJudge.WindowState = WindowState.Normal; // æ¢å¤çª—口状态
                    }
                    resultJudge.Activate(); // å¦‚果窗口已存在,则激活它
                }
            }
        }
        #region è¾“出模式选择
        private void OutputCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            IsSignleOutput = true;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "结果输出模式",
                $"修改为: å•点输出",
                null);
        }
        private void OutputCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            IsSignleOutput = false;
            // è®°å½•日志
            OperateLogService.LogOperation(
                "结果输出模式",
                $"修改为: å¤šç‚¹è¾“出",
                null);
        }
        #endregion
        // å›¾åƒä¿å­˜è®¾ç½®
        SmartScanner.DownloadData downloadData = null;
        private void ImageSetup_Btn_Click(object sender, RoutedEventArgs e)
        {
            var loginWindow = new LoginWindow();
            if (loginWindow.ShowDialog() == true)
            {
                if (downloadData == null || !downloadData.IsLoaded)
                {
                    downloadData = new DownloadData();
                    downloadData.Closed += (s, args) => { downloadData = null; };
                    downloadData.SetControlsEnabled(UserManager.HasAdministratorPrivilege());
                    downloadData.ShowDialog();
                }
                else
                {
                    if (downloadData.WindowState == WindowState.Minimized)
                    {
                        downloadData.WindowState = WindowState.Normal; // æ¢å¤çª—口状态
                    }
                    downloadData.Activate(); // å¦‚果窗口已存在,则激活它
                }
            }
        }
        private void AddTestLog_Click(object sender, RoutedEventArgs e)
        {
            EnhancedLogViewModel.Instance.AddLog("这是一条普通信息");
            EnhancedLogViewModel.Instance.AddLog("这是一条警告信息", "WARN");
            EnhancedLogViewModel.Instance.AddLog("这是一条错误信息", "ERROR");
            EnhancedLogViewModel.Instance.AddLog("这是一条调试信息", "DEBUG");
        }
        private void TCPClient_Connect_Click(object sender, RoutedEventArgs e)
        {
        }
        private void TCPClient_ClearClientLogs_Click(object sender, RoutedEventArgs e)
        {
        }
        private void btnViewLogs_Click(object sender, RoutedEventArgs e)
        {
            var operateLogView = new OperateLogView();
            operateLogView.ShowDialog();
        }
        private void btnViewReports_Click(object sender, RoutedEventArgs e)
        {
            ExcelResultRecorder.OpenReportFolder();
        }
        private async void RestartButton_Click(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("确定要重启应用程序吗?", "确认重启",
            MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                Mouse.OverrideCursor = Cursors.Wait;
                try
                {
                    await AppRestartHelper.RestartAsync();
                }
                finally
                {
                    Mouse.OverrideCursor = null;
                }
            }
        }
        #region ç•Œé¢å›¾ç‰‡æ˜¾ç¤ºæŒ‰é’®
        private ImageDisplayWindow displayWindow;
        private void finall_result0_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_1.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_2.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_3.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result3_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_4.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result4_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_5.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result5_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_6.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result6_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_7.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result7_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_8.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result8_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_9.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result9_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_10.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result10_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_11.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result11_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_12.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result12_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_13.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result13_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_14.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result14_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_15.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result15_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_16.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result16_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_17.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result17_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_18.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result18_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_19.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result19_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_20.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result20_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_21.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result21_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_22.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result22_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_23.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        private void finall_result23_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            displayWindow = new ImageDisplayWindow();
            bool isShow = displayWindow.ShowImage_main(".\\vino_res\\result_24.jpg");
            if (isShow)
            {
                displayWindow.Show();
            }
            else
            {
                return;
            }
        }
        #endregion
        #region TCP/IP通讯模块
        private void TCPServer_Start_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var ip = GetSelectedIP();
                var port = GetSelectedPort();
                var enableHeartbeat = TCPServer_EnableHeartbeat.IsChecked ?? false;
                var heartbeatCommand = TCPServer_HeartbeatCommand.Text.Trim();
                var heartbeatInterval = int.Parse(TCPServer_HeartbeatInterval.Text);
                var outputIOCount = DeviceListBox.Items.Count;
                // éªŒè¯å¿ƒè·³è®¾ç½®
                if (enableHeartbeat)
                {
                    if (string.IsNullOrWhiteSpace(heartbeatCommand))
                    {
                        MessageBox.Show("请输入有效的心跳指令");
                        return;
                    }
                    if (heartbeatInterval <= 0)
                    {
                        MessageBox.Show("心跳间隔必须大于0");
                        return;
                    }
                }
                _tcpServerManager = new TcpServerManager(
                    enableHeartbeat,
                    heartbeatCommand,
                    heartbeatInterval,
                    GetImageAndProcess,
                    outputIOCount);
                _tcpServerManager.LogMessage += msg => Dispatcher.Invoke(() =>
                {
                    TCPServer_LogsTextBox.AppendText($"{DateTime.Now:HH:mm:ss:fff} {msg}\n");
                    TCPServer_LogsTextBox.ScrollToEnd();
                });
                _ = _tcpServerManager.StartAsync(ip, port);
                TCPServer_Start.IsEnabled = false;
                TCPServer_Stop.IsEnabled = true;
                LinkState.Text = "TCP已启动";
                LinkState.Foreground = System.Windows.Media.Brushes.LightGreen;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"启动服务器失败: {ex.Message}");
            }
        }
        private async Task<int[]> GetImageAndProcess()
        {
            try
            {
                usOutput_tcp = new int[DeviceListBox.Items.Count];
                return await Task.Run(() =>
                {
                    GetImage();
                    return usOutput_tcp; // è¿”回结果
                }).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"图像处理异常: {ex.Message}");
                throw; // é‡æ–°æŠ›å‡ºä»¥è§¦å‘TCP层的错误处理
            }
        }
        private void TCPServer_Stop_Click(object sender, RoutedEventArgs e)
        {
            _tcpServerManager?.Stop();
            TCPServer_Start.IsEnabled = true;
            TCPServer_Stop.IsEnabled = false;
            LinkState.Text = "未连接";
            LinkState.Foreground = System.Windows.Media.Brushes.Red;
        }
        private void TCPServer_EnableHeartbeat_Checked(object sender, RoutedEventArgs e)
        {
            TCPServer_HeartbeatPanel.Visibility = Visibility.Visible;
        }
        private void TCPServer_EnableHeartbeat_Unchecked(object sender, RoutedEventArgs e)
        {
            TCPServer_HeartbeatPanel.Visibility = Visibility.Collapsed;
        }
        private void TCPServer_ClearLogs_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.Invoke(() =>
            TCPServer_LogsTextBox.Clear());
        }
        private void RefreshIpButton_Click(object sender, RoutedEventArgs e)
        {
            TCPServer_IpComboBox.Items.Clear();
            // æ·»åŠ é»˜è®¤é€‰é¡¹
            TCPServer_IpComboBox.Items.Add(new ComboBoxItem
            {
                Content = "0.0.0.0 (All Interfaces)"
            });
            TCPServer_IpComboBox.Items.Add(new ComboBoxItem
            {
                Content = "127.0.0.1 (Loopback)"
            });
            // æ·»åŠ å®žé™…IP地址
            foreach (var ip in GetAvailableIPs())
            {
                var item = new ComboBoxItem
                {
                    Content = $"{ip} ({GetNetworkInterfaceName(ip)})",
                    Tag = ip // å­˜å‚¨å®žé™…IP对象
                };
                TCPServer_IpComboBox.Items.Add(item);
            }
            TCPServer_IpComboBox.SelectedIndex = 0;
        }
        private string GetNetworkInterfaceName(IPAddress ip)
        {
            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
            {
                foreach (UnicastIPAddressInformation addr in nic.GetIPProperties().UnicastAddresses)
                {
                    if (addr.Address.Equals(ip))
                    {
                        return nic.Name;
                    }
                }
            }
            return "Unknown";
        }
        private List<IPAddress> GetAvailableIPs()
        {
            var ips = new List<IPAddress>();
            // èŽ·å–æ‰€æœ‰æ´»åŠ¨çš„ç½‘ç»œæŽ¥å£
            foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
            {
                // åªèŽ·å–å·²å¯ç”¨ä¸”éžè™šæ‹Ÿçš„æŽ¥å£
                if (nic.OperationalStatus != OperationalStatus.Up ||
                    nic.NetworkInterfaceType == NetworkInterfaceType.Loopback)
                    continue;
                // èŽ·å–IPv4地址
                foreach (UnicastIPAddressInformation ip in nic.GetIPProperties().UnicastAddresses)
                {
                    if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        ips.Add(ip.Address);
                    }
                }
            }
            return ips;
        }
        /// <summary>
        /// èŽ·å–å½“å‰é€‰æ‹©çš„IP地址字符串
        /// </summary>
        /// <returns>
        /// "0.0.0.0" - æ‰€æœ‰æŽ¥å£
        /// "127.0.0.1" - çŽ¯å›žåœ°å€
        /// "192.168.1.100" - å…·ä½“IP
        /// </returns>
        public string GetSelectedIP()
        {
            // æƒ…况1:用户手动输入(IsEditable=true时)
            if (!string.IsNullOrWhiteSpace(TCPServer_IpComboBox.Text))
            {
                if (IsValidIP(TCPServer_IpComboBox.Text))
                    return TCPServer_IpComboBox.Text.Trim();
            }
            // æƒ…况2:从下拉项选择
            if (TCPServer_IpComboBox.SelectedItem is ComboBoxItem item)
            {
                // å¤„理特殊选项
                if (item.Content.ToString().Contains("0.0.0.0"))
                    return "0.0.0.0";
                if (item.Content.ToString().Contains("127.0.0.1"))
                    return "127.0.0.1";
                // ä»Žå†…容中提取IP部分(格式:"IP (描述)")
                var ipPart = item.Content.ToString().Split().FirstOrDefault();
                if (IsValidIP(ipPart))
                    return ipPart;
            }
            // é»˜è®¤è¿”回"0.0.0.0"
            return "0.0.0.0";
        }
        // IP地址验证方法
        private bool IsValidIP(string ipString)
        {
            return IPAddress.TryParse(ipString, out _);
        }
        /// <summary>
        /// å®‰å…¨èŽ·å–é€‰æ‹©çš„ç«¯å£å·
        /// </summary>
        /// <returns>
        /// æˆåŠŸè¿”å›žæœ‰æ•ˆç«¯å£(1-65535),失败返回-1并显示错误提示
        /// </returns>
        public int GetSelectedPort()
        {
            try
            {
                // æƒ…况1:从下拉项选择
                if (TCPServer_PortComboBox.SelectedItem is ComboBoxItem selectedItem)
                {
                    if (int.TryParse(selectedItem.Content.ToString(), out int port) && IsValidPort(port))
                        return port;
                }
                // æƒ…况2:手动输入文本
                if (!string.IsNullOrWhiteSpace(TCPServer_PortComboBox.Text))
                {
                    if (int.TryParse(TCPServer_PortComboBox.Text, out int manualPort) && IsValidPort(manualPort))
                        return manualPort;
                }
                throw new ArgumentException("未选择有效端口");
            }
            catch (Exception ex)
            {
                ShowPortError($"端口获取失败: {ex.Message}");
                return -1;
            }
        }
        // ç«¯å£èŒƒå›´éªŒè¯
        private bool IsValidPort(int port) => port > 0 && port <= 65535;
        // é”™è¯¯æç¤ºæ–¹æ³•
        private void ShowPortError(string message)
        {
            MessageBox.Show(message, "端口配置错误",
                          MessageBoxButton.OK,
                          MessageBoxImage.Error);
        }
        #endregion
        #region å·¥ç¨‹æ–¹æ¡ˆè®¾ç½®æ¨¡å—按钮事件
        private void BtnSelectParam_Click(object sender, RoutedEventArgs e)
        {
            RefreshDetectionPlanList();
            if (cmbDetectionPlans.SelectedItem == null)
            {
                MessageBox.Show("请先选择检测方案", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            string selectedPlan = ((dynamic)cmbDetectionPlans.SelectedItem).FileName;
            MessageBox.Show($"已选择检测方案: {selectedPlan}", "检测方案确认",
                           MessageBoxButton.OK, MessageBoxImage.Information);
        }
        /// <summary>
        /// åŠ è½½æ£€æµ‹æ–¹æ¡ˆåˆ—è¡¨
        /// </summary>
        private void RefreshDetectionPlanList()
        {
            var plans = GetAvailableDetectionPlans()
                .Select(name => new
                {
                    FileName = name,
                    FullPath = Path.Combine("DetectionPlan", name)
                }).ToList();
            cmbDetectionPlans.ItemsSource = plans;
            if (plans.Any()) cmbDetectionPlans.SelectedIndex = 0;
        }
        /// <summary>
        /// èŽ·å–æ‰€æœ‰å¯ç”¨æ£€æµ‹æ–¹æ¡ˆ
        /// </summary>
        private string[] GetAvailableDetectionPlans()
        {
            string planPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DetectionPlan");
            if (!Directory.Exists(planPath))
            {
                Directory.CreateDirectory(planPath);
                return Array.Empty<string>();
            }
            return Directory.GetFiles(planPath, "*.json")
                           .Select(Path.GetFileName)
                           .ToArray();
        }
        private void BtnConfirmModel_Click(object sender, RoutedEventArgs e)
        {
            if (cmbModels.SelectedItem == null)
            {
                MessageBox.Show("请先选择模型文件", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            string selectedModel = ((dynamic)cmbModels.SelectedItem).FileName;
            MessageBox.Show($"已选择模型: {selectedModel}", "模型确认",
                           MessageBoxButton.OK, MessageBoxImage.Information);
        }
        /// <summary>
        /// åŠ è½½æ¨¡åž‹åˆ—è¡¨
        /// </summary>
        private void RefreshModelList()
        {
            var models = LBProjService.GetAvailableModels()
                .Select(name => new
                {
                    FileName = name,
                    FullPath = Path.Combine("model", name)
                }).ToList();
            cmbModels.ItemsSource = models;
            if (models.Any()) cmbModels.SelectedIndex = 0;
        }
        private void BtnExport_Click(object sender, RoutedEventArgs e)
        {
            if (cmbModels.SelectedItem == null)
            {
                MessageBox.Show("请先点击【确定】按钮选择模型", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            // å›ºå®šå¯¼å‡ºè·¯å¾„
            string projectDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Project");
            if (!Directory.Exists(projectDir))
            {
                Directory.CreateDirectory(projectDir);
            }
            var saveDialog = new System.Windows.Forms.SaveFileDialog
            {
                Title = "导出 LBProj å·¥ç¨‹",
                Filter = "LBProj文件|*.lbproj",
                FileName = $"project_{DateTime.Now:yyyyMMdd_HHmmss}",
                InitialDirectory = projectDir
            };
            if (saveDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string modelName = ((dynamic)cmbModels.SelectedItem).FileName;
                // ä½¿ç”¨å›ºå®šè·¯å¾„的检测方案文件
                string detectionPlanPath = cmbDetectionPlans.SelectedItem != null ?
                    Path.Combine("DetectionPlan", ((dynamic)cmbDetectionPlans.SelectedItem).FileName) :
                    "";
                var (success, message) = LBProjService.CreateLBProj(
                    detectionPlanPath,
                    modelName,
                    saveDialog.FileName);
                if (success)
                {
                    Properties.Settings.Default.LastConfigFilePath_Proj = saveDialog.FileName;
                    Properties.Settings.Default.Save();
                    MessageBox.Show($"工程已成功保存到: {saveDialog.FileName}", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
                    OperateLogService.LogOperation("工程文件修改", $"工程文件修改为: {saveDialog.FileName}", null);
                    //txtExportPath.Text = saveDialog.FileName;
                }
                else
                {
                    MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }
        private void BtnLoad_Click(object sender, RoutedEventArgs e)
        {
            //RefreshProjectList();
            if (cmbProjects.SelectedItem == null)
            {
                MessageBox.Show("请先选择工程文件", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            string selectedProject = ((dynamic)cmbProjects.SelectedItem).FullPath;
            var (modelName, configPath, configContent, message) = LBProjService.LoadLBProj(selectedProject);
            config = JsonConvert.DeserializeObject<ResultJudge.JudgmentConfiguration>(configContent);
            if (modelName != null)
            {
                // æ›´æ–°æ¨¡åž‹é€‰æ‹©
                foreach (var item in cmbModels.Items)
                {
                    if (((dynamic)item).FileName == modelName)
                    {
                        cmbModels.SelectedItem = item;
                        break;
                    }
                }
                if (detector != IntPtr.Zero)
                {
                    DisposeDetector_CPU(detector);
                }
                Task.Run(() =>
                {
                    // æ¨¡åž‹æŽ¨ç†å¼•擎选择
                    detector = CreateDetector_CPU();
                    bool isLoadModel = InitializeDetector_CPU(detector, Detector_Device, $".\\model\\{modelName}");
                    while (true)
                    {
                        if (isLoadModel)
                        {
                            EnhancedLogViewModel.Instance.AddLog($"模型编译成功");
                            break;
                        }
                    }
                });
                Properties.Settings.Default.LastConfigFilePath_Proj = selectedProject;
                Properties.Settings.Default.Save();
                //txtParamPath.Text = configPath;
                //cmbModels.ItemsSource = modelName.ToString();
                MessageBox.Show($"已加载模型: {modelName}\n{message}", "成功",
                    MessageBoxButton.OK, MessageBoxImage.Information);
                this.Dispatcher.BeginInvoke(new Action(() =>
                {
                    ProjectState.Foreground = System.Windows.Media.Brushes.LightGreen;
                    ModelState.Foreground = System.Windows.Media.Brushes.LightGreen;
                    ProjectState.Text = selectedProject;
                    ModelState.Text = modelName;
                }));
                EnhancedLogViewModel.Instance.AddLog($"已加载工程文件: {selectedProject},模型:{modelName}");
            }
            else
            {
                MessageBox.Show(message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        /// <summary>
        /// åŠ è½½å·¥ç¨‹æ–‡ä»¶åˆ—è¡¨
        /// </summary>
        private void RefreshProjectList()
        {
            var projects = GetAvailableProjects()
                .Select(name => new
                {
                    FileName = name,
                    FullPath = Path.Combine("Project", name)
                }).ToList();
            cmbProjects.ItemsSource = projects;
            if (projects.Any()) cmbProjects.SelectedIndex = 0;
        }
        /// <summary>
        /// èŽ·å–æ‰€æœ‰å¯ç”¨å·¥ç¨‹æ–‡ä»¶
        /// </summary>
        private string[] GetAvailableProjects()
        {
            string projectPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Project");
            if (!Directory.Exists(projectPath))
            {
                Directory.CreateDirectory(projectPath);
                return Array.Empty<string>();
            }
            return Directory.GetFiles(projectPath, "*.lbproj")
                           .Select(Path.GetFileName)
                           .ToArray();
        }
        private void BtnRefreshModels_Click(object sender, RoutedEventArgs e)
        {
            RefreshModelList();
            RefreshDetectionPlanList();
            RefreshProjectList();
            MessageBox.Show("模型、检测方案和工程文件列表已刷新", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
        }
        #endregion
        #region ç‰ˆæœ¬è¯´æ˜ŽåŠŸèƒ½
        private void VersionButton_Click(object sender, RoutedEventArgs e)
        {
            ShowVersionInfo();
        }
        private void ShowVersionInfo()
        {
            try
            {
                // è¯»å–版本说明文件
                string versionFile = "版本说明.txt";
                if (File.Exists(versionFile))
                {
                    string versionContent = File.ReadAllText(versionFile);
                    // è§£æžç‰ˆæœ¬è¯´æ˜Žæ–‡ä»¶ï¼Œæå–最新版本信息
                    var versionLines = versionContent.Split('\n');
                    string latestVersion = "";
                    string latestDate = "";
                    string latestChanges = "";
                    // ä»Žæœ€åŽä¸€è¡Œå‘前查找最新的版本信息
                    for (int i = versionLines.Length - 1; i >= 0; i--)
                    {
                        if (versionLines[i].Contains("v") && versionLines[i].Contains("."))
                        {
                            // æå–版本日期和版本号
                            var parts = versionLines[i].Trim().Split(' ');
                            foreach (var part in parts)
                            {
                                if (part.Contains(".") && part.Length > 0)
                                {
                                    if (part.StartsWith("v") || part.Contains("v"))
                                    {
                                        latestVersion = part.Trim();
                                    }
                                    else if (char.IsDigit(part[0]))
                                    {
                                        latestDate = part.Trim();
                                    }
                                }
                            }
                            // æŸ¥æ‰¾è¯¥ç‰ˆæœ¬çš„æ›´æ–°å†…容
                            for (int j = i + 1; j < versionLines.Length; j++)
                            {
                                string contentLine = versionLines[j].Trim();
                                // åœæ­¢æ¡ä»¶ï¼šç©ºè¡Œæˆ–新的版本行
                                if (string.IsNullOrEmpty(contentLine) ||
                                    (contentLine.Contains("v") && contentLine.Contains(".") && contentLine.Length > 8))
                                {
                                    break;
                                }
                                // æ·»åŠ æ‰€æœ‰éžç©ºå†…å®¹è¡Œ
                                if (contentLine.Length > 0)
                                {
                                    latestChanges += contentLine + "\n";
                                }
                                // æœ€å¤šè¯»å–8行内容
                                if (j - i > 8)
                                {
                                    break;
                                }
                            }
                            // æ˜¾ç¤ºç‰ˆæœ¬ä¿¡æ¯å¯¹è¯æ¡†
                            string message = $"当前软件版本: {latestVersion}\n" +
                                           $"发布日期: {latestDate}\n\n" +
                                           $"最新更新内容:\n{latestChanges}\n" +
                                           $"完整版本历史记录请查看版本说明.txt文件";
                            MessageBox.Show(message, "软件版本说明", MessageBoxButton.OK, MessageBoxImage.Information);
                            return;
                        }
                    }
                    // å¦‚果没有找到版本信息,显示默认提示
                    MessageBox.Show("版本说明文件中未找到有效的版本信息", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                {
                    MessageBox.Show("版本说明文件不存在", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取版本信息时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        #endregion
    }
}
IDViewer_2D/ModbusTCPClient.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using NModbus;
using NModbus.Device;
using NModbus.Extensions.Enron;
using OpenCvSharp;
namespace SmartScanner
{
    class ModbusTCPClient
    {
        public TcpClient _client;
        public IModbusMaster _master;
        public ModbusFactory factory = new ModbusFactory();
        public int isconnnum = 1;
        public ushort[] previousValus_trigger = { 0, 0 };   //寄存器当前值
        public ushort[] currentValus_trigger = { 0, 0 };    //寄存器前一个值
        public ushort[] previousValus_ROIModel = { 0, 0 };
        public ushort[] currentValus_ROIModel = { 0, 0 };
        public bool istrigger = false;
        // é‡è¿žç›¸å…³å­—段
        public const int MaxReconnectAttempts = 5; // æœ€å¤§é‡è¿žæ¬¡æ•°
        public const int ReconnectInterval = 5000; // é‡è¿žé—´é𔿗¶é—´(毫秒)
        private int _reconnectAttempts = 0; // å½“前重连尝试次数
        private bool _isReconnecting = false; // æ˜¯å¦æ­£åœ¨é‡è¿ž
        public void ModbudTCP_Connect(string ipAddress, int port)
        {
            try
            {
                _client = new TcpClient(ipAddress, port);
                if (_client.Connected)
                {
                    // åˆ›å»º TCP å®¢æˆ·ç«¯
                    //MessageBox.Show("连接到服务器成功");
                    // åˆ›å»º Modbus å·¥åŽ‚å’Œä¸»æœº
                    _master = (ModbusMaster)factory.CreateMaster(_client);
                    if (_master == null)
                    {
                        MessageBox.Show("无法创建 Modbus master å®žä¾‹ã€‚");
                        return;
                    }
                    // è¿žæŽ¥æˆåŠŸï¼Œé‡ç½®é‡è¿žè®¡æ•°
                    _reconnectAttempts = 0;
                }
                else
                {
                    if (isconnnum++ < 5)
                    {
                        ModbudTCP_Connect(ipAddress, port);
                        Thread.Sleep(1000);
                    }
                    else
                    {
                        MessageBox.Show("连接到服务器超时");
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"连接到服务器失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                Console.WriteLine("连接到服务器失败");
                return;
            }
        }
        // é‡è¿žæ–¹æ³•
        public bool Reconnect(string ipAddress, int port)
        {
            // é¿å…é‡å¤é‡è¿ž
            if (_isReconnecting) return false;
            _isReconnecting = true;
            try
            {
                // é‡Šæ”¾åŽŸæœ‰è¿žæŽ¥
                _master?.Dispose();
                _client?.Close();
                _client = null;
                // æ£€æŸ¥æ˜¯å¦è¶…过最大重连次数
                if (_reconnectAttempts >= MaxReconnectAttempts)
                {
                    Console.WriteLine("Modbus重连失败,已达到最大重连次数");
                    return false;
                }
                _reconnectAttempts++;
                Console.WriteLine($"尝试第{_reconnectAttempts}次重连...");
                // å°è¯•重新连接
                _client = new TcpClient();
                var connectTask = _client.ConnectAsync(ipAddress, port);
                // ç­‰å¾…连接完成,最多等待5秒
                if (connectTask.Wait(5000))
                {
                    if (_client.Connected)
                    {
                        _master = (ModbusMaster)factory.CreateMaster(_client);
                        if (_master != null)
                        {
                            // é‡è¿žæˆåŠŸï¼Œé‡ç½®è®¡æ•°
                            _reconnectAttempts = 0;
                            Console.WriteLine("Modbus重连成功");
                            return true;
                        }
                    }
                }
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"重连失败: {ex.Message}");
                return false;
            }
            finally
            {
                _isReconnecting = false;
            }
        }
        public ushort[] HoldingRegisterRead(ushort starAddress) //读保持寄存器
        {
            try
            {
                ushort[] registerValues = _master.ReadHoldingRegisters(1, starAddress, 1);
                return registerValues;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取保持寄存器失败: {ex.Message}");
                throw;
            }
        }
        public void HoldingRegisterWrite(ushort registerAddress, ushort WriteValue) //写保存寄存器
        {
            try
            {
                _master.WriteSingleRegister(1, registerAddress, WriteValue);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入保持寄存器失败: {ex.Message}");
                throw;
            }
        }
        public void SingleCoilWrite(ushort CoilAddress, bool valueToWrite) //写单线圈
        {
            try
            {
                _master.WriteSingleCoil(1, CoilAddress, valueToWrite);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入单线圈失败: {ex.Message}");
                throw;
            }
        }
        public void MultipleRegistersWrite(ushort starAddress, ushort[] valueToWrite)
        {
            try
            {
                _master.WriteMultipleRegisters(1, starAddress, valueToWrite);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入多个寄存器失败: {ex.Message}");
                throw;
            }
        }
        public ushort[] InputRegistersRead(ushort starAddress)
        {
            try
            {
                ushort[] registerValues = _master.ReadInputRegisters(1, starAddress, 1);
                return registerValues;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"读取输入寄存器失败: {ex.Message}");
                throw;
            }
        }
    }
}
IDViewer_2D/OperateLog/OperateLogService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmartScanner.OperateLog
{
    public static class OperateLogService
    {
        private static readonly string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
        private static readonly string logFileName = $"OperationLog_{DateTime.Now:yyyyMMdd}.txt";
        static OperateLogService()
        {
            // ç¡®ä¿æ—¥å¿—目录存在
            if (!Directory.Exists(logDirectory))
            {
                Directory.CreateDirectory(logDirectory);
            }
        }
        public static void LogOperation(string operationType, string operationDetails, string targetDevice = null)
        {
            if (UserManager.CurrentUser == null) return;
            try
            {
                var logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} | " +
                              $"操作人员: {UserManager.CurrentUser.Username} | " +
                              $"操作类型: {operationType} | " +
                              $"目标设备: {targetDevice ?? "N/A"} | " +
                              $"操作详情: {operationDetails}";
                var logPath = Path.Combine(logDirectory, logFileName);
                File.AppendAllText(logPath, logEntry + Environment.NewLine);
            }
            catch (Exception ex)
            {
                // ç®€å•处理日志写入错误
                Console.WriteLine($"日志记录失败: {ex.Message}");
            }
        }
        public static string[] GetRecentLogs(int days = 7)
        {
            try
            {
                var logFiles = Directory.GetFiles(logDirectory, "OperationLog_*.txt")
                                      .OrderByDescending(f => f)
                                      .Take(days)
                                      .ToList();
                var allLogs = new List<string>();
                foreach (var file in logFiles)
                {
                    allLogs.AddRange(File.ReadAllLines(file));
                }
                return allLogs.ToArray();
            }
            catch
            {
                return new string[0];
            }
        }
    }
}
IDViewer_2D/OperateLog/OperateLogView.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
<Window x:Class="SmartScanner.OperateLog.OperateLogView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmartScanner.OperateLog"
        mc:Ignorable="d"
        Title="操作日志" Height="450" Width="800">
    <DockPanel>
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="5">
            <Button Content="刷新" Width="80" Margin="5" Click="BtnRefresh_Click"/>
            <Button Content="打开日志文件夹" Width="120" Margin="5" Click="BtnOpenFolder_Click"/>
        </StackPanel>
        <TextBox x:Name="txtLogs" DockPanel.Dock="Bottom" Margin="5"
                 IsReadOnly="True" VerticalScrollBarVisibility="Auto"
                 TextWrapping="Wrap" FontSize="12"/>
    </DockPanel>
</Window>
IDViewer_2D/OperateLog/OperateLogView.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SmartScanner.OperateLog
{
    /// <summary>
    /// OperateLogView.xaml çš„交互逻辑
    /// </summary>
    public partial class OperateLogView : Window
    {
        public OperateLogView()
        {
            InitializeComponent();
            RefreshLogs();
        }
        private void RefreshLogs()
        {
            var logs = OperateLogService.GetRecentLogs();
            txtLogs.Text = string.Join(Environment.NewLine, logs);
        }
        private void BtnRefresh_Click(object sender, RoutedEventArgs e)
        {
            RefreshLogs();
        }
        private void BtnOpenFolder_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var logDirectory = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
                if (Directory.Exists(logDirectory))
                {
                    Process.Start("explorer.exe", logDirectory);
                }
                else
                {
                    MessageBox.Show("日志目录不存在", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开日志文件夹失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }
}
IDViewer_2D/ProductManager.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<Window x:Class="SmartScanner.ProductManager"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmartScanner"
        mc:Ignorable="d"
        Title="设备管理" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <!-- è¾“入控制区 -->
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <TextBlock Text="连接顺序:" VerticalAlignment="Center"/>
            <ComboBox x:Name="cmbOrder" Width="80" Margin="5,0"
                     DisplayMemberPath="." SelectedValuePath="."/>
            <TextBlock Text="相机IP:" VerticalAlignment="Center" Margin="10,0,0,0"/>
            <ComboBox x:Name="cmbIP" Width="150" Margin="5,0"
                     ItemsSource="{Binding AvailableIPs}"/>
            <!--<TextBlock Text="模型选择:" VerticalAlignment="Center" Margin="10,0,0,0"/>
            <ComboBox x:Name="cmbModel" Width="150" Margin="5,0"
                     ItemsSource="{Binding AvailableIPs}"/>-->
            <Button x:Name="DeviceRefresh_PM" Content="刷新设备" Width="80" Margin="10,0" Click="BtnRefreshDevices_Click"/>
            <Button x:Name="AddMapping_PM" Content="添加映射" Width="80" Margin="5,0" Click="BtnAddMapping_Click"/>
            <Button x:Name="SaveConfig_PM" Content="保存" Width="80" Margin="5,0" Click="BtnSave_Click"/>
            <Button x:Name="LoadConfig_PM" Content="加载映射" Width="80" Margin="5,0" Click="BtnLoad_Click"/>
        </StackPanel>
        <!-- æ˜ å°„表显示 -->
        <DataGrid Grid.Row="1" x:Name="dgMapping" AutoGenerateColumns="False"
                 CanUserAddRows="False" CanUserDeleteRows="True">
            <DataGrid.Columns>
                <DataGridTextColumn Header="连接顺序" Binding="{Binding Key}" Width="*"/>
                <DataGridTextColumn Header="相机IP" Binding="{Binding Value}" Width="2*"/>
                <!--<DataGridTextColumn Header="推理模型" Binding="{Binding DetectorSelect}" Width="*"/>-->
                <DataGridTemplateColumn Header="操作" Width="100">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="移除" Click="DeleteMapping_Click"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <!-- çŠ¶æ€æ  -->
        <StatusBar Grid.Row="2">
            <StatusBarItem>
                <TextBlock x:Name="tbStatus" Text="就绪"/>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>
IDViewer_2D/ProductManager.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using SmartScanner.OperateLog;
using Newtonsoft.Json;
using static SmartScanner.IDViewerDefines;
using static SmartScanner.IDViewerSDK;
namespace SmartScanner
{
    /// <summary>
    /// ProductManager.xaml çš„交互逻辑
    /// </summary>
    public partial class ProductManager : Window
    {
        private readonly ObservableCollection<KeyValuePair<int, string>> _ipMapping = new ObservableCollection<KeyValuePair<int, string>>();
        private ObservableCollection<string> _availableIPs = new ObservableCollection<string>();
        private const string ConfigFile = "connection_order.json";
        IDDeviceInfo[] deviceInfo = new IDDeviceInfo[100];
        public ProductManager()
        {
            InitializeComponent();
            long result = IDVIEWER_Init_();
            dgMapping.ItemsSource = _ipMapping;
            cmbIP.ItemsSource = _availableIPs;
            RefreshDeviceList();
        }
        public void SetControlsEnabled(bool isEnabled)
        {
            // ç¦ç”¨æˆ–启用所有可编辑的控件
            //LoadConfig_RJ.IsEnabled = isEnabled;
            cmbOrder.IsEnabled = isEnabled;
            cmbIP.IsEnabled = isEnabled;
            DeviceRefresh_PM.IsEnabled = isEnabled;
            AddMapping_PM.IsEnabled = isEnabled;
            SaveConfig_PM.IsEnabled = isEnabled;
            //LoadConfig_PM.IsEnabled = isEnabled;
            // ... å…¶ä»–需要控制的控件
        }
        private void RefreshDeviceList()
        {
            try
            {
                //获取设备列表句柄
                IntPtr devicesListHandle = IDVIEWER_DiscoveryDevices_(500);
                // èŽ·å–è®¾å¤‡æ€»æ•°
                int deviceCount = (int)IDVIEWER_GetDevicesLength_(devicesListHandle);
                // ç”Ÿæˆé¡ºåºå·é€‰é¡¹ï¼ˆ1~N)
                cmbOrder.ItemsSource = Enumerable.Range(1, deviceCount).ToList();
                cmbOrder.SelectedIndex = 0;
                List<string> ips = new List<string>();
                for (int i = 0; i < deviceCount; i++)
                {
                    //获取相机IP
                    IDViewerSDK.IDVIEWER_SelectIDDeviceInfo_(devicesListHandle, ref deviceInfo[i], (uint)i);
                    string deviceIP = deviceInfo[i].cameraIP.Trim();
                    ips.Add(deviceIP);
                }
                // èŽ·å–å¯ç”¨IP列表
                ips.Where(IsValidIP).ToList();
                _availableIPs.Clear();
                foreach (var ip in ips)
                {
                    _availableIPs.Add(ip);
                }
                tbStatus.Text = $"检测到 {deviceCount} å°è®¾å¤‡ | å¯ç”¨IP:{ips.Count} ä¸ª";
            }
            catch (Exception ex)
            {
                MessageBox.Show($"设备检测失败:{ex.Message}");
            }
        }
        private void BtnAddMapping_Click(object sender, RoutedEventArgs e)
        {
            if (cmbOrder.SelectedItem == null || cmbIP.SelectedItem == null)
            {
                MessageBox.Show("请选择顺序和IP地址");
                return;
            }
            int selectedOrder = (int)cmbOrder.SelectedItem;
            string selectedIP = cmbIP.SelectedItem.ToString();
            // æ£€æŸ¥é¡ºåºå†²çª
            if (_ipMapping.Any(x => x.Key == selectedOrder))
            {
                MessageBox.Show("该顺序已分配,请先移除原有分配");
                return;
            }
            // æ£€æŸ¥IP重复
            if (_ipMapping.Any(x => x.Value == selectedIP))
            {
                MessageBox.Show("该IP已分配顺序");
                return;
            }
            _ipMapping.Add(new KeyValuePair<int, string>(selectedOrder, selectedIP));
            SortMapping();
        }
        private void DeleteMapping_Click(object sender, RoutedEventArgs e)
        {
            if (dgMapping.SelectedItem is KeyValuePair<int, string> item)
            {
                _ipMapping.Remove(item);
                SortMapping();
            }
        }
        private void SortMapping()
        {
            var sorted = _ipMapping
                .OrderBy(x => x.Key)
                .ToList();
            _ipMapping.Clear();
            foreach (var item in sorted)
            {
                _ipMapping.Add(item);
            }
        }
        private void BtnRefreshDevices_Click(object sender, RoutedEventArgs e) => RefreshDeviceList();
        // ä¿å­˜/加载方法
        private void BtnSave_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var config = new
                {
                    LastModified = DateTime.Now,
                    Mapping = _ipMapping.ToList()
                };
                File.WriteAllText(ConfigFile, JsonConvert.SerializeObject(config, Formatting.Indented));
                MessageBox.Show("配置保存成功");
                // è®°å½•日志
                OperateLogService.LogOperation(
                    "映射表修改",
                    $"映射表修改为: {ConfigFile}",
                    null);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存失败:{ex.Message}");
            }
        }
        private void BtnLoad_Click(object sender, RoutedEventArgs e)
        {
          var loadedMapping = LoadConfig();
            if (loadedMapping.Count > 0)
            {
                _ipMapping.Clear(); // æ¸…空当前映射
                foreach (var item in loadedMapping)
                {
                    _ipMapping.Add(item); // æ·»åŠ åŠ è½½çš„é…ç½®
                }
                SortMapping(); // é‡æ–°æŽ’序
                RefreshMappingDisplay(); // åˆ·æ–°ç•Œé¢æ˜¾ç¤º
                MessageBox.Show("配置加载成功");
            }
        }
        private void RefreshMappingDisplay()
        {
            // ç»‘定数据到 DataGrid
            dgMapping.ItemsSource = null; // å…ˆæ¸…空绑定
            dgMapping.ItemsSource = _ipMapping.ToList(); // é‡æ–°ç»‘定
        }
        public List<KeyValuePair<int, string>> LoadConfig()
        {
            try
            {
                if (File.Exists(ConfigFile))
                {
                    var json = File.ReadAllText(ConfigFile);
                    var config = JsonConvert.DeserializeObject<dynamic>(json);
                    var mapping = new List<KeyValuePair<int, string>>();
                    foreach (var item in config.Mapping)
                    {
                        mapping.Add(new KeyValuePair<int, string>(
                            (int)item.Key,
                            (string)item.Value));
                    }
                    return mapping;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载映射表失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            return new List<KeyValuePair<int, string>>();
        }
        private static bool IsValidIP(string ip) => Regex.IsMatch(ip,
        @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    }
}
IDViewer_2D/Program.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using static IDViewerDemo.IDViewerDefines;
using static IDViewerDemo.IDViewerSDK;
namespace IDViewerDemo
{
    delegate void IDViewerCallBack(IntPtr device, IntPtr image, IntPtr decodeInfoHandel);
    class Program
    {
        static string filepath = "D:\\text.bmp";
        static void Main(string[] args)
        {
            int option = 0;
            long result = IDViewerSDK.IDVIEWER_Init_();
            while (0 == result)
            {
                ClearScreen();
                Console.WriteLine("0) é€€å‡ºç¨‹åº");
                Console.WriteLine("1) è¯»ç å™¨æ“ä½œ");
                if (GetInputOption(ref option) == false) continue;
                switch (option)
                {
                    case 0:
                        return;
                    case 1:
                        MenuIDViewer();
                        break;
                    default:
                        break;
                }
            }
        }
        static void MenuIDViewer()
        {
            int option = 0;
            while (true)
            {
                ClearScreen();
                Console.WriteLine("0) è¿”回上一级");
                Console.WriteLine("1) æ‰«ææ‰€æœ‰è¯»ç å™¨");
                Console.WriteLine("2) é€šè¿‡SN号连接读码器");
                if (GetInputOption(ref option) == false) continue;
                switch (option)
                {
                    case 0:
                        return;
                    case 1:
                        DiscoveryIDViewer();
                        system("pause");
                        break;
                    case 2:
                        DiscoveryIDViewer_SN();
                        system("pause");
                        break;
                    default:
                        break;
                }
            }
        }
        static void DiscoveryIDViewer()
        {
            IntPtr deviceList = IDVIEWER_DiscoveryDevices_();
            long length = IDVIEWER_GetDevicesLength_(deviceList);
            Console.WriteLine("获取到读码器个数为:" + length);
            IDDeviceInfo info = new IDDeviceInfo();
            for (uint i = 0; i < length; i++)
            {
                long Inforesult = IDVIEWER_SelectIDDeviceInfo_(deviceList, ref info, i);
                //Console.WriteLine(Inforesult);
                Console.WriteLine("*******************************************");
                if (i >= 0) Console.WriteLine("index:" + i);
                Console.WriteLine("networkIP:" + new string(info.networkIP));
                Console.WriteLine("networkMask:" + new string(info.networkMask));
                Console.WriteLine("networkGateway:" + new string(info.networkGateway));
                Console.WriteLine("cameraIP:" + new string(info.cameraIP));
                Console.WriteLine("cameraSN:" + new string(info.cameraSN));
                Console.WriteLine("cameraType:" + new string(info.cameraType));
            }
        }
        static void DiscoveryIDViewer_SN()
        {
            IntPtr device = IntPtr.Zero;
            IDDeviceInfo info = new IDDeviceInfo();
            Console.WriteLine("请输入SN号");
           String serialNum = Console.ReadLine();
            long result =  IDVIEWER_CreateDeviceBySN_(serialNum, ref device);
            if (device != IntPtr.Zero)
            {
                int option = 0;
                while (true)
                {
                    ClearScreen();
                    Console.WriteLine("0) è¿”回上一级");
                    Console.WriteLine("1) æ‰“å¼€");
                    Console.WriteLine("2) è¿è¡Œ");
                    Console.WriteLine("3) è¿žæŽ¥çŠ¶æ€");
                    Console.WriteLine("4) å…³é—­");
                    if (GetInputOption(ref option) == false) continue;
                    if (option == 0)
                    {
                        return;
                    }
                    if (option < 1 || option > 10)
                    {
                        continue;
                    }
                    switch (option)
                    {
                        case 1:
                            IDDevice_Open(device);
                            break;
                        case 2:
                            Device_StartRunning(device);
                            break;
                        case 3:
                            Device_IsOpen(device);
                            break;
                        case 4:
                            IDDevice_Close(device);
                            break;
                        default:
                            break;
                    }
                    system("pause");
                }
            }
        }
        static IDViewerCallBack callbackDelegate;
        static IDDecodeInfo decodeInfo;
        public static void CallBack(IntPtr device, IntPtr image, IntPtr decodeInfoHandel)
        {
            IDDecodeInfo info = new IDDecodeInfo();
            IDCallback_GetIDDecodeInfo_A(decodeInfoHandel, ref info);       //ROI解码信息数组的长度 èŽ·å–åˆ°ROI的解码数量
            if (info.decodeStatus)
            {
                for (uint roi = 0; roi < info.IDDecodeROIInfoLength; roi++)
                {
                    IDDecodeROIInfo IDpecodeROIInfo = IDCallback_GetIDDecodeROIInfo(decodeInfoHandel, 0);
                    if (IDpecodeROIInfo.decodeReusltLength > 0)
                    {
                        IDDecodeResult IDpecodeResult = IDCallback_GetIDDecodeResult(decodeInfoHandel, roi, 0);
                        if (IDpecodeResult.dmResultsLength != 0)
                        {
                            for (uint dmSuccessNumber = 0; dmSuccessNumber < IDpecodeResult.dmResultsLength; dmSuccessNumber++)
                            {
                                IDDMCodeResult DMBarCodeResultData = new IDDMCodeResult();
                                long a = IDCallback_GetIDDMCodeResult(decodeInfoHandel, roi, 0, dmSuccessNumber, ref DMBarCodeResultData);
                                Console.WriteLine("ROI:" + (roi + 1));
                                Console.WriteLine("SuccessNumber:" + (dmSuccessNumber + 1));
                                Console.WriteLine("subType:" + new string(DMBarCodeResultData.subType));
                                Console.WriteLine("codeString: " + new string(DMBarCodeResultData.codeString));
                            }
                        }
                        else if (IDpecodeResult.qrResultsLength != 0)
                        {
                            for (uint qrSuccessNumber = 0; qrSuccessNumber < IDpecodeResult.qrResultsLength; qrSuccessNumber++)
                            {
                                IDQRCodeResult QRBarCodeResultData = new IDQRCodeResult();
                                long a = IDCallback_GetID_QR_CODE_Result(decodeInfoHandel, roi, 0, qrSuccessNumber, ref QRBarCodeResultData);
                                Console.WriteLine("ROI:" + (roi + 1));
                                Console.WriteLine("SuccessNumber:" + (qrSuccessNumber + 1));
                                Console.WriteLine("subType:" + new string(QRBarCodeResultData.subType));
                                Console.WriteLine("codeString: " + new string(QRBarCodeResultData.codeString));
                            }
                        }
                        else if (IDpecodeResult.pdf417ResultsLength != 0)
                        {
                            for (uint pdf417SuccessNumber = 0; pdf417SuccessNumber < IDpecodeResult.qrResultsLength; pdf417SuccessNumber++)
                            {
                                IDPDF417CodeResult PDF417BarCodeResultData = new IDPDF417CodeResult();
                                long a = IDCallback_GetIDPDF417CodeResult(decodeInfoHandel, roi, 0, pdf417SuccessNumber, ref PDF417BarCodeResultData);
                                Console.WriteLine("ROI:" + (roi + 1));
                                Console.WriteLine("SuccessNumber:" + (pdf417SuccessNumber + 1));
                                Console.WriteLine("subType:" + new string(PDF417BarCodeResultData.subType));
                                Console.WriteLine("codeString: " + new string(PDF417BarCodeResultData.codeString));
                            }
                        }
                        else if (IDpecodeResult.barcodeResultsLength != 0)
                        {
                            for (uint barcodeSuccessNumber = 0; barcodeSuccessNumber < IDpecodeResult.qrResultsLength; barcodeSuccessNumber++)
                            {
                                IDBarCodeResult IDBarCodeResultData = new IDBarCodeResult();
                                long a = IDCallback_GetIDBarCodeResult(decodeInfoHandel, roi, 0, barcodeSuccessNumber, ref IDBarCodeResultData);
                                Console.WriteLine("ROI:" + (roi + 1));
                                Console.WriteLine("SuccessNumber:" + (barcodeSuccessNumber + 1));
                                Console.WriteLine("codeString: " + new string(IDBarCodeResultData.codeString));
                            }
                        }
                    }
                }
            }
        }
        static void Device_StartRunning(IntPtr device)
        {
            IDDevice_StartRunning(device,1);
            callbackDelegate = new IDViewerCallBack(CallBack);
            IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(callbackDelegate);
            IDCallback_ResultNotify_(device, functionPointer);
            GC.KeepAlive(callbackDelegate);
        }
        static void Device_IsOpen(IntPtr device)
        {
            long rel = IDDevice_IsOpen(device);
            if (rel == 0)
            {
                Console.WriteLine("读码器未打开");
            }
            else
            {
                Console.WriteLine("读码器已打开");
            }
        }
        static bool GetInputOption(ref int option)
        {
            int op;
            try
            {
                op = int.Parse(Console.ReadLine());
            }
            catch
            {
                return false;
            }
            option = op;
            return true;
        }
        static void ClearScreen()
        {
            system("cls");
            Console.WriteLine("*******************************************");
            Console.WriteLine("*              IDViewer Demo              *");
            Console.WriteLine("*******************************************");
        }
        [DllImport("msvcrt.dll", SetLastError = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        private extern static void system(string command);
    }
}
IDViewer_2D/Properties/AssemblyInfo.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// æœ‰å…³ç¨‹åºé›†çš„一般信息由以下
// æŽ§åˆ¶ã€‚更改这些特性值可修改
// ä¸Žç¨‹åºé›†å…³è”的信息。
[assembly: AssemblyTitle("SmartScanner")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SmartScanner")]
[assembly: AssemblyCopyright("Copyright Â©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// å°† ComVisible è®¾ç½®ä¸º false ä¼šä½¿æ­¤ç¨‹åºé›†ä¸­çš„类型
//对 COM ç»„件不可见。如果需要从 COM è®¿é—®æ­¤ç¨‹åºé›†ä¸­çš„类型
//请将此类型的 ComVisible ç‰¹æ€§è®¾ç½®ä¸º true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj æ–‡ä»¶ä¸­çš„ <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> è®¾ç½®ä¸º en-US。  ç„¶åŽå–消
//对以下 NeutralResourceLanguage ç‰¹æ€§çš„æ³¨é‡Šã€‚  æ›´æ–°
//以下行中的“en-US”以匹配项目文件中的 UICulture è®¾ç½®ã€‚
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
    ResourceDictionaryLocation.None, //主题特定资源词典所处位置
                                     //(未在页面中找到资源时使用,
                                     //或应用程序资源字典中找到时使用)
    ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
                                              //(未在页面中找到资源时使用,
                                              //、应用程序或任何主题专用资源字典中找到时使用)
)]
// ç¨‹åºé›†çš„版本信息由下列四个值组成:
//
//      ä¸»ç‰ˆæœ¬
//      æ¬¡ç‰ˆæœ¬
//      ç”Ÿæˆå·
//      ä¿®è®¢å·
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
IDViewer_2D/Properties/Resources.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     æ­¤ä»£ç ç”±å·¥å…·ç”Ÿæˆã€‚
//     è¿è¡Œæ—¶ç‰ˆæœ¬:4.0.30319.42000
//
//     å¯¹æ­¤æ–‡ä»¶çš„æ›´æ”¹å¯èƒ½ä¼šå¯¼è‡´ä¸æ­£ç¡®çš„行为,并且如果
//     é‡æ–°ç”Ÿæˆä»£ç ï¼Œè¿™äº›æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚
// </auto-generated>
//------------------------------------------------------------------------------
namespace SmartScanner.Properties {
    using System;
    /// <summary>
    ///   ä¸€ä¸ªå¼ºç±»åž‹çš„资源类,用于查找本地化的字符串等。
    /// </summary>
    // æ­¤ç±»æ˜¯ç”± StronglyTypedResourceBuilder
    // ç±»é€šè¿‡ç±»ä¼¼äºŽ ResGen æˆ– Visual Studio çš„工具自动生成的。
    // è‹¥è¦æ·»åŠ æˆ–ç§»é™¤æˆå‘˜ï¼Œè¯·ç¼–è¾‘ .ResX æ–‡ä»¶ï¼Œç„¶åŽé‡æ–°è¿è¡Œ ResGen
    // (以 /str ä½œä¸ºå‘½ä»¤é€‰é¡¹),或重新生成 VS é¡¹ç›®ã€‚
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resources {
        private static global::System.Resources.ResourceManager resourceMan;
        private static global::System.Globalization.CultureInfo resourceCulture;
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources() {
        }
        /// <summary>
        ///   è¿”回此类使用的缓存的 ResourceManager å®žä¾‹ã€‚
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SmartScanner.Properties.Resources", typeof(Resources).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        /// <summary>
        ///   é‡å†™å½“前线程的 CurrentUICulture å±žæ€§ï¼Œå¯¹
        ///   ä½¿ç”¨æ­¤å¼ºç±»åž‹èµ„源类的所有资源查找执行重写。
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
    }
}
IDViewer_2D/Properties/Resources.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--
    Microsoft ResX Schema
    Version 2.0
    The primary goals of this format is to allow a simple XML format
    that is mostly human readable. The generation and parsing of the
    various data types are done through the TypeConverter classes
    associated with the data types.
    Example:
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
    There are any number of "resheader" rows that contain simple
    name/value pairs.
    Each data row contains a name, and value. The row also contains a
    type or mimetype. Type corresponds to a .NET class that support
    text/value conversion through the TypeConverter architecture.
    Classes that don't support this are serialized and stored with the
    mimetype set.
    The mimetype is used for serialized objects, and tells the
    ResXResourceReader how to depersist the object. This is currently not
    extensible. For a given mimetype the value must be set accordingly:
    Note - application/x-microsoft.net.object.binary.base64 is the format
    that the ResXResourceWriter will generate, however the reader can
    read any of the formats listed below.
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with
            : System.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
</root>
IDViewer_2D/Properties/Settings.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,182 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     æ­¤ä»£ç ç”±å·¥å…·ç”Ÿæˆã€‚
//     è¿è¡Œæ—¶ç‰ˆæœ¬:4.0.30319.42000
//
//     å¯¹æ­¤æ–‡ä»¶çš„æ›´æ”¹å¯èƒ½ä¼šå¯¼è‡´ä¸æ­£ç¡®çš„行为,并且如果
//     é‡æ–°ç”Ÿæˆä»£ç ï¼Œè¿™äº›æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚
// </auto-generated>
//------------------------------------------------------------------------------
namespace SmartScanner.Properties {
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
        public static Settings Default {
            get {
                return defaultInstance;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("")]
        public string LastConfigFilePath {
            get {
                return ((string)(this["LastConfigFilePath"]));
            }
            set {
                this["LastConfigFilePath"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("")]
        public string DataSavingRoad {
            get {
                return ((string)(this["DataSavingRoad"]));
            }
            set {
                this["DataSavingRoad"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("False")]
        public bool ImageDeleteEnabled {
            get {
                return ((bool)(this["ImageDeleteEnabled"]));
            }
            set {
                this["ImageDeleteEnabled"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("30")]
        public int DeleteImageDays {
            get {
                return ((int)(this["DeleteImageDays"]));
            }
            set {
                this["DeleteImageDays"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("True")]
        public bool ImageSaveEnabled {
            get {
                return ((bool)(this["ImageSaveEnabled"]));
            }
            set {
                this["ImageSaveEnabled"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("0")]
        public int CompressionRatio {
            get {
                return ((int)(this["CompressionRatio"]));
            }
            set {
                this["CompressionRatio"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("0")]
        public int ImageFormatSelect {
            get {
                return ((int)(this["ImageFormatSelect"]));
            }
            set {
                this["ImageFormatSelect"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("20")]
        public int MemoryAlarmSetting {
            get {
                return ((int)(this["MemoryAlarmSetting"]));
            }
            set {
                this["MemoryAlarmSetting"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("False")]
        public bool MemoryAlarmEnabled {
            get {
                return ((bool)(this["MemoryAlarmEnabled"]));
            }
            set {
                this["MemoryAlarmEnabled"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("False")]
        public bool OutputCheckBoxEnable {
            get {
                return ((bool)(this["OutputCheckBoxEnable"]));
            }
            set {
                this["OutputCheckBoxEnable"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("\"8080\"")]
        public string DefaultPort {
            get {
                return ((string)(this["DefaultPort"]));
            }
            set {
                this["DefaultPort"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("8080")]
        public int SelectedPort {
            get {
                return ((int)(this["SelectedPort"]));
            }
            set {
                this["SelectedPort"] = value;
            }
        }
        [global::System.Configuration.UserScopedSettingAttribute()]
        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.Configuration.DefaultSettingValueAttribute("")]
        public string LastConfigFilePath_Proj {
            get {
                return ((string)(this["LastConfigFilePath_Proj"]));
            }
            set {
                this["LastConfigFilePath_Proj"] = value;
            }
        }
    }
}
IDViewer_2D/Properties/Settings.settings
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="SmartScanner.Properties" GeneratedClassName="Settings">
  <Profiles />
  <Settings>
    <Setting Name="LastConfigFilePath" Type="System.String" Scope="User">
      <Value Profile="(Default)" />
    </Setting>
    <Setting Name="DataSavingRoad" Type="System.String" Scope="User">
      <Value Profile="(Default)" />
    </Setting>
    <Setting Name="ImageDeleteEnabled" Type="System.Boolean" Scope="User">
      <Value Profile="(Default)">False</Value>
    </Setting>
    <Setting Name="DeleteImageDays" Type="System.Int32" Scope="User">
      <Value Profile="(Default)">30</Value>
    </Setting>
    <Setting Name="ImageSaveEnabled" Type="System.Boolean" Scope="User">
      <Value Profile="(Default)">True</Value>
    </Setting>
    <Setting Name="CompressionRatio" Type="System.Int32" Scope="User">
      <Value Profile="(Default)">0</Value>
    </Setting>
    <Setting Name="ImageFormatSelect" Type="System.Int32" Scope="User">
      <Value Profile="(Default)">0</Value>
    </Setting>
    <Setting Name="MemoryAlarmSetting" Type="System.Int32" Scope="User">
      <Value Profile="(Default)">20</Value>
    </Setting>
    <Setting Name="MemoryAlarmEnabled" Type="System.Boolean" Scope="User">
      <Value Profile="(Default)">False</Value>
    </Setting>
    <Setting Name="OutputCheckBoxEnable" Type="System.Boolean" Scope="User">
      <Value Profile="(Default)">False</Value>
    </Setting>
    <Setting Name="DefaultPort" Type="System.String" Scope="User">
      <Value Profile="(Default)">"8080"</Value>
    </Setting>
    <Setting Name="SelectedPort" Type="System.Int32" Scope="User">
      <Value Profile="(Default)">8080</Value>
    </Setting>
    <Setting Name="LastConfigFilePath_Proj" Type="System.String" Scope="User">
      <Value Profile="(Default)" />
    </Setting>
  </Settings>
</SettingsFile>
IDViewer_2D/ResultJudge.xaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
<Window x:Class="SmartScanner.ResultJudge"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SmartScanner"
        mc:Ignorable="d"
        Title="检测方案编辑" Height="600" Width="450">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="15*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="检测方案编辑器" FontSize="16" FontWeight="Bold" Margin="0,0,0,10"/>
        <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
            <ItemsControl ItemsSource="{Binding JudgmentPoints}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Border BorderBrush="LightGray" BorderThickness="1" Margin="0,5" Padding="10">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" Text="{Binding PointNumber}"
                                           FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,10,0"/>
                                <StackPanel Grid.Column="1">
                                    <StackPanel Orientation="Horizontal" Margin="0,0,0,5">
                                        <TextBlock Text="目标数量:" Width="80"/>
                                        <ComboBox ItemsSource="{Binding DataContext.TargetCountOptions, RelativeSource={RelativeSource AncestorType=Window}}"
                                                  SelectedItem="{Binding TargetCount}" Width="50"/>
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal" Margin="0,0,0,5">
                                        <TextBlock Text="得分阈值:" Width="80"/>
                                        <TextBox Text="{Binding ScoreThreshold}" Width="50"/>
                                    </StackPanel>
                                    <ItemsControl ItemsSource="{Binding TargetConditions}" Margin="10,0,0,0">
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <StackPanel Orientation="Horizontal" Margin="0,0,0,5">
                                                    <TextBlock Text="目标类型:" Width="80"/>
                                                    <ComboBox ItemsSource="{Binding DataContext.TargetTypeOptions, RelativeSource={RelativeSource AncestorType=Window}}"
                          SelectedItem="{Binding TargetType}" Width="50"/>
                                                </StackPanel>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                    </ItemsControl>
                                </StackPanel>
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
        <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,0">
            <Button x:Name="LoadConfig_RJ" Content="加载配置" Width="80" Margin="0,0,10,0" Command="{Binding LoadCommand}"/>
            <Button x:Name="SaveConfig_RJ" Content="保存配置" Width="80" Command="{Binding SaveCommand}"/>
        </StackPanel>
    </Grid>
</Window>
IDViewer_2D/ResultJudge.xaml.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,384 @@
using System;
using System.Linq;
using System.Windows;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Collections.Generic;
using Newtonsoft.Json;
using SmartScanner.OperateLog;
namespace SmartScanner
{
    public partial class ResultJudge : Window
    {
        public static class AppSettings
        {
            private static readonly string SettingsKey = "LastConfigFilePath";
            public static string LastConfigFilePath
            {
                get => Properties.Settings.Default.LastConfigFilePath ?? string.Empty;
                set
                {
                    Properties.Settings.Default.LastConfigFilePath = value;
                    Properties.Settings.Default.Save();
                }
            }
            private static readonly string SettingsKey_Proj = "LastConfigFilePath_Proj";
            public static string LastConfigFilePath_Proj
            {
                get => Properties.Settings.Default.LastConfigFilePath_Proj ?? string.Empty;
                set
                {
                    Properties.Settings.Default.LastConfigFilePath_Proj = value;
                    Properties.Settings.Default.Save();
                }
            }
        }
        public ResultJudgeViewModel ViewModel { get; set; }
        public ResultJudge()
        {
            InitializeComponent();
            ViewModel = new ResultJudgeViewModel();
            DataContext = ViewModel;
        }
        public void SetControlsEnabled(bool isEnabled)
        {
            SaveConfig_RJ.IsEnabled = isEnabled;
        }
        public class ResultJudgeViewModel : BaseViewModel
        {
            public ObservableCollection<int> TargetCountOptions { get; } = new ObservableCollection<int> { 0, 1, 2, 3, 4 };
            public ObservableCollection<int> TargetTypeOptions { get; } = new ObservableCollection<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
            public ObservableCollection<JudgmentPoint> JudgmentPoints { get; set; } = new ObservableCollection<JudgmentPoint>();
            public ICommand SaveCommand { get; }
            public ICommand LoadCommand { get; }
            public ResultJudgeViewModel()
            {
                // åˆå§‹åŒ–20个点位
                for (int i = 1; i <= 20; i++)
                {
                    JudgmentPoints.Add(new JudgmentPoint(i, this));
                }
                SaveCommand = new RelayCommand(SaveConfiguration);
                LoadCommand = new RelayCommand(LoadConfiguration);
            }
            private void SaveConfiguration()
            {
                try
                {
                    var config = JudgmentConfiguration.FromViewModel(this);
                    var json = JsonConvert.SerializeObject(config, Formatting.Indented);
                    var saveFileDialog = new Microsoft.Win32.SaveFileDialog
                    {
                        Filter = "JSON æ–‡ä»¶ (*.json)|*.json|所有文件 (*.*)|*.*",
                        DefaultExt = ".json",
                        AddExtension = true,
                        Title = "保存配置文件",
                        FileName = Properties.Settings.Default.LastConfigFilePath
                    };
                    if (saveFileDialog.ShowDialog() == true)
                    {
                        File.WriteAllText(saveFileDialog.FileName, json);
                        Properties.Settings.Default.LastConfigFilePath = saveFileDialog.FileName;
                        Properties.Settings.Default.Save();
                        MessageBox.Show($"配置已成功保存到: {saveFileDialog.FileName}", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
                        OperateLogService.LogOperation("检测方案修改", $"检测方案修改为: {saveFileDialog.FileName}", null);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"保存配置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            private void LoadConfiguration()
            {
                try
                {
                    var openFileDialog = new Microsoft.Win32.OpenFileDialog
                    {
                        Filter = "JSON æ–‡ä»¶ (*.json)|*.json|所有文件 (*.*)|*.*",
                        DefaultExt = ".json",
                        Title = "加载配置文件",
                        FileName = AppSettings.LastConfigFilePath
                    };
                    if (openFileDialog.ShowDialog() == true)
                    {
                        var json = File.ReadAllText(openFileDialog.FileName);
                        AppSettings.LastConfigFilePath = openFileDialog.FileName;
                        var config = JsonConvert.DeserializeObject<JudgmentConfiguration>(json);
                        // ä½¿ç”¨ä¿®æ”¹åŽçš„ToViewModel方法
                        JudgmentConfiguration.ToViewModel(config, this);
                        MessageBox.Show($"配置已成功从 {openFileDialog.FileName} åŠ è½½", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"加载配置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }
        public class JudgmentPoint : BaseViewModel
        {
            private readonly ResultJudgeViewModel _parent;
            public int PointNumber { get; }
            private int _targetCount;
            public int TargetCount
            {
                get => _targetCount;
                set
                {
                    if (SetProperty(ref _targetCount, value))
                    {
                        UpdateTargetConditions();
                    }
                }
            }
            private int _scoreThreshold;
            public int ScoreThreshold
            {
                get => _scoreThreshold;
                set
                {
                    if (SetProperty(ref _scoreThreshold, value))
                    {
                        foreach (var condition in TargetConditions)
                        {
                            condition.ScoreThreshold = value;
                        }
                    }
                }
            }
            public ObservableCollection<TargetCondition> TargetConditions { get; } = new ObservableCollection<TargetCondition>();
            public JudgmentPoint(int pointNumber, ResultJudgeViewModel parent)
            {
                PointNumber = pointNumber;
                _parent = parent;
                TargetCount = 0;
            }
            private void UpdateTargetConditions()
            {
                // åªæ·»åŠ ç¼ºå°‘çš„æ¡ä»¶ï¼Œä¸åˆ é™¤å·²æœ‰æ¡ä»¶
                int currentCount = TargetConditions.Count;
                if (currentCount < TargetCount)
                {
                    for (int i = currentCount; i < TargetCount; i++)
                    {
                        TargetConditions.Add(new TargetCondition
                        {
                            ScoreThreshold = this.ScoreThreshold
                        });
                    }
                }
                else if (currentCount > TargetCount)
                {
                    // åªç§»é™¤å¤šä½™çš„æ¡ä»¶
                    for (int i = currentCount - 1; i >= TargetCount; i--)
                    {
                        TargetConditions.RemoveAt(i);
                    }
                }
            }
        }
        public class TargetCondition : BaseViewModel
        {
            private int _targetType;
            public int TargetType
            {
                get => _targetType;
                set => SetProperty(ref _targetType, value);
            }
            [JsonIgnore]
            public int ScoreThreshold { get; set; }
        }
        public class JudgmentConfiguration
        {
            public List<JudgmentPointData> Points { get; set; }
            public static JudgmentConfiguration FromViewModel(ResultJudgeViewModel viewModel)
            {
                var config = new JudgmentConfiguration
                {
                    Points = new List<JudgmentPointData>()
                };
                foreach (var point in viewModel.JudgmentPoints)
                {
                    var pointData = new JudgmentPointData
                    {
                        PointNumber = point.PointNumber,
                        TargetCount = point.TargetCount,
                        Conditions = new List<TargetConditionData>()
                    };
                    foreach (var condition in point.TargetConditions)
                    {
                        pointData.Conditions.Add(new TargetConditionData
                        {
                            TargetType = condition.TargetType,
                            ScoreThreshold = point.ScoreThreshold
                        });
                    }
                    config.Points.Add(pointData);
                }
                return config;
            }
            public static void ToViewModel(JudgmentConfiguration config, ResultJudgeViewModel viewModel)
            {
                // å…ˆæ¸…空所有点位
                viewModel.JudgmentPoints.Clear();
                // é‡æ–°åˆ›å»ºç‚¹ä½å¹¶åŠ è½½é…ç½®
                for (int i = 1; i <= 20; i++)
                {
                    var pointData = config.Points.FirstOrDefault(p => p.PointNumber == i);
                    var point = new JudgmentPoint(i, viewModel);
                    if (pointData != null)
                    {
                        point.TargetCount = pointData.TargetCount;
                        point.ScoreThreshold = pointData.Conditions.FirstOrDefault()?.ScoreThreshold ?? 0;
                        // æ¸…除自动生成的条件
                        point.TargetConditions.Clear();
                        // æ·»åŠ é…ç½®ä¸­çš„æ¡ä»¶
                        foreach (var conditionData in pointData.Conditions)
                        {
                            point.TargetConditions.Add(new TargetCondition
                            {
                                TargetType = conditionData.TargetType,
                                ScoreThreshold = point.ScoreThreshold
                            });
                        }
                    }
                    viewModel.JudgmentPoints.Add(point);
                }
            }
            public int JudgeDetectionResult(int pointNumber, int[] numBoxes, int[] classIds, float[] prob)
            {
                var pointConfig = Points.FirstOrDefault(p => p.PointNumber == pointNumber);
                if (pointConfig == null) return 0;
                // ç¬¬ä¸€å±‚判断:目标数量
                if (numBoxes[0] < pointConfig.TargetCount)
                {
                    return 0;
                }
                // ç¬¬äºŒå±‚判断:目标类型
                bool typeMatch = true;
                switch (pointConfig.TargetCount)
                {
                    case 0:
                        return 1;
                    case 1:
                        typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType);
                        break;
                    case 2:
                        typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[1].TargetType);
                        break;
                    case 3:
                        typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[1].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[2].TargetType);
                        break;
                    case 4:
                        typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[1].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[2].TargetType) &&
                                   classIds.Contains(pointConfig.Conditions[3].TargetType);
                        break;
                }
                if (!typeMatch)
                {
                    return 0;
                }
                // ç¬¬ä¸‰å±‚判断:得分阈值(使用第一个条件的阈值)
                float threshold = pointConfig.Conditions[0].ScoreThreshold / 100f;
                return prob.Take(pointConfig.TargetCount).All(p => p >= threshold) ? 1 : 0;
            }
        }
        public class JudgmentPointData
        {
            public int PointNumber { get; set; }
            public int TargetCount { get; set; }
            public List<TargetConditionData> Conditions { get; set; }
        }
        public class TargetConditionData
        {
            public int TargetType { get; set; }
            public int ScoreThreshold { get; set; }
        }
        public class BaseViewModel : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected bool SetProperty<T>(ref T field, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
            {
                if (EqualityComparer<T>.Default.Equals(field, value)) return false;
                field = value;
                PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
                return true;
            }
        }
        public class RelayCommand : ICommand
        {
            private readonly Action _execute;
            private readonly Func<bool> _canExecute;
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
            public RelayCommand(Action execute, Func<bool> canExecute = null)
            {
                _execute = execute ?? throw new ArgumentNullException(nameof(execute));
                _canExecute = canExecute;
            }
            public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
            public void Execute(object parameter) => _execute();
        }
    }
}
IDViewer_2D/Settings.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
namespace SmartScanner.Properties {
    // é€šè¿‡æ­¤ç±»å¯ä»¥å¤„理设置类的特定事件:
    //  åœ¨æ›´æ”¹æŸä¸ªè®¾ç½®çš„值之前将引发 SettingChanging äº‹ä»¶ã€‚
    //  åœ¨æ›´æ”¹æŸä¸ªè®¾ç½®çš„值之后将引发 PropertyChanged äº‹ä»¶ã€‚
    //  åœ¨åŠ è½½è®¾ç½®å€¼ä¹‹åŽå°†å¼•å‘ SettingsLoaded äº‹ä»¶ã€‚
    //  åœ¨ä¿å­˜è®¾ç½®å€¼ä¹‹å‰å°†å¼•发 SettingsSaving äº‹ä»¶ã€‚
    internal sealed partial class Settings {
        public Settings() {
            // // è‹¥è¦ä¸ºä¿å­˜å’Œæ›´æ”¹è®¾ç½®æ·»åŠ äº‹ä»¶å¤„ç†ç¨‹åºï¼Œè¯·å–æ¶ˆæ³¨é‡Šä¸‹åˆ—è¡Œ:
            //
            // this.SettingChanging += this.SettingChangingEventHandler;
            //
            // this.SettingsSaving += this.SettingsSavingEventHandler;
            //
        }
        private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
            // åœ¨æ­¤å¤„添加用于处理 SettingChangingEvent äº‹ä»¶çš„代码。
        }
        private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
            // åœ¨æ­¤å¤„添加用于处理 SettingsSaving äº‹ä»¶çš„代码。
        }
    }
}
IDViewer_2D/SmartScanner.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,365 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props" Condition="Exists('..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props')" />
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{D1C98439-DD40-43CD-BC99-899868FD2EDF}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <RootNamespace>SmartScanner</RootNamespace>
    <AssemblyName>SmartScanner</AssemblyName>
    <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <WarningLevel>4</WarningLevel>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <Deterministic>true</Deterministic>
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
    <TargetFrameworkProfile />
    <PublishUrl>publish\</PublishUrl>
    <Install>true</Install>
    <InstallFrom>Disk</InstallFrom>
    <UpdateEnabled>false</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>false</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>
    <MapFileExtensions>true</MapFileExtensions>
    <ApplicationRevision>0</ApplicationRevision>
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
    <IsWebBootstrapper>false</IsWebBootstrapper>
    <UseApplicationTrust>false</UseApplicationTrust>
    <BootstrapperEnabled>true</BootstrapperEnabled>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x64\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <LangVersion>7.3</LangVersion>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
    <OutputPath>bin\x64\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <Optimize>true</Optimize>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <LangVersion>7.3</LangVersion>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup>
    <StartupObject />
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x86\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>full</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <LangVersion>7.3</LangVersion>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
    <OutputPath>bin\x86\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <Optimize>true</Optimize>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <LangVersion>7.3</LangVersion>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
  </PropertyGroup>
  <PropertyGroup>
    <ApplicationIcon>IDViewer2D.ico</ApplicationIcon>
  </PropertyGroup>
  <PropertyGroup />
  <PropertyGroup />
  <ItemGroup>
    <Reference Include="EPPlus, Version=8.0.7.0, Culture=neutral, PublicKeyToken=ea159fdaa78159a1, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>bin\x64\Debug\EPPlus.dll</HintPath>
    </Reference>
    <Reference Include="EPPlus.Interfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=a694d7f3b0907a61, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>bin\x64\Debug\EPPlus.Interfaces.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.3.0.1\lib\netstandard2.0\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
    </Reference>
    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="NModbus, Version=3.0.81.0, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>bin\x64\Debug\NModbus.dll</HintPath>
    </Reference>
    <Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
      <HintPath>..\packages\OpenCvSharp4.4.10.0.20241108\lib\netstandard2.0\OpenCvSharp.dll</HintPath>
    </Reference>
    <Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
      <HintPath>..\packages\OpenCvSharp4.Extensions.4.10.0.20241108\lib\netstandard2.0\OpenCvSharp.Extensions.dll</HintPath>
    </Reference>
    <Reference Include="OpenCvSharp.WpfExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\OpenCvSharp4.WpfExtensions.4.5.1.20210210\lib\net461\OpenCvSharp.WpfExtensions.dll</HintPath>
    </Reference>
    <Reference Include="Syncfusion.Compression.Portable, Version=29.1.37.0, Culture=neutral, PublicKeyToken=3d67ed1f87d44c89, processorArchitecture=MSIL">
      <HintPath>..\packages\Syncfusion.Compression.Net.Core.29.1.37\lib\netstandard2.0\Syncfusion.Compression.Portable.dll</HintPath>
    </Reference>
    <Reference Include="Syncfusion.Licensing, Version=29.1462.37.0, Culture=neutral, PublicKeyToken=632609b4d040f6b4, processorArchitecture=MSIL">
      <HintPath>..\packages\Syncfusion.Licensing.29.1.37\lib\net462\Syncfusion.Licensing.dll</HintPath>
    </Reference>
    <Reference Include="Syncfusion.OfficeChart.Portable, Version=29.1.37.0, Culture=neutral, PublicKeyToken=3d67ed1f87d44c89, processorArchitecture=MSIL">
      <HintPath>..\packages\Syncfusion.OfficeChart.Net.Core.29.1.37\lib\netstandard2.0\Syncfusion.OfficeChart.Portable.dll</HintPath>
    </Reference>
    <Reference Include="Syncfusion.Presentation.Portable, Version=29.1.37.0, Culture=neutral, PublicKeyToken=3d67ed1f87d44c89, processorArchitecture=MSIL">
      <HintPath>..\packages\Syncfusion.Presentation.Net.Core.29.1.37\lib\netstandard2.0\Syncfusion.Presentation.Portable.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
    </Reference>
    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.ComponentModel.Annotations.5.0.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
    </Reference>
    <Reference Include="System.ComponentModel.DataAnnotations" />
    <Reference Include="System.configuration" />
    <Reference Include="System.Data" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.IO.Compression.FileSystem" />
    <Reference Include="System.Management" />
    <Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
    </Reference>
    <Reference Include="System.Numerics" />
    <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
    </Reference>
    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
    </Reference>
    <Reference Include="System.Security" />
    <Reference Include="System.Security.Cryptography.Xml, Version=8.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Security.Cryptography.Xml.8.0.2\lib\net462\System.Security.Cryptography.Xml.dll</HintPath>
    </Reference>
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xaml">
      <RequiredTargetFramework>4.0</RequiredTargetFramework>
    </Reference>
    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
    <Reference Include="Xceed.Wpf.AvalonDock, Version=4.7.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
      <HintPath>..\packages\Extended.Wpf.Toolkit.4.7.25104.5739\lib\net40\Xceed.Wpf.AvalonDock.dll</HintPath>
    </Reference>
    <Reference Include="Xceed.Wpf.AvalonDock.Themes.Aero, Version=4.7.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
      <HintPath>..\packages\Extended.Wpf.Toolkit.4.7.25104.5739\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll</HintPath>
    </Reference>
    <Reference Include="Xceed.Wpf.AvalonDock.Themes.Metro, Version=4.7.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
      <HintPath>..\packages\Extended.Wpf.Toolkit.4.7.25104.5739\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll</HintPath>
    </Reference>
    <Reference Include="Xceed.Wpf.AvalonDock.Themes.VS2010, Version=4.7.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
      <HintPath>..\packages\Extended.Wpf.Toolkit.4.7.25104.5739\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll</HintPath>
    </Reference>
    <Reference Include="Xceed.Wpf.Toolkit, Version=4.7.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
      <HintPath>..\packages\Extended.Wpf.Toolkit.4.7.25104.5739\lib\net40\Xceed.Wpf.Toolkit.dll</HintPath>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <ApplicationDefinition Include="App.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </ApplicationDefinition>
    <Compile Include="AppRestartHelper.cs" />
    <Compile Include="DownloadData.xaml.cs">
      <DependentUpon>DownloadData.xaml</DependentUpon>
    </Compile>
    <Compile Include="ExcelResultRecorder.cs" />
    <Compile Include="ImageService\ImageCleanupService.cs" />
    <Compile Include="ImageDisplayWindow .xaml.cs">
      <DependentUpon>ImageDisplayWindow .xaml</DependentUpon>
    </Compile>
    <Compile Include="ImageService\MemoryAlarmCheck.cs" />
    <Compile Include="LBProjService.cs" />
    <Compile Include="LBProtect.cs" />
    <Compile Include="LogAutoSaveService.cs" />
    <Compile Include="LoginWindow.xaml.cs">
      <DependentUpon>LoginWindow.xaml</DependentUpon>
    </Compile>
    <Compile Include="OperateLog\OperateLogService.cs" />
    <Compile Include="OperateLog\OperateLogView.xaml.cs">
      <DependentUpon>OperateLogView.xaml</DependentUpon>
    </Compile>
    <Compile Include="ResultJudge.xaml.cs">
      <DependentUpon>ResultJudge.xaml</DependentUpon>
    </Compile>
    <Compile Include="Settings.cs" />
    <Compile Include="TcpServerManager.cs" />
    <Compile Include="User.cs" />
    <Compile Include="ViewModel\LogViewModel.cs" />
    <Page Include="DownloadData.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="ImageDisplayWindow .xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="LoadingWindow.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="LoginWindow.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="MainWindow.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
    <Compile Include="App.xaml.cs">
      <DependentUpon>App.xaml</DependentUpon>
      <SubType>Code</SubType>
    </Compile>
    <Compile Include="IDViewerDefines.cs" />
    <Compile Include="IDViewerSDK.cs" />
    <Compile Include="IDViewerSDK2.cs" />
    <Compile Include="LoadingWindow.xaml.cs">
      <DependentUpon>LoadingWindow.xaml</DependentUpon>
    </Compile>
    <Compile Include="MainWindow.xaml.cs">
      <DependentUpon>MainWindow.xaml</DependentUpon>
      <SubType>Code</SubType>
    </Compile>
    <Page Include="OperateLog\OperateLogView.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="ProductManager.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="ResultJudge.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="ModbusTCPClient.cs" />
    <Compile Include="ProductManager.xaml.cs">
      <DependentUpon>ProductManager.xaml</DependentUpon>
    </Compile>
    <Compile Include="Properties\AssemblyInfo.cs">
      <SubType>Code</SubType>
    </Compile>
    <Compile Include="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
    <Compile Include="Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
    <EmbeddedResource Include="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
    <None Include="packages.config" />
    <None Include="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <ItemGroup>
    <Resource Include="Image\Currency\logo.png" />
    <Resource Include="Image\Currency\logo_01.png" />
    <Resource Include="Image\Currency\logo_02.png" />
    <Resource Include="Image\Currency\MTV3Dlogo.ico" />
    <Resource Include="Image\Currency\删除.png" />
    <Resource Include="Image\Currency\刷新.png" />
    <Resource Include="Image\Currency\单张抓图.png" />
    <Resource Include="Image\Currency\存储图片.png" />
    <Resource Include="Image\Currency\宣传图.png" />
    <Resource Include="Image\Currency\开始采集.jpg" />
    <Resource Include="Image\Currency\打开文件.png" />
    <Resource Include="Image\Currency\断开.png" />
    <Resource Include="Image\Currency\暂停.png" />
    <Resource Include="Image\Currency\连接.png" />
    <Resource Include="Image\Currency\连续抓图.png" />
    <Resource Include="Image\Currency\采集.png" />
  </ItemGroup>
  <ItemGroup>
    <Resource Include="IDViewer2D.ico" />
  </ItemGroup>
  <ItemGroup>
    <BootstrapperPackage Include=".NETFramework,Version=v4.7.1">
      <Visible>False</Visible>
      <ProductName>Microsoft .NET Framework 4.7.1 %28x86 å’Œ x64%29</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1</ProductName>
      <Install>false</Install>
    </BootstrapperPackage>
  </ItemGroup>
  <ItemGroup>
    <Resource Include="Image\ICON\camera-switch-fill.png" />
    <Resource Include="Image\ICON\folder-2-fill.png" />
    <Resource Include="Image\ICON\folder-open-fill.png" />
    <Resource Include="Image\ICON\import-fill.png" />
    <Resource Include="Image\ICON\link-m.png" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>这台计算机上缺少此项目引用的 NuGet ç¨‹åºåŒ…。使用“NuGet ç¨‹åºåŒ…还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp4.runtime.win.4.10.0.20240616\build\netstandard\OpenCvSharp4.runtime.win.props'))" />
    <Error Condition="!Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets'))" />
  </Target>
  <Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
</Project>
IDViewer_2D/TcpServerManager.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,272 @@
using SmartScanner.ViewModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SmartScanner
{
    public class TcpServerManager : IDisposable
    {
        private TcpListener _listener;
        public static bool _isRunning;
        private CancellationTokenSource _cts;
        private Func<Task<int[]>> _imageProcessingHandler; // å›¾åƒå¤„理委托
        private int _outputIOCount; // è¾“出IO数量
        // å¿ƒè·³é…ç½®
        public bool EnableHeartbeat { get; private set; }
        public string HeartbeatCommand { get; private set; }
        public int HeartbeatInterval { get; private set; }
        // å®¢æˆ·ç«¯åˆ—表管理(如果需要跟踪多个客户端)
        // private ConcurrentDictionary<string, TcpClient> _connectedClients = new ConcurrentDictionary<string, TcpClient>();
        public event Action<string> LogMessage;
        public event Action<string, string> CommandReceived;
        public event Action<string> ClientConnected;
        public event Action<string> ClientDisconnected;
        public TcpServerManager(bool enableHeartbeat, string heartbeatCommand, int heartbeatInterval,
                               Func<Task<int[]>> imageProcessingHandler, int outputIOCount)
        {
            EnableHeartbeat = enableHeartbeat;
            HeartbeatCommand = heartbeatCommand ?? "heartBeat";
            HeartbeatInterval = heartbeatInterval > 0 ? heartbeatInterval : 1000;
            _imageProcessingHandler = imageProcessingHandler ?? throw new ArgumentNullException(nameof(imageProcessingHandler));
            _outputIOCount = outputIOCount > 0 ? outputIOCount : 1;
        }
        /// <summary>
        /// TCP服务器开始侦听
        /// </summary>
        /// <param name="ip">服务器IP地址</param>
        /// <param name="port">服务器端口</param>
        public async Task StartAsync(string ip, int port)
        {
            if (port == -1) return;
            _cts = new CancellationTokenSource();
            _isRunning = true;
            _listener = new TcpListener(IPAddress.Parse(ip), port);
            _listener.Start();
            LogMessage?.Invoke($"TCP服务器已启动,开始侦听 {ip}:{port}");
            LogMessage?.Invoke($"心跳检测: {(EnableHeartbeat ? "已启用" : "已禁用")}");
            if (EnableHeartbeat)
            {
                LogMessage?.Invoke($"心跳指令: {HeartbeatCommand}, é—´éš”: {HeartbeatInterval}ms");
            }
            try
            {
                while (_isRunning)
                {
                    var acceptTask = _listener.AcceptTcpClientAsync();
                    var cancelTask = Task.Delay(-1, _cts.Token);
                    var completedTask = await Task.WhenAny(acceptTask, cancelTask);
                    if (completedTask == cancelTask || _cts.Token.IsCancellationRequested)
                    {
                        break;
                    }
                    var client = await acceptTask;
                    _ = HandleClientAsync(client);
                }
            }
            catch (Exception ex)
            {
                LogMessage?.Invoke($"服务器错误: {ex.Message}");
            }
        }
        private async Task HandleClientAsync(TcpClient client)
        {
            var clientId = client.Client.RemoteEndPoint?.ToString() ?? "未知客户端";
            ClientConnected?.Invoke(clientId);
            LogMessage?.Invoke($"客户端已连接: {clientId}");
            try
            {
                using (client)
                using (var stream = client.GetStream())
                {
                    // ä½¿ç”¨NetworkStream读取
                    byte[] buffer = new byte[4096];
                    MemoryStream ms = new MemoryStream();
                    while (!_cts.IsCancellationRequested && client.Connected)
                    {
                        // æ£€æŸ¥æ•°æ®æ˜¯å¦å¯ç”¨
                        if (!stream.DataAvailable)
                        {
                            await Task.Delay(10, _cts.Token); // çŸ­æš‚等待
                            continue;
                        }
                        // åŒæ­¥è¯»å–方式
                        int bytesRead = stream.Read(buffer, 0, buffer.Length);
                        if (bytesRead == 0) // è¿žæŽ¥å·²å…³é—­
                        {
                            LogMessage?.Invoke($"客户端 {clientId} æ­£å¸¸æ–­å¼€");
                            break;
                        }
                        ms.Write(buffer, 0, bytesRead);
                        // å¤„理完整消息(消息以换行符结尾)
                        string receivedData = Encoding.ASCII.GetString(ms.ToArray());
                        //if (receivedData.Contains('\n'))
                        //{
                        string[] messages = receivedData.Split('\n');
                        for (int i = 0; i < messages.Length - 1; i++) // æœ€åŽä¸€æ®µå¯èƒ½ä¸å®Œæ•´
                        {
                            string message = messages[i].Trim();
                            if (!string.IsNullOrEmpty(message))
                            {
                                await ProcessMessageAsync(message, stream, clientId);
                            }
                        }
                        // ä¿ç•™ä¸å®Œæ•´çš„部分
                        ms.SetLength(0);
                        if (!string.IsNullOrEmpty(messages.Last()))
                        {
                            ms.Write(Encoding.ASCII.GetBytes(messages.Last()), 0, messages.Last().Length);
                        }
                        //}
                    }
                }
            }
            catch (Exception ex)
            {
                LogMessage?.Invoke($"处理客户端 {clientId} æ—¶å‡ºé”™: {ex.Message}");
            }
            finally
            {
                ClientDisconnected?.Invoke(clientId);
                LogMessage?.Invoke($"客户端断开: {clientId}");
            }
        }
        private async Task ProcessMessageAsync(string message, NetworkStream stream, string clientId)
        {
            LogMessage?.Invoke($"来自 {clientId}: {message}");
            Console.WriteLine($"{DateTime.Now:HH:mm:ss:fff}:检测到触发信号{message}");
            EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:检测到触发信号{message}");
            // å¤„理心跳
            if (EnableHeartbeat && message == HeartbeatCommand)
            {
                byte[] ack = Encoding.ASCII.GetBytes($"{HeartbeatCommand}_ACK\n");
                await stream.WriteAsync(ack, 0, ack.Length);
                return;
            }
            // å¤„理业务消息
            var parts = message.Split(',');
            if (parts.Length >= 2 && int.TryParse(parts[0], out var functionCode))
            {
                // å¤„理触发信号 (暂定功能码为3,待后续与客户沟通)
                if (functionCode == 3)
                {
                    await HandleTriggerCommand(stream, clientId);
                }
                else
                {
                    // å…¶ä»–功能码处理
                    var response = $"{functionCode},0,Invalid function code\n";
                    byte[] responseBytes = Encoding.ASCII.GetBytes(response);
                    await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
                }
            }
        }
        private async Task HandleTriggerCommand(NetworkStream stream, string clientId)
        {
            try
            {
                LogMessage?.Invoke($"开始处理触发命令,进行图像采集和推理...");
                // è°ƒç”¨å›¾åƒå¤„理委托
                int[] processingResults = await _imageProcessingHandler()
         .ConfigureAwait(false); // é¿å…æ­»é”
                if (processingResults == null || processingResults.Length != _outputIOCount)
                {
                    throw new InvalidOperationException($"图像处理结果无效,预期{_outputIOCount}个输出,实际得到{processingResults?.Length ?? 0}");
                }
                // æž„建响应消息
                var responseBuilder = new StringBuilder();
                responseBuilder.Append("3,"); // åŠŸèƒ½å·
                responseBuilder.Append(_outputIOCount); // è¾“出IO数
                // æ·»åŠ æ¯ä¸ªç‚¹ä½çš„å¤„ç†ç»“æžœ
                foreach (var result in processingResults)
                {
                    responseBuilder.Append($",{result}");
                }
                responseBuilder.Append("\n"); // ç»“束符
                string response = responseBuilder.ToString();
                LogMessage?.Invoke($"返回结果: {response.Trim()}");
                EnhancedLogViewModel.Instance.AddLog($"{DateTime.Now:HH:mm:ss:fff}:检测完成,返回结果{response.Trim()}");
                // å‘送响应
                byte[] responseBytes = Encoding.ASCII.GetBytes(response);
                await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
            }
            catch (Exception ex)
            {
                LogMessage?.Invoke($"处理触发命令时出错: {ex.Message}");
                // å‘送错误响应
                var errorResponse = $"3,0,Error: {ex.Message}\n";
                byte[] errorBytes = Encoding.ASCII.GetBytes(errorResponse);
                await stream.WriteAsync(errorBytes, 0, errorBytes.Length);
            }
        }
        private async Task StartHeartbeatAsync(StreamWriter writer, CancellationToken token)
        {
            try
            {
                while (!token.IsCancellationRequested)
                {
                    await writer.WriteLineAsync(HeartbeatCommand);
                    await Task.Delay(HeartbeatInterval, token);
                }
            }
            catch (OperationCanceledException)
            {
                // æ­£å¸¸å–消
            }
            catch (Exception ex)
            {
                LogMessage?.Invoke($"心跳任务错误: {ex.Message}");
            }
        }
        public void Stop()
        {
            _isRunning = false;
            _cts?.Cancel();
            try
            {
                _listener?.Stop();
                LogMessage?.Invoke("TCP服务器已停止");
            }
            catch (Exception ex)
            {
                LogMessage?.Invoke($"停止服务器时出错: {ex.Message}");
            }
        }
        public void Dispose()
        {
            Stop();
            _cts?.Dispose();
        }
    }
}
IDViewer_2D/User.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SmartScanner
{
    public class User
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public UserRole Role { get; set; }
    }
    public enum UserRole
    {
        Administrator,
        Technician
    }
    public static class UserManager
    {
        public static List<User> UserList { get; } = new List<User>
    {
        new User { Username = "admin", Password = "123", Role = UserRole.Administrator },
        //new User { Username = "admin2", Password = "admin456", Role = UserRole.Administrator },
        //new User { Username = "tech1", Password = "tech123", Role = UserRole.Technician },
        //new User { Username = "tech2", Password = "tech456", Role = UserRole.Technician }
    };
        public static User CurrentUser { get; private set; }
        public static bool Authenticate(string username, string password)
        {
            var user = UserList.FirstOrDefault(u => u.Username == username && u.Password == password);
            if (user != null)
            {
                CurrentUser = user;
                return true;
            }
            return false;
        }
        public static bool HasAdministratorPrivilege()
        {
            return CurrentUser?.Role == UserRole.Administrator;
        }
    }
}
IDViewer_2D/VersionHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
using System;
using System.IO;
using System.Text;
using System.Windows;
namespace IDViewer_2D
{
    public static class VersionHelper
    {
        public static void ShowVersionInfo()
        {
            try
            {
                string versionFile = "版本说明.txt";
                if (!File.Exists(versionFile))
                {
                    MessageBox.Show("版本说明文件不存在", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
                string[] lines = File.ReadAllLines(versionFile, Encoding.UTF8);
                string latestVersion = "";
                string latestDate = "";
                StringBuilder changes = new StringBuilder();
                // ä»ŽåŽå‘前查找最新版本
                for (int i = lines.Length - 1; i >= 0; i--)
                {
                    string line = lines[i].Trim();
                    // æŸ¥æ‰¾ç‰ˆæœ¬è¡Œ (包含日期和v版本号)
                    if (IsVersionLine(line))
                    {
                        ParseVersionLine(line, ref latestVersion, ref latestDate);
                        // æ”¶é›†æ›´æ–°å†…容
                        for (int j = i + 1; j < lines.Length; j++)
                        {
                            string contentLine = lines[j].Trim();
                            if (string.IsNullOrEmpty(contentLine) || IsVersionLine(contentLine))
                                break;
                            changes.AppendLine(contentLine);
                            if (j - i > 8) break; // æœ€å¤š8行
                        }
                        break;
                    }
                }
                if (string.IsNullOrEmpty(latestVersion))
                {
                    MessageBox.Show("未找到版本信息", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }
                string message = $"当前软件版本: {latestVersion}\n" +
                               $"发布日期: {latestDate}\n\n" +
                               $"最新更新内容:\n{changes}\n" +
                               $"完整版本历史记录请查看版本说明.txt文件";
                MessageBox.Show(message, "软件版本说明", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取版本信息出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private static bool IsVersionLine(string line)
        {
            return !string.IsNullOrEmpty(line) &&
                   line.Contains("v") &&
                   line.Contains(".") &&
                   line.Length > 8 &&
                   char.IsDigit(line[0]);
        }
        private static void ParseVersionLine(string line, ref string version, ref string date)
        {
            string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string part in parts)
            {
                if (part.Contains("v") && part.Contains("."))
                {
                    version = part;
                }
                else if (part.Contains(".") && part.Length >= 8 && char.IsDigit(part[0]))
                {
                    date = part;
                }
            }
        }
    }
}
IDViewer_2D/ViewModel/LogViewModel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using SmartScanner;
namespace SmartScanner.ViewModel
{
    public class LogEntry : INotifyPropertyChanged
    {
        private DateTime _timestamp;
        public DateTime Timestamp
        {
            get => _timestamp;
            set
            {
                _timestamp = value;
                OnPropertyChanged();
            }
        }
        private string _level;
        public string Level
        {
            get => _level;
            set
            {
                _level = value;
                OnPropertyChanged();
            }
        }
        private string _message;
        public string Message
        {
            get => _message;
            set
            {
                _message = value;
                OnPropertyChanged();
            }
        }
        private Brush _foreground;
        public Brush Foreground
        {
            get => _foreground;
            set
            {
                _foreground = value;
                OnPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public class EnhancedLogViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<LogEntry> LogEntries { get; } = new ObservableCollection<LogEntry>();
        private static readonly Lazy<EnhancedLogViewModel> _instance =
       new Lazy<EnhancedLogViewModel>(() => new EnhancedLogViewModel());
        public static EnhancedLogViewModel Instance => _instance.Value;
        // æ—¥å¿—自动保存服务
        private LogAutoSaveService _logAutoSaveService;
        private EnhancedLogViewModel()
        {
            // åˆå§‹åŒ–日志自动保存服务
            _logAutoSaveService = new LogAutoSaveService(LogEntries);
        }
        // æ·»åР坹ScrollViewer的引用
        private ScrollViewer _logScrollViewer;
        public ScrollViewer LogScrollViewer
        {
            get => _logScrollViewer;
            set
            {
                _logScrollViewer = value;
                OnPropertyChanged();
            }
        }
        public void AddLog(string message, string level = "INFO")
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                var entry = new LogEntry
                {
                    Timestamp = DateTime.Now,
                    Level = level,
                    Message = message,
                    Foreground = GetLevelColor(level)
                };
                LogEntries.Add(entry);
                // é™åˆ¶æ—¥å¿—数量
                if (LogEntries.Count > 500)
                {
                    LogEntries.RemoveAt(0);
                }
                // é€šçŸ¥è‡ªåŠ¨ä¿å­˜æœåŠ¡æœ‰æ–°æ—¥å¿—ï¼Œä¼ é€’LogEntry对象
                _logAutoSaveService?.LogAdded(entry);
                // æ»šåŠ¨åˆ°åº•éƒ¨
                ScrollToBottom();
            });
        }
        /// <summary>
        /// æ‰‹åŠ¨ä¿å­˜å½“å‰æ—¥å¿—
        /// </summary>
        public void SaveLogs()
        {
            _logAutoSaveService?.ForceSave();
        }
        /// <summary>
        /// åœæ­¢æ—¥å¿—自动保存服务
        /// </summary>
        public void StopAutoSaveService()
        {
            _logAutoSaveService?.Stop();
            _logAutoSaveService = null;
        }
        /// <summary>
        /// èŽ·å–è‡ªåŠ¨ä¿å­˜æœåŠ¡çŠ¶æ€
        /// </summary>
        public string GetAutoSaveStatus()
        {
            return _logAutoSaveService?.GetStatus() ?? "自动保存服务未运行";
        }
        private void ScrollToBottom()
        {
            if (LogScrollViewer != null)
            {
                LogScrollViewer.ScrollToEnd();
            }
        }
        private Brush GetLevelColor(string level)
        {
            switch (level)
            {
                case "ERROR":
                    return Brushes.Red;
                case "WARN":
                    return Brushes.Orange;
                case "DEBUG":
                    return Brushes.Blue;
                default:
                    return Brushes.Black;
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
IDViewer_2D/packages.config
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Extended.Wpf.Toolkit" version="4.7.25104.5739" targetFramework="net471" />
  <package id="Microsoft.IO.RecyclableMemoryStream" version="3.0.1" targetFramework="net471" />
  <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net471" />
  <package id="NETStandard.Library" version="2.0.0" targetFramework="net471" />
  <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" />
  <package id="OpenCvSharp4" version="4.10.0.20241108" targetFramework="net461" />
  <package id="OpenCvSharp4.Extensions" version="4.10.0.20241108" targetFramework="net461" />
  <package id="OpenCvSharp4.runtime.win" version="4.10.0.20240616" targetFramework="net471" />
  <package id="OpenCvSharp4.WpfExtensions" version="4.5.1.20210210" targetFramework="net471" />
  <package id="Syncfusion.Compression.Net.Core" version="29.1.37" targetFramework="net471" />
  <package id="Syncfusion.Licensing" version="29.1.37" targetFramework="net471" />
  <package id="Syncfusion.OfficeChart.Net.Core" version="29.1.37" targetFramework="net471" />
  <package id="Syncfusion.Presentation.Net.Core" version="29.1.37" targetFramework="net471" />
  <package id="System.Buffers" version="4.5.1" targetFramework="net471" />
  <package id="System.ComponentModel.Annotations" version="5.0.0" targetFramework="net471" />
  <package id="System.Drawing.Common" version="8.0.0" targetFramework="net461" requireReinstallation="true" />
  <package id="System.Memory" version="4.5.5" targetFramework="net471" />
  <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net471" />
  <package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net471" />
  <package id="System.Security.Cryptography.Xml" version="8.0.2" targetFramework="net471" />
</packages>
IDViewer_2D/Èí¼þÐèÇ󹿏ñ˵Ã÷Êé.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,339 @@
# IDViewer_2D è½¯ä»¶éœ€æ±‚规格说明书
## 1. æ¦‚è¿°
IDViewer_2D æ˜¯ä¸€æ¬¾ä¸“业的二维视觉检测软件,主要用于工业场景中的条码/二维码识别、图像处理、设备管理和数据通信。软件支持多设备连接、实时检测、结果判定和数据导出等功能。
## 2. ç³»ç»Ÿæž¶æž„
### 2.1 æŠ€æœ¯æž¶æž„
- **开发语言**: C#
- **UI框架**: WPF (Windows Presentation Foundation)
- **SDK依赖**: IDViewerCSDK.dll (底层视觉算法库)
- **图像处理**: OpenCVSharp
- **通信协议**: Modbus TCP、TCP/IP、UDP
### 2.2 è½¯ä»¶æ¨¡å—
1. è®¾å¤‡ç®¡ç†æ¨¡å—
2. å›¾åƒå¤„理模块
3. æ£€æµ‹æ–¹æ¡ˆæ¨¡å—
4. é€šä¿¡é…ç½®æ¨¡å—
5. æ•°æ®å­˜å‚¨æ¨¡å—
6. ç”¨æˆ·æƒé™æ¨¡å—
7. æ—¥å¿—管理模块
## 3. åŠŸèƒ½éœ€æ±‚
### 3.1 ä¸»ç•Œé¢åŠŸèƒ½
#### 3.1.1 è®¾å¤‡è¿žæŽ¥ç®¡ç†
- [x] **设备扫描**: è‡ªåŠ¨å‘çŽ°ç½‘ç»œä¸­çš„è§†è§‰è®¾å¤‡
- [x] **设备列表**: æ˜¾ç¤ºå·²å‘现设备的IP、型号、固件版本等信息
- [x] **连接状态**: å®žæ—¶æ˜¾ç¤ºè®¾å¤‡è¿žæŽ¥çŠ¶æ€ï¼ˆå·²è¿žæŽ¥/未连接)
- [x] **刷新连接**: æ‰‹åŠ¨åˆ·æ–°è®¾å¤‡åˆ—è¡¨å¹¶é‡æ–°è¿žæŽ¥
- [x] **设备信息**: æ˜¾ç¤ºé€‰ä¸­è®¾å¤‡çš„详细信息(IP地址、子网掩码、网关、固件版本、设备型号、设备名称)
#### 3.1.2 å·¥å…·æ åŠŸèƒ½
- [x] **刷新设备**: åˆ·æ–°è®¾å¤‡åˆ—表并重新连接
- [x] **设备管理**: æ‰“开设备映射配置界面
- [x] **检测方案**: æ‰“开检测方案配置界面
- [x] **存图设置**: æ‰“开图像存储设置界面
- [x] **单点输出**: åˆ‡æ¢å•点/多点输出模式
- [x] **通讯测试**: æµ‹è¯•设备通信功能
- [x] **手动采集**: æ‰‹åŠ¨è§¦å‘å›¾åƒé‡‡é›†
- [x] **界面重置**: é‡ç½®ç•Œé¢åˆ°åˆå§‹çŠ¶æ€
- [x] **查看检测报告**: æŸ¥çœ‹åŽ†å²æ£€æµ‹ç»“æžœæŠ¥å‘Š
- [x] **查看日志**: æŸ¥çœ‹ç³»ç»Ÿæ“ä½œæ—¥å¿—
- [x] **一键重启**: é‡å¯åº”用程序
#### 3.1.3 ç»“果显示
- [x] **多通道显示**: æ”¯æŒæœ€å¤š24个检测通道同时显示
- [x] **实时状态**: æ˜¾ç¤ºå½“前检测状态和通信状态
- [x] **结果标识**: ä½¿ç”¨é¢œè‰²åŒºåˆ†æ£€æµ‹ç»“果(OK/NG)
- [x] **设备别名**: æ˜¾ç¤ºæ¯ä¸ªé€šé“对应的设备别名
- [x] **点击交互**: æ”¯æŒç‚¹å‡»ç»“果区域查看详细结果
#### 3.1.4 æ—¥å¿—显示
- [x] **实时日志**: å®žæ—¶æ˜¾ç¤ºæ£€æµ‹æ—¥å¿—信息
- [x] **日志级别**: æ”¯æŒä¸åŒçº§åˆ«çš„æ—¥å¿—显示
- [x] **时间戳**: æ¯æ¡æ—¥å¿—都带有时间戳
- [x] **自动滚动**: æ—¥å¿—自动滚动到最新内容
### 3.2 è®¾å¤‡ç®¡ç†æ¨¡å—
#### 3.2.1 è®¾å¤‡æ˜ å°„配置
- [x] **连接顺序**: é…ç½®è®¾å¤‡çš„连接顺序
- [x] **IP映射**: é…ç½®è®¾å¤‡IP与显示位置的映射关系
- [x] **添加映射**: æ·»åŠ æ–°çš„è®¾å¤‡æ˜ å°„
- [x] **删除映射**: åˆ é™¤çŽ°æœ‰è®¾å¤‡æ˜ å°„
- [x] **保存配置**: ä¿å­˜æ˜ å°„配置到文件
- [x] **加载配置**: ä»Žæ–‡ä»¶åŠ è½½æ˜ å°„é…ç½®
#### 3.2.2 è®¾å¤‡æŽ§åˆ¶
- [x] **设备打开/关闭**: æŽ§åˆ¶è®¾å¤‡çš„开启和关闭
- [x] **运行模式**: å¯åЍ/停止设备运行
- [x] **调试模式**: è¿›å…¥è®¾å¤‡è°ƒè¯•模式
- [x] **图像采集**: æ‰‹åŠ¨é‡‡é›†å•å¸§å›¾åƒ
- [x] **参数设置**: è®¾ç½®è®¾å¤‡å‚数(曝光、增益、伽马等)
- [x] **固件信息**: èŽ·å–è®¾å¤‡å›ºä»¶ç‰ˆæœ¬ä¿¡æ¯
### 3.3 æ£€æµ‹æ–¹æ¡ˆæ¨¡å—
#### 3.3.1 æ–¹æ¡ˆé…ç½®
- [x] **方案选择**: é€‰æ‹©æ£€æµ‹æ–¹æ¡ˆæ–‡ä»¶
- [x] **模型选择**: é€‰æ‹©æŽ¨ç†æ¨¡åž‹æ–‡ä»¶
- [x] **工程导出**: å¯¼å‡ºå·¥ç¨‹é…ç½®æ–‡ä»¶
- [x] **工程加载**: åŠ è½½å·²æœ‰å·¥ç¨‹é…ç½®
- [x] **模型刷新**: åˆ·æ–°å¯ç”¨æ¨¡åž‹åˆ—表
#### 3.3.2 æ£€æµ‹å‚æ•°
- [x] **目标数量**: è®¾ç½®æ£€æµ‹ç›®æ ‡æ•°é‡
- [x] **得分阈值**: è®¾ç½®æ£€æµ‹å¾—分阈值
- [x] **目标类型**: é…ç½®æ£€æµ‹çš„目标类型
- [x] **条件设置**: è®¾ç½®æ£€æµ‹æ¡ä»¶è§„则
- [x] **多检测点**: æ”¯æŒå¤šä¸ªæ£€æµ‹ç‚¹é…ç½®
#### 3.3.3 ROI管理
- [x] **ROI添加**: æ·»åŠ æ£€æµ‹åŒºåŸŸ(ROI)
- [x] **ROI删除**: åˆ é™¤æŒ‡å®šROI
- [x] **ROI修改**: ä¿®æ”¹ROI位置和大小
- [x] **ROI清空**: æ¸…除所有ROI
- [x] **码制管理**: ç®¡ç†æ”¯æŒçš„æ¡ç ç±»åž‹
### 3.4 å›¾åƒå¤„理模块
#### 3.4.1 å›¾åƒé‡‡é›†
- [x] **自动采集**: æ”¯æŒè‡ªåŠ¨è¿žç»­é‡‡é›†
- [x] **手动采集**: æ”¯æŒæ‰‹åŠ¨å•å¸§é‡‡é›†
- [x] **触发模式**: æ”¯æŒå¤šç§è§¦å‘模式(软触发、硬触发、网络触发等)
- [x] **图像预览**: å®žæ—¶å›¾åƒé¢„览显示
#### 3.4.2 å›¾åƒå‚æ•°
- [x] **曝光设置**: è°ƒæ•´å›¾åƒæ›å…‰å‚æ•°
- [x] **增益设置**: è°ƒæ•´å›¾åƒå¢žç›Šå‚æ•°
- [x] **伽马设置**: è°ƒæ•´å›¾åƒä¼½é©¬å€¼
- [x] **自动曝光**: å¯ç”¨/禁用自动曝光
- [x] **自动增益**: å¯ç”¨/禁用自动增益
- [x] **光源控制**: æŽ§åˆ¶ç…§æ˜Žå…‰æºäº®åº¦
#### 3.4.3 å›¾åƒæ˜¾ç¤º
- [x] **多图浏览**: æ”¯æŒå¤šå¼ å›¾åƒæµè§ˆ
- [x] **图像缩放**: æ”¯æŒå›¾åƒç¼©æ”¾æŸ¥çœ‹
- [x] **上一张/下一张**: å›¾åƒæµè§ˆå¯¼èˆª
- [x] **结果渲染**: åœ¨å›¾åƒä¸Šæ¸²æŸ“检测结果
### 3.5 é€šä¿¡é…ç½®æ¨¡å—
#### 3.5.1 Modbus TCP配置
- [x] **服务器IP**: è®¾ç½®Modbus服务器IP地址
- [x] **端口设置**: è®¾ç½®é€šä¿¡ç«¯å£ï¼ˆé»˜è®¤502)
- [x] **连接控制**: Modbus连接建立和断开
- [x] **日志显示**: æ˜¾ç¤ºModbus通信日志
- [x] **清空日志**: æ¸…除通信日志
#### 3.5.2 TCP/IP服务器配置
- [x] **IP绑定**: è®¾ç½®æœåŠ¡å™¨ç»‘å®šçš„IP地址
- [x] **端口设置**: è®¾ç½®ç›‘听端口(默认5011)
- [x] **心跳检测**: å¯ç”¨/禁用心跳检测功能
- [x] **心跳指令**: è®¾ç½®å¿ƒè·³æŒ‡ä»¤å†…容
- [x] **心跳周期**: è®¾ç½®å¿ƒè·³æ£€æµ‹å‘¨æœŸ
- [x] **服务器控制**: å¯åЍ/停止TCP服务器
- [x] **IP刷新**: åˆ·æ–°å¯ç”¨IP地址列表
#### 3.5.3 é€šä¿¡åè®®æ”¯æŒ
- [x] **Modbus TCP**: æ”¯æŒModbus TCP协议
- [x] **TCP/IP**: æ”¯æŒæ ‡å‡†TCP/IP通信
- [x] **UDP**: æ”¯æŒUDP协议通信
- [x] **串口通信**: æ”¯æŒä¸²å£é€šä¿¡
- [x] **EtherNet/IP**: æ”¯æŒEtherNet/IP协议
- [x] **Profinet**: æ”¯æŒProfinet协议
- [x] **FINS**: æ”¯æŒFINS协议
- [x] **MC协议**: æ”¯æŒä¸‰è±MC协议
- [x] **EtherCAT**: æ”¯æŒEtherCAT协议
### 3.6 æ•°æ®å­˜å‚¨æ¨¡å—
#### 3.6.1 å­˜å‚¨è®¾ç½®
- [x] **存储路径**: è®¾ç½®æ•°æ®å­˜å‚¨è·¯å¾„
- [x] **图像格式**: é€‰æ‹©å›¾åƒå­˜å‚¨æ ¼å¼ï¼ˆBMP/JPG/PNG)
- [x] **压缩比率**: è®¾ç½®å›¾åƒåŽ‹ç¼©æ¯”çŽ‡ï¼ˆ0-10)
- [x] **启用存储**: å¯ç”¨/禁用图像存储功能
#### 3.6.2 å­˜å‚¨ç®¡ç†
- [x] **定期清理**: è®¾ç½®å®šæœŸæ¸…理图像功能
- [x] **清理周期**: è®¾ç½®å›¾åƒä¿ç•™å¤©æ•°ï¼ˆ1-200000天)
- [x] **空间预警**: å¯ç”¨å­˜å‚¨ç©ºé—´é¢„警功能
- [x] **预警阈值**: è®¾ç½®ç©ºé—´é¢„警百分比(10%-90%)
- [x] **存储状态**: æ˜¾ç¤ºå½“前存储状态信息
#### 3.6.3 æ•°æ®å¯¼å‡º
- [x] **Excel导出**: æ”¯æŒæ£€æµ‹ç»“果导出到Excel
- [x] **报告生成**: ç”Ÿæˆæ£€æµ‹æŠ¥å‘Šæ–‡æ¡£
- [x] **数据格式**: æ”¯æŒå¤šç§æ•°æ®å¯¼å‡ºæ ¼å¼
- [x] **批量导出**: æ”¯æŒæ‰¹é‡æ•°æ®å¯¼å‡º
### 3.7 ç”¨æˆ·æƒé™æ¨¡å—
#### 3.7.1 ç”¨æˆ·ç™»å½•
- [x] **用户认证**: æ”¯æŒç”¨æˆ·ç™»å½•认证
- [x] **用户管理**: ç®¡ç†ç”¨æˆ·è´¦æˆ·åˆ—表
- [x] **密码保护**: æ”¯æŒå¯†ç è¾“入保护
- [x] **权限控制**: ä¸åŒç”¨æˆ·æƒé™æŽ§åˆ¶
#### 3.7.2 æ“ä½œæƒé™
- [x] **配置权限**: æŽ§åˆ¶é…ç½®ä¿®æ”¹æƒé™
- [x] **设备控制权限**: æŽ§åˆ¶è®¾å¤‡æ“ä½œæƒé™
- [x] **数据查看权限**: æŽ§åˆ¶æ•°æ®æŸ¥çœ‹æƒé™
- [x] **系统管理权限**: æŽ§åˆ¶ç³»ç»Ÿç®¡ç†åŠŸèƒ½
### 3.8 æ—¥å¿—管理模块
#### 3.8.1 ç³»ç»Ÿæ—¥å¿—
- [x] **操作日志**: è®°å½•用户操作日志
- [x] **错误日志**: è®°å½•系统错误信息
- [x] **通信日志**: è®°å½•通信数据日志
- [x] **检测日志**: è®°å½•检测结果日志
#### 3.8.2 æ—¥å¿—功能
- [x] **实时显示**: å®žæ—¶æ˜¾ç¤ºæ—¥å¿—内容
- [x] **日志过滤**: æ”¯æŒæŒ‰çº§åˆ«è¿‡æ»¤æ—¥å¿—
- [x] **日志导出**: æ”¯æŒæ—¥å¿—导出功能
- [x] **日志清理**: æ”¯æŒæ—¥å¿—自动清理
## 4. éžåŠŸèƒ½éœ€æ±‚
### 4.1 æ€§èƒ½éœ€æ±‚
- [x] **实时性**: æ£€æµ‹å“åº”æ—¶é—´ < 100ms
- [x] **稳定性**: 7×24小时连续运行
- [x] **并发性**: æ”¯æŒå¤šè®¾å¤‡å¹¶å‘检测
- [x] **资源占用**: CPU占用率 < 70%,内存占用 < 2GB
### 4.2 å¯é æ€§éœ€æ±‚
- [x] **异常处理**: å®Œå–„的异常处理机制
- [x] **自动重连**: ç½‘络异常自动重连
- [x] **数据恢复**: å¼‚常断电数据恢复
- [x] **日志追踪**: å®Œæ•´çš„æ“ä½œæ—¥å¿—追踪
### 4.3 å¯ç”¨æ€§éœ€æ±‚
- [x] **用户界面**: ç›´è§‚易用的图形界面
- [x] **操作流程**: ç®€æ´æ˜Žäº†çš„æ“ä½œæµç¨‹
- [x] **帮助文档**: å®Œå–„的帮助文档支持
- [x] **多语言**: æ”¯æŒä¸­è‹±æ–‡ç•Œé¢
### 4.4 å®‰å…¨æ€§éœ€æ±‚
- [x] **数据安全**: æ£€æµ‹æ•°æ®å®‰å…¨å­˜å‚¨
- [x] **访问控制**: ä¸¥æ ¼çš„访问权限控制
- [x] **通信加密**: æ•æ„Ÿæ•°æ®é€šä¿¡åР坆
- [x] **操作审计**: æ‰€æœ‰æ“ä½œéƒ½æœ‰å®¡è®¡æ—¥å¿—
### 4.5 å…¼å®¹æ€§éœ€æ±‚
- [x] **操作系统**: æ”¯æŒWindows 7/10/11
- [x] **硬件兼容**: æ”¯æŒå¤šç§è§†è§‰è®¾å¤‡
- [x] **网络兼容**: æ”¯æŒå¤šç§ç½‘络协议
- [x] **数据兼容**: æ”¯æŒå¤šç§æ•°æ®æ ¼å¼
## 5. æŽ¥å£éœ€æ±‚
### 5.1 ç¡¬ä»¶æŽ¥å£
- [x] **相机接口**: æ”¯æŒGigE Vision、USB3.0相机
- [x] **IO接口**: æ”¯æŒæ•°å­—输入输出控制
- [x] **串口接口**: æ”¯æŒRS232/RS485串口通信
- [x] **网络接口**: æ”¯æŒåƒå…†ä»¥å¤ªç½‘接口
### 5.2 è½¯ä»¶æŽ¥å£
- [x] **SDK接口**: IDViewerCSDK.dll æŽ¥å£è°ƒç”¨
- [x] **数据库接口**: æ”¯æŒSQLite数据库
- [x] **文件接口**: æ”¯æŒæ–‡ä»¶è¯»å†™æ“ä½œ
- [x] **网络接口**: æ”¯æŒSocket通信
### 5.3 é€šä¿¡æŽ¥å£
- [x] **Modbus TCP**: æ”¯æŒModbus TCP客户端/服务器
- [x] **TCP/IP**: æ”¯æŒæ ‡å‡†TCP/IP通信
- [x] **UDP**: æ”¯æŒUDP数据报通信
- [x] **HTTP**: æ”¯æŒHTTP协议通信
- [x] **FTP**: æ”¯æŒFTP文件传输
## 6. æ•°æ®éœ€æ±‚
### 6.1 æ•°æ®å­˜å‚¨
- [x] **配置数据**: XML格式配置文件
- [x] **图像数据**: BMP/JPG/PNG格式图像文件
- [x] **结果数据**: Excel/CSV格式结果文件
- [x] **日志数据**: æ–‡æœ¬æ ¼å¼æ—¥å¿—文件
### 6.2 æ•°æ®å¤„理
- [x] **数据解析**: è§£æžå„种格式的数据
- [x] **数据转换**: æ•°æ®æ ¼å¼è½¬æ¢å¤„理
- [x] **数据校验**: æ•°æ®å®Œæ•´æ€§æ ¡éªŒ
- [x] **数据备份**: è‡ªåŠ¨æ•°æ®å¤‡ä»½
### 6.3 æ•°æ®å±•示
- [x] **实时显示**: å®žæ—¶æ•°æ®å¯è§†åŒ–显示
- [x] **历史查询**: åŽ†å²æ•°æ®æŸ¥è¯¢æ˜¾ç¤º
- [x] **统计报表**: æ•°æ®ç»Ÿè®¡æŠ¥è¡¨ç”Ÿæˆ
- [x] **趋势分析**: æ•°æ®è¶‹åŠ¿åˆ†æžæ˜¾ç¤º
## 7. çº¦æŸæ¡ä»¶
### 7.1 æŠ€æœ¯çº¦æŸ
- [x] **开发语言**: å¿…须使用C#开发
- [x] **运行环境**: å¿…须支持.NET Framework 4.5+
- [x] **第三方库**: ä¾èµ–IDViewerCSDK.dll库
- [x] **界面框架**: ä½¿ç”¨WPF框架开发
### 7.2 ä¸šåŠ¡çº¦æŸ
- [x] **实时性要求**: å¿…须满足实时检测要求
- [x] **准确性要求**: æ£€æµ‹å‡†ç¡®çއ > 99.9%
- [x] **稳定性要求**: æ— æ•…障运行时间 > 1000小时
### 7.3 èµ„源约束
- [x] **硬件资源**: éœ€è¦è¶³å¤Ÿçš„计算资源
- [x] **存储资源**: éœ€è¦è¶³å¤Ÿçš„存储空间
- [x] **网络资源**: éœ€è¦ç¨³å®šçš„网络环境
## 8. è´¨é‡å±žæ€§
### 8.1 å¯ç»´æŠ¤æ€§
- [x] **模块化设计**: ç³»ç»Ÿé‡‡ç”¨æ¨¡å—化设计
- [x] **代码规范**: éµå¾ªç¼–码规范和标准
- [x] **文档完整**: æä¾›å®Œæ•´çš„æŠ€æœ¯æ–‡æ¡£
- [x] **易于扩展**: ç³»ç»Ÿæ˜“于功能扩展
### 8.2 å¯æµ‹è¯•性
- [x] **单元测试**: æ”¯æŒå•元测试
- [x] **集成测试**: æ”¯æŒé›†æˆæµ‹è¯•
- [x] **系统测试**: æ”¯æŒç³»ç»Ÿæµ‹è¯•
- [x] **自动化测试**: æ”¯æŒè‡ªåŠ¨åŒ–æµ‹è¯•
### 8.3 å¯ç§»æ¤æ€§
- [x] **环境隔离**: è¿è¡ŒçŽ¯å¢ƒä¾èµ–éš”ç¦»
- [x] **配置管理**: ç»Ÿä¸€çš„配置管理
- [x] **部署简单**: ç®€å•的部署过程
- [x] **跨平台**: æ”¯æŒWindows平台
## 9. é™„录
### 9.1 æœ¯è¯­è¡¨
- **ROI**: Region of Interest,感兴趣区域
- **Modbus**: å·¥ä¸šé€šä¿¡åè®®
- **TCP/IP**: ä¼ è¾“控制协议/网际协议
- **GigE Vision**: åƒå…†ä»¥å¤ªç½‘视觉标准
- **SDK**: Software Development Kit,软件开发工具包
### 9.2 å‚考资料
- IDViewerCSDK开发文档
- Modbus协议规范
- TCP/IP协议详解
- WPF开发指南
- OpenCV图像处理库文档
### 9.3 ç‰ˆæœ¬åŽ†å²
| ç‰ˆæœ¬å· | ä¿®è®¢æ—¥æœŸ | ä¿®è®¢å†…容 | ä¿®è®¢äºº |
|--------|----------|----------|--------|
| v1.0 | 2024-03-20 | åˆå§‹ç‰ˆæœ¬åˆ›å»º | ç³»ç»Ÿåˆ†æžå¸ˆ |
| v1.1 | 2024-03-21 | å®Œå–„功能描述 | ç³»ç»Ÿåˆ†æžå¸ˆ |
---
**文档状态**: âœ… å·²å®Œæˆ
**评审状态**: â³ å¾…评审
**批准状态**: â³ å¾…批准
SmartScanner.sln
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.35425.106
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartScanner", "IDViewer_2D\SmartScanner.csproj", "{D1C98439-DD40-43CD-BC99-899868FD2EDF}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Debug|x64 = Debug|x64
        Debug|x86 = Debug|x86
        Release|Any CPU = Release|Any CPU
        Release|x64 = Release|x64
        Release|x86 = Release|x86
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|x64.ActiveCfg = Debug|x64
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|x64.Build.0 = Debug|x64
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|x86.ActiveCfg = Debug|x86
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Debug|x86.Build.0 = Debug|x86
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|Any CPU.Build.0 = Release|Any CPU
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|x64.ActiveCfg = Release|x64
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|x64.Build.0 = Release|x64
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|x86.ActiveCfg = Release|x86
        {D1C98439-DD40-43CD-BC99-899868FD2EDF}.Release|x86.Build.0 = Release|x86
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
        SolutionGuid = {86CD00DD-4539-43C7-819E-DACFFA267AF1}
    EndGlobalSection
EndGlobal
TCPͨѶÊý¾Ý¸ñʽ˵Ã÷.xlsx
Binary files differ
°²×°½Å±¾.iss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "SmartScanner"
#define MyAppVersion "1.26.1"  ; æ›´æ–°åŽéœ€è¦å…¨å±€æ›´æ–°ç‰ˆæœ¬å·
#define MyAppPublisher "SHLANBAO"
#define MyAppExeName "SmartScanner.exe"
#define MyAppAssocName MyAppName + " v1.26.1"
#define MyAppAssocExt ".myp"
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{AA622081-8085-48FE-A317-86D82708B190}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
ChangesAssociations=yes
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=C:\Users\C3032\Desktop\安装包
OutputBaseFilename=SmartScanner v1.26.1
SetupIconFile=D:\00 Code\01 ID Viewer\IDViewer_2D-1 v26 API\IDViewer_2D\IDViewer2D.ico
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "chinese"; MessagesFile: "compiler:Languages\Chinese.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "D:\00 Code\01 ID Viewer\IDViewer_2D-1 v26 API\IDViewer_2D\bin\x64\Debug\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "D:\00 Code\01 ID Viewer\IDViewer_2D-1 v26 API\IDViewer_2D\bin\x64\Debug\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Registry]
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".myp"; ValueData: ""
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\IDViewer2D.ico"
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
°æ±¾ËµÃ÷.txt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
2025.5.8 v1.0.7
1.新增连接状态界面进度显示
2025.5.28 v1.0.8
1.修复设备断开后Log连接显示问题;
2.新增连接状态检查定时器,每3s自动检查连接状态
2025.5.28 v1.0.9
1.多点IO输出固定写死20点修改为自适应连接数量
2025.6.10 v1.0.9
1.新增图像定期删除功能
2.新增自选图像保存格式(BMP、JGP、PNG)和压缩比率,其中BMP格式的图像不允许压缩
3.新增图像保存路径自由选择
4.新增存储空间不足自动弹窗报警
2025.6.13 v1.1.0
1.新增检测日志显示,完整的显示检测过程和结果,并对日志信息进行分级显示
2025.6.18 v1.1.1
1.新增“CPU”/“GPU”推理手动切换
2025.6.20 v1.1.1
1.新增权限管控功能,参数调节需登录管理员账户
2025.6.27 v1.1.2
1.新增操作日志记录和显示,记录修改日志、操作人员、操作类型、目标设备和操作详情
2025.7.11 v1.1.3
1.新增检测结果记录保存至Excel表,保存格式为“二维码+检测点位+检测结果+检测时间+操作人员
2.主界面新增”当前检测状态“和”当前通讯状态“两种状态显示
3.取消检测时”ModBus未连接“弹窗,改为通讯模块状态栏显示
2025.7.11 v1.1.4
1.新增一键重启功能
2025.7.30 v1.1.5
1.界面结果显示框体新增按钮功能,点击后可显示当前框体对应的图像
2.单点/多点输出选择控件样式重写,重写为左右滑动的复选按钮样式
3.单点/多点输出自动保存
2025.8.8 v1.1.6
1.SDK更新
2025.8.20 v1.1.8
1.新增TCP/IP通讯功能,软件作为服务端
2.开启/关闭心跳信号
3.心跳信号周期和指令可设置
2025.8.20 v1.1.9
1.检测方案中每个点位可检测的目标增加到4个
2025.8.25 v1.2.0
1.新增ng图像自动保存功能
2025.8.30 v1.2.1
1.新增工程方案文件,将检测方案和模型打包为完整的工程文件
2.工程文件支持导出/导入
3.修复插入移动存储设备后授权失效问题
2025.9.5 v1.2.2
1.模型格式修改为lb加密格式
2025.9.20 v1.2.3
1.新增软件内版本说明,记录每个版本软件修改记录,可通过软件内按钮查询
2.IO触发自锁,规定时间内只能触发一次,信号保持时间可自定义
3.修复连接TCP后无法手动触发的问题
2025.10.21 v1.2.4
1.优化Modbus异常断开后处理措施,新增断开重连机制
2.异常断开后尝试重连5次,若5次连接失败则弹窗警报
2025.10.24 v1.2.5
1.工程文件操作流程简化
2.检测方案文件固定保存在DetectionPlan文件夹中
3.工程文件固定保存在Project文件夹中
2025.10.30 v1.2.6
1.新增检测日志自动导出功能,自动保存至D:02 LBLog文件夹中
2.日志默认存储48小时,48小时以后自动清除
Èí¼þ¹¦ÄÜÁбí.xlsx
Binary files differ
¼¯³ÉÏà»úÈí¼þ¹¦ÄÜÁбí.xlsx
Binary files differ