2020 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			VB.net
		
	
	
	
	
	
			
		
		
	
	
			2020 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			VB.net
		
	
	
	
	
	
| Imports System.IO
 | ||
| Imports System.Net
 | ||
| Imports System.Runtime.InteropServices
 | ||
| Imports System.Security.AccessControl
 | ||
| Imports System.Security.Principal
 | ||
| Imports Microsoft.Win32
 | ||
| Imports System.Text
 | ||
| Imports System.Threading
 | ||
| Imports System.Net.NetworkInformation
 | ||
| Imports System.Net.Http
 | ||
| Imports System.Web.Script.Serialization
 | ||
| Imports System.Reflection
 | ||
| 
 | ||
| Public Class Form1
 | ||
|     Dim 是否断网 As Boolean = False
 | ||
|     Dim 全局变量_BIOS识别码 As String = ""
 | ||
|     Dim 全局变量_异常密码 As String = "009988"
 | ||
|     'api接口地址 ' 
 | ||
|     Dim ApiEndPoint As String = "http://api.systemcd.org/api/v1"
 | ||
|     Dim 全局变量_id As String = ""
 | ||
|     Dim 全局变量_心跳时间 As String = ""
 | ||
|     Dim 全局变量_关键字心跳时间 As String = ""
 | ||
|     Dim 全局变量_进程限制 As Integer = 2
 | ||
|     Dim 全局变量_应用限制 As Integer = 2
 | ||
|     Dim 全局变量_关键字采集 As Integer = 2 '关键字采集 1开启 2-关闭 默认关闭'
 | ||
|     Dim 全局变量_拦截记录间隔 As Double = 1 '进程拦截记录间隔(小时)'
 | ||
|     Dim 全局变量_采集的文本 As List(Of KeywordItemReq) = New List(Of KeywordItemReq) '已采集的违规文本'
 | ||
|     Dim 全局变量_程序版本 As String = ""
 | ||
|     '忽略的特殊字符'
 | ||
|     Dim ignoreChars As New HashSet(Of Char)({" ", vbCrLf, ",", "。", ":", "【", "】", "?", ";", ",", ".", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "`", "~", "[", "]", "{", "}", "\", "|", ";", ":", "’", "‘", "'", """", "<", ">", "/", "?"})
 | ||
| 
 | ||
|     Dim 全局变量_已拦截进程 As Dictionary(Of String, DateTime) = New Dictionary(Of String, Date)
 | ||
|     Public 全局变量_关键字 As KeywordItem = New KeywordItem
 | ||
| 
 | ||
|     'http请求对象'
 | ||
|     Dim client As New HttpClient()
 | ||
|     '序列化对象'
 | ||
|     Dim serializer As New JavaScriptSerializer()
 | ||
| 
 | ||
|     Private Const HWND_BROADCAST As Integer = &HFFFF
 | ||
|     Private Const WM_SETTINGCHANGE As Integer = &H1A
 | ||
|     Private Const SMTO_NORMAL As UInteger = &H0
 | ||
| 
 | ||
|     Private promptLoopTask As Task = Nothing
 | ||
|     Private promptLoopStarted As Boolean = False
 | ||
|     Private promptLoopLock As New Object() ' 用于线程同步
 | ||
|     Private keywordLoopLock As New Object() '关键词task线程同步'
 | ||
| 
 | ||
|     '允许进程列表'
 | ||
|     Private allowedProcesses As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
 | ||
|     '组策略允许列表'
 | ||
|     Private allGroupApplication As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
 | ||
| 
 | ||
|     '用于存储定时任务的 Task
 | ||
|     Private monitorTask As Task
 | ||
|     '关键词定时同步 Task'
 | ||
|     Private keywordMonitorTask As Task
 | ||
|     '用于控制定时任务的取消'
 | ||
|     Private monitorCancellationTokenSource As New CancellationTokenSource()
 | ||
|     '关键字控制定时任务取消'
 | ||
|     Private monitorKeywordCancellationTokenSource As New CancellationTokenSource()
 | ||
| 
 | ||
|     '剪切板'
 | ||
|     Private Const WM_CLIPBOARDUPDATE As Integer = &H31D
 | ||
|     '增加剪切板监听'
 | ||
|     <DllImport("user32.dll", SetLastError:=True)>
 | ||
|     Private Shared Function AddClipboardFormatListener(hWnd As IntPtr) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     '移除剪切板监听'
 | ||
|     <DllImport("user32.dll", SetLastError:=True)>
 | ||
|     Private Shared Function RemoveClipboardFormatListener(hWnd As IntPtr) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
 | ||
|     Private Shared Function MoveFileEx(
 | ||
|         lpExistingFileName As String,
 | ||
|         lpNewFileName As String,
 | ||
|         dwFlags As Integer) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
 | ||
|     Private Shared Function SendMessageTimeout(
 | ||
|         hWnd As IntPtr,
 | ||
|         Msg As UInteger,
 | ||
|         wParam As IntPtr,
 | ||
|         lParam As String,
 | ||
|         fuFlags As UInteger,
 | ||
|         uTimeout As UInteger,
 | ||
|         ByRef lpdwResult As IntPtr
 | ||
|     ) As IntPtr
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
 | ||
|     Private Shared Function SendNotifyMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("user32.dll", SetLastError:=True)>
 | ||
|     Private Shared Function RegisterHotKey(
 | ||
|         hWnd As IntPtr,
 | ||
|         id As Integer,
 | ||
|         fsModifiers As UInteger,
 | ||
|         vk As UInteger
 | ||
|     ) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("user32.dll", SetLastError:=True)>
 | ||
|     Private Shared Function UnregisterHotKey(
 | ||
|         hWnd As IntPtr,
 | ||
|         id As Integer
 | ||
|     ) As Boolean
 | ||
|     End Function
 | ||
| 
 | ||
|     <DllImport("advapi32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
 | ||
|     Private Shared Function SetNamedSecurityInfo(
 | ||
|         pObjectName As String,
 | ||
|         objectType As Integer,
 | ||
|         securityInfo As Integer,
 | ||
|         psidOwner As IntPtr,
 | ||
|         psidGroup As IntPtr,
 | ||
|         pDacl As IntPtr,
 | ||
|         pSacl As IntPtr
 | ||
|     ) As Integer
 | ||
|     End Function
 | ||
| 
 | ||
|     Private Const SE_FILE_OBJECT As Integer = 1
 | ||
|     Private Const OWNER_SECURITY_INFORMATION As Integer = &H1
 | ||
|     Private Const WM_HOTKEY As Integer = &H312
 | ||
|     Private Const MOD_CONTROL As Integer = &H2
 | ||
|     Private Const MOD_ALT As Integer = &H1
 | ||
|     Private Const HOTKEY_ID As Integer = 1
 | ||
|     ' 检测当前是否以管理员身份运行
 | ||
|     Private Function IsAdministrator() As Boolean
 | ||
|         Dim identity = WindowsIdentity.GetCurrent()
 | ||
|         Dim principal = New WindowsPrincipal(identity)
 | ||
|         Return principal.IsInRole(WindowsBuiltInRole.Administrator)
 | ||
|     End Function
 | ||
|     Private Sub EnsureElevated()
 | ||
|         If Not IsAdministrator() Then
 | ||
|             Dim psi As New ProcessStartInfo(Application.ExecutablePath) With {
 | ||
|                 .Verb = "runas",
 | ||
|                 .UseShellExecute = True
 | ||
|             }
 | ||
|             Try
 | ||
|                 Process.Start(psi)
 | ||
|             Catch ex As Exception
 | ||
|                 MessageBox.Show("需要管理员权限才能继续。", "权限不足", MessageBoxButtons.OK, MessageBoxIcon.Warning)
 | ||
|             End Try
 | ||
|             Application.Exit()
 | ||
|         End If
 | ||
|     End Sub
 | ||
|     Async Function GetSmbiosUuid() As Task(Of String)
 | ||
|         Dim result As String = String.Empty
 | ||
| 
 | ||
|         Try
 | ||
|             Dim adapters As NetworkInterface() = NetworkInterface.GetAllNetworkInterfaces()
 | ||
| 
 | ||
|             If adapters.Length = 0 Then
 | ||
|                 Console.WriteLine("未找到任何网络接口。")
 | ||
|                 Return String.Empty
 | ||
|             End If
 | ||
|             For Each adapter As NetworkInterface In adapters
 | ||
|                 ' 过滤掉 Loopback 和 Tunnel 接口,只关注 Ethernet 接口
 | ||
|                 If adapter.NetworkInterfaceType = NetworkInterfaceType.Ethernet Then
 | ||
|                     Dim physicalAddress As PhysicalAddress = adapter.GetPhysicalAddress()
 | ||
|                     Dim macBytes As Byte() = physicalAddress.GetAddressBytes()
 | ||
|                     result = String.Join(":", macBytes.Select(Function(b) b.ToString("X2")))
 | ||
| 
 | ||
|                     Exit For
 | ||
|                 End If
 | ||
|             Next
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             ' 读取失败时可以日志记录或抛出
 | ||
|             Console.Error.WriteLine("读取 SMBIOS UUID 时发生异常: " & ex.Message)
 | ||
|         End Try
 | ||
| 
 | ||
|         Return result
 | ||
|     End Function
 | ||
|     Private Async Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
 | ||
|         Dim title As String = $"管理端{全局变量_程序版本}"
 | ||
|         If IsNetworkAvailable() = True Then
 | ||
|             是否断网 = True
 | ||
|         Else
 | ||
|             title = $"管理端{全局变量_程序版本} - 无网络"
 | ||
|             是否断网 = False
 | ||
|         End If
 | ||
| 
 | ||
|         Me.Text = title
 | ||
|         '打开时先判断是否有网络
 | ||
|         Await Task.WhenAll(AddStartupEntry())
 | ||
| 
 | ||
|         '首先第一步就是获取CPU识别号。
 | ||
|         Await Task.Run(Async Function()
 | ||
|                            全局变量_BIOS识别码 = Await GetSmbiosUuid()
 | ||
|                            TextBox4.BeginInvoke(Sub()
 | ||
|                                                     TextBox4.Text = 全局变量_BIOS识别码
 | ||
|                                                 End Sub)
 | ||
|                        End Function)
 | ||
| 
 | ||
| 
 | ||
|         Try
 | ||
|             Dim initResult As Boolean = Await InitSetting()
 | ||
| 
 | ||
|             If initResult = False Then
 | ||
|                 Return
 | ||
|             End If
 | ||
| 
 | ||
|             ' 隐藏当前窗体并继续后续异步初始化
 | ||
|             If Not 全局变量_id = "" Then
 | ||
|                 Me.Hide()
 | ||
|             End If
 | ||
| 
 | ||
|             If Not Me.Visible Then
 | ||
|                 If 是否断网 = True Then
 | ||
|                     Await Task.WhenAll(
 | ||
|                                 GetRemoteTextAndPopulateAllowedProcesses())
 | ||
| 
 | ||
|                     Await Task.Run(Async Function()
 | ||
|                                        Await 日志输出(全局变量_id, "1", 全局变量_BIOS识别码) '打开软件
 | ||
|                                    End Function)
 | ||
|                 Else
 | ||
|                     Dim folder As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Vls")
 | ||
|                     Dim filePath1 As String = Path.Combine(folder, "list")
 | ||
| 
 | ||
|                     ' 检查文件是否存在
 | ||
|                     If File.Exists(filePath1) Then
 | ||
|                         ' 逐行读取并加入 HashSet
 | ||
|                         For Each rawLine As String In File.ReadLines(filePath1)
 | ||
|                             Dim line As String = rawLine.Trim()
 | ||
|                             If Not String.IsNullOrEmpty(line) Then
 | ||
|                                 allowedProcesses.Add(line)
 | ||
| 
 | ||
|                                 TextBox2.BeginInvoke(Sub()
 | ||
|                                                          TextBox2.AppendText(line & vbCrLf)
 | ||
|                                                      End Sub)
 | ||
|                             End If
 | ||
|                         Next
 | ||
| 
 | ||
|                         Button5.BeginInvoke(Sub()
 | ||
|                                                 Button5.Enabled = False
 | ||
|                                             End Sub)
 | ||
|                         Button3.BeginInvoke(Sub()
 | ||
|                                                 Button3.Enabled = False
 | ||
|                                             End Sub)
 | ||
| 
 | ||
|                         StartMonitorLoop()
 | ||
|                     Else
 | ||
|                         MessageBox.Show("进程列表不存在,此软件运行不会生效。确定之后将退出。", "Err", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|                     End If
 | ||
| 
 | ||
|                     If 全局变量_关键字采集 = 1 Then
 | ||
|                         StartKeywordMonitorLoop()
 | ||
|                     End If
 | ||
| 
 | ||
|                 End If
 | ||
| 
 | ||
|                 StartPromptLoopOnce()
 | ||
|             Else
 | ||
|                 Me.Hide()
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             MessageBox.Show("读取文件时发生错误: " & ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         End Try
 | ||
| 
 | ||
|     End Sub
 | ||
| 
 | ||
|     Protected Overrides Sub WndProc(ByRef m As Message)
 | ||
|         MyBase.WndProc(m)
 | ||
|         If m.Msg = WM_HOTKEY AndAlso m.WParam.ToInt32() = HOTKEY_ID Then
 | ||
|             Dim 断网_tmp As Boolean = IsNetworkAvailable()
 | ||
|             If 断网_tmp = False Then
 | ||
|                 MessageBox.Show("当前已断网,请输入超级密码进行登陆!", "Err", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             End If
 | ||
|             Using dlg As New PasswordDialog("请输入打开密码:", "权限请求")
 | ||
|                 If dlg.ShowDialog(Me) = DialogResult.OK Then
 | ||
|                     If 断网_tmp = True Then
 | ||
|                         是否断网 = True
 | ||
|                         Dim PasswordCode As String = 获取密码() ' 假设这是一个字符串
 | ||
|                         Dim input As String = dlg.PasswordText ' 保留为字符串类型
 | ||
|                         If input = PasswordCode Then
 | ||
|                             Me.Show()
 | ||
|                         End If
 | ||
|                     Else
 | ||
|                         Me.Text = $"管理端{全局变量_程序版本} - 无网络"
 | ||
|                         是否断网 = False
 | ||
|                         Dim input As String = dlg.PasswordText ' 保留为字符串类型
 | ||
|                         If input = 全局变量_异常密码 Then
 | ||
|                             Me.Show()
 | ||
|                         End If
 | ||
|                     End If
 | ||
|                 End If
 | ||
|             End Using
 | ||
|         End If
 | ||
| 
 | ||
|         Select Case m.Msg
 | ||
|             Case WM_CLIPBOARDUPDATE
 | ||
|                 ' 获取剪贴板中的文本内容 
 | ||
|                 If 全局变量_关键字采集 = 1 AndAlso Clipboard.ContainsText() Then
 | ||
|                     Dim clipboardText As String = Clipboard.GetText()
 | ||
|                     If Not clipboardText = "" Then
 | ||
|                         Task.Run(Async Function()
 | ||
|                                      Await JudgeKeywords(clipboardText)
 | ||
|                                  End Function)
 | ||
|                     End If
 | ||
|                 End If
 | ||
|         End Select
 | ||
|     End Sub
 | ||
|     Public Function 获取密码() As String
 | ||
|         Dim result As String = ""
 | ||
| 
 | ||
|         Try
 | ||
|             ' 设置请求的URL
 | ||
|             Dim url As String = $"{ApiEndPoint}/mm-machine/getPassword" ' 请替换为你实际的接口地址
 | ||
|             '使用TLS12安全协议连接
 | ||
|             ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
 | ||
|             ' 创建 HttpWebRequest 对象
 | ||
|             Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
 | ||
| 
 | ||
|             ' 设置请求方法为 GET
 | ||
|             request.Method = "GET"
 | ||
|             request.Proxy = Nothing
 | ||
|             ' 发送请求并获取响应
 | ||
|             Dim response As WebResponse = request.GetResponse()
 | ||
| 
 | ||
|             ' 读取响应流并获取内容
 | ||
|             Using reader As New StreamReader(response.GetResponseStream())
 | ||
|                 result = reader.ReadToEnd()
 | ||
|             End Using
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             result = 全局变量_异常密码
 | ||
|         End Try
 | ||
| 
 | ||
|         Return result
 | ||
|     End Function
 | ||
|     Private Async Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
 | ||
|         Dim result As DialogResult = MessageBox.Show("确定要退出吗?", "确认退出", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
 | ||
| 
 | ||
|         ' 如果用户选择“否”,则取消关闭操作
 | ||
|         If result = DialogResult.No Then
 | ||
|             e.Cancel = True
 | ||
|         Else
 | ||
|             If IsNetworkAvailable() = True Then
 | ||
|                 '如果有网络,那么执行日志输出错误,避免出错
 | ||
|                 Await Task.Run(Async Function()
 | ||
|                                    Await 日志输出(全局变量_id, "4", 全局变量_BIOS识别码) '退出软件
 | ||
|                                End Function)
 | ||
|             End If
 | ||
| 
 | ||
|             UnregisterHotKey(Me.Handle, HOTKEY_ID)
 | ||
|             End
 | ||
|         End If
 | ||
| 
 | ||
|         RemoveClipboardFormatListener(Me.Handle)
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 定时任务
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function MonitorLoopAsync(cc As Int64, cancellationToken As CancellationToken) As Task
 | ||
|         Do
 | ||
|             'Logger.Info($"循环中2 {cc}")
 | ||
|             Dim isNetworkAvailableLocal As Boolean = IsNetworkAvailable()
 | ||
|             Dim limitText As String = ""
 | ||
| 
 | ||
|             If 全局变量_进程限制 = 1 Then
 | ||
|                 limitText = "已应用"
 | ||
|             Else
 | ||
|                 limitText = "未应用"
 | ||
|             End If
 | ||
| 
 | ||
|             lbl_taskLimit.BeginInvoke(Sub()
 | ||
|                                           lbl_taskLimit.Text = limitText
 | ||
|                                       End Sub)
 | ||
|             If IsNetworkAvailable() = True Then
 | ||
|                 是否断网 = True
 | ||
|             Else
 | ||
|                 Me.BeginInvoke(Sub()
 | ||
|                                    Me.Text = $"管理端 - 无网络"
 | ||
|                                End Sub)
 | ||
|                 是否断网 = False
 | ||
|             End If
 | ||
| 
 | ||
| 
 | ||
|             If 是否断网 = True And 全局变量_进程限制 <> 2 Then
 | ||
|                 Dim 是否调试 As Boolean = CheckBox1.Checked
 | ||
|                 Try
 | ||
|                     For Each proc As Process In Process.GetProcesses()
 | ||
|                         If Not JudeProcessName(proc.ProcessName) Then
 | ||
|                             Try
 | ||
|                                 If 是否调试 = True Then
 | ||
|                                     ListBox1.BeginInvoke(Sub()
 | ||
|                                                              ListBox1.Items.Add(proc.ProcessName)
 | ||
|                                                          End Sub)
 | ||
|                                 End If
 | ||
| 
 | ||
|                                 If JudgeTimeInterval(proc.ProcessName) Then
 | ||
|                                     Await Task.Run(Async Function()
 | ||
|                                                        Await 日志输出(全局变量_id, "6", 全局变量_BIOS识别码, proc.ProcessName) '拦截进程
 | ||
|                                                    End Function)
 | ||
|                                 End If
 | ||
| 
 | ||
|                                 If 全局变量_进程限制 = 1 Then
 | ||
|                                     proc.Kill()
 | ||
|                                 End If
 | ||
|                             Catch
 | ||
|                             End Try
 | ||
|                         End If
 | ||
|                     Next
 | ||
|                 Catch
 | ||
| 
 | ||
|                 End Try
 | ||
|             ElseIf 全局变量_进程限制 <> 2 Then
 | ||
|                 Dim 是否调试 As Boolean = CheckBox1.Checked
 | ||
|                 Try
 | ||
|                     For Each proc As Process In Process.GetProcesses()
 | ||
|                         If Not JudeProcessName(proc.ProcessName) Then
 | ||
|                             Try
 | ||
|                                 If 是否调试 = True Then
 | ||
|                                     ListBox1.BeginInvoke(Sub()
 | ||
|                                                              ListBox1.Items.Add(proc.ProcessName)
 | ||
|                                                          End Sub)
 | ||
|                                 End If
 | ||
|                                 If 全局变量_进程限制 = 1 Then
 | ||
|                                     proc.Kill()
 | ||
|                                 End If
 | ||
|                             Catch
 | ||
|                             End Try
 | ||
|                         End If
 | ||
|                     Next
 | ||
|                 Catch
 | ||
|                 End Try
 | ||
|             End If
 | ||
| 
 | ||
|             Try
 | ||
|                 Await Task.Delay(500, cancellationToken) ' 使用 CancellationToken 进行延迟
 | ||
|             Catch ex As TaskCanceledException
 | ||
|                 'Console.WriteLine("定时任务已取消")
 | ||
|                 Exit Do
 | ||
|             Catch ex As Exception
 | ||
|                 Logger.Error($"定时任务循环中发生错误: {ex.Message}")
 | ||
|             End Try
 | ||
|         Loop
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 判断是否重复提交
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="进程名称"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Function JudgeTimeInterval(ByVal 进程名称 As String) As Boolean
 | ||
|         ' 检查进程名称是否在字典中
 | ||
|         If Not 全局变量_已拦截进程.ContainsKey(进程名称) Then
 | ||
|             ' 不在字典中,允许通过
 | ||
|             ' 超过指定小时数,允许通过,并更新拦截时间为当前时间
 | ||
|             全局变量_已拦截进程.Add(进程名称, DateTime.Now)
 | ||
|             Return True
 | ||
|         Else
 | ||
|             ' 在字典中,获取记录的时间
 | ||
|             Dim 拦截时间 As DateTime = 全局变量_已拦截进程(进程名称)
 | ||
| 
 | ||
|             ' 计算当前时间与拦截时间的差值(以小时为单位)
 | ||
|             Dim 时间差 As TimeSpan = DateTime.Now - 拦截时间
 | ||
|             Dim 小时差 As Double = 时间差.TotalHours
 | ||
| 
 | ||
|             ' 判断时间差是否超过指定的小时数
 | ||
|             If 小时差 >= 全局变量_拦截记录间隔 Then
 | ||
|                 ' 超过指定小时数,允许通过,并更新拦截时间为当前时间
 | ||
|                 全局变量_已拦截进程(进程名称) = DateTime.Now
 | ||
|                 Return True
 | ||
|             Else
 | ||
|                 ' 未超过指定小时数,不允许通过
 | ||
|                 Return False
 | ||
|             End If
 | ||
|         End If
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 比较进程名
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="processName"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Function JudeProcessName(processName As String) As Boolean
 | ||
|         Dim process As String = processName.Trim.ToLower
 | ||
|         For Each item As String In allowedProcesses
 | ||
|             Dim content As String = item.Trim.ToLower
 | ||
| 
 | ||
|             If process.StartsWith(content) Then
 | ||
|                 Return True
 | ||
|             End If
 | ||
|         Next
 | ||
| 
 | ||
|         Return False
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 定时更新关键字任务
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="cancellationToken"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function KeywordMonitorLoopAsync(cancellationToken As CancellationToken) As Task
 | ||
|         Do
 | ||
|             'Logger.Info("循环中3")
 | ||
|             Dim isNetworkAvailableLocal As Boolean = IsNetworkAvailable()
 | ||
| 
 | ||
|             If isNetworkAvailableLocal = True AndAlso 全局变量_采集的文本.Count > 0 Then
 | ||
|                 Dim keywords As KeywordItemReq() = 全局变量_采集的文本.ToArray
 | ||
|                 全局变量_采集的文本.Clear()
 | ||
|                 Await SaveKeywordLog(keywords)
 | ||
|             End If
 | ||
| 
 | ||
|             If isNetworkAvailableLocal = True AndAlso 全局变量_关键字采集 = 1 Then
 | ||
|                 Await InitLocalKeywords(全局变量_id)
 | ||
|             End If
 | ||
| 
 | ||
|             Try
 | ||
|                 'Console.WriteLine("关键字心跳", 全局变量_关键字心跳时间)
 | ||
|                 If 全局变量_关键字心跳时间 = "" OrElse 全局变量_关键字心跳时间 = "0" OrElse 全局变量_关键字心跳时间 < 30 * 1000 Then
 | ||
|                     Await Task.Delay(60 * 1000, cancellationToken)
 | ||
|                 Else
 | ||
|                     Await Task.Delay(全局变量_关键字心跳时间, cancellationToken)
 | ||
|                 End If
 | ||
| 
 | ||
|             Catch ex As TaskCanceledException
 | ||
|                 'Console.WriteLine("定时任务已取消")
 | ||
|                 Exit Do
 | ||
|             Catch ex As Exception
 | ||
|                 Logger.Error($"定时任务循环中发生错误: {ex.Message}")
 | ||
|             End Try
 | ||
|         Loop
 | ||
|     End Function
 | ||
| 
 | ||
|     Private Sub ListBox1_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles ListBox1.MouseDoubleClick
 | ||
|         Dim index As Integer = ListBox1.IndexFromPoint(e.Location)
 | ||
|         If index >= 0 Then
 | ||
|             Dim selectedItem As String = ListBox1.Items(index).ToString()
 | ||
|             Clipboard.SetText(selectedItem)
 | ||
|             MessageBox.Show("已将 " & selectedItem & " 复制到剪贴板", "复制成功")
 | ||
|         End If
 | ||
|     End Sub
 | ||
|     Private Async Function ReadLocalProcessList() As Task
 | ||
|         Dim exeDir = Application.StartupPath
 | ||
|         Dim txtPath = Path.Combine(exeDir, "ProcessList.txt")
 | ||
|         allowedProcesses.Clear()
 | ||
|         If File.Exists(txtPath) Then
 | ||
|             For Each line As String In File.ReadAllLines(txtPath, Encoding.UTF8)
 | ||
|                 Dim name = line.Trim()
 | ||
|                 If name <> "" Then allowedProcesses.Add(name)
 | ||
|             Next
 | ||
|         Else
 | ||
|             MessageBox.Show($"未找到进程列表文件:{txtPath}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning)
 | ||
|         End If
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 加入启动项
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function AddStartupEntry() As Task
 | ||
|         Try
 | ||
|             '修改目标目录为 C:\ProgramData\MyApp或者AppData 目录
 | ||
|             Dim targetDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Vls")
 | ||
|             If Not Directory.Exists(targetDir) Then
 | ||
|                 Directory.CreateDirectory(targetDir)
 | ||
|             End If
 | ||
| 
 | ||
|             ' 使用任务计划程序的注册方式或直接注册到注册表
 | ||
|             Using runKey = Registry.CurrentUser.OpenSubKey(
 | ||
|             "Software\Microsoft\Windows\CurrentVersion\Run", writable:=True)
 | ||
| 
 | ||
|                 Dim valueName = "XNwhin"
 | ||
|                 If runKey.GetValue(valueName) Is Nothing Then
 | ||
|                     Dim sourcePath = Application.ExecutablePath
 | ||
|                     Dim targetPath = Path.Combine(targetDir, Path.GetFileName(sourcePath))
 | ||
| 
 | ||
|                     ' —— 1. 先复制可执行文件 —— 
 | ||
|                     If File.Exists(targetPath) Then
 | ||
|                         Dim oldAttrs = File.GetAttributes(targetPath)
 | ||
|                         oldAttrs = oldAttrs And Not FileAttributes.ReadOnly And Not FileAttributes.System
 | ||
|                         File.SetAttributes(targetPath, oldAttrs)
 | ||
|                     End If
 | ||
|                     File.Copy(sourcePath, targetPath, overwrite:=True)
 | ||
| 
 | ||
|                     ' —— 2. 设置只读和系统属性 —— 
 | ||
|                     Dim attrs = File.GetAttributes(targetPath)
 | ||
|                     attrs = attrs Or FileAttributes.ReadOnly Or FileAttributes.System Or FileAttributes.Hidden
 | ||
|                     File.SetAttributes(targetPath, attrs)
 | ||
| 
 | ||
|                     Dim everyone = New SecurityIdentifier(WellKnownSidType.WorldSid, Nothing)
 | ||
| 
 | ||
|                     ' —— 3. 对目录加 ACL,拒绝删除 —— 
 | ||
|                     Dim dirInfo = New DirectoryInfo(targetDir)
 | ||
|                     Dim dirAcl = dirInfo.GetAccessControl(AccessControlSections.All)
 | ||
|                     dirAcl.SetAccessRuleProtection(isProtected:=True, preserveInheritance:=True)
 | ||
|                     Dim denyDirRule = New FileSystemAccessRule(
 | ||
|                     everyone,
 | ||
|                     FileSystemRights.Delete Or FileSystemRights.DeleteSubdirectoriesAndFiles,
 | ||
|                     InheritanceFlags.ContainerInherit Or InheritanceFlags.ObjectInherit,
 | ||
|                     PropagationFlags.None,
 | ||
|                     AccessControlType.Deny)
 | ||
|                     dirAcl.AddAccessRule(denyDirRule)
 | ||
|                     dirInfo.SetAccessControl(dirAcl)
 | ||
| 
 | ||
|                     ' —— 4. 对文件加 ACL,拒绝删除 —— 
 | ||
|                     Dim fileInfo = New FileInfo(targetPath)
 | ||
|                     Dim fileAcl = fileInfo.GetAccessControl(AccessControlSections.All)
 | ||
|                     fileAcl.SetAccessRuleProtection(isProtected:=True, preserveInheritance:=True)
 | ||
|                     Dim denyFileRule = New FileSystemAccessRule(
 | ||
|                     everyone,
 | ||
|                     FileSystemRights.Delete,
 | ||
|                     InheritanceFlags.None,
 | ||
|                     PropagationFlags.NoPropagateInherit,
 | ||
|                     AccessControlType.Deny)
 | ||
|                     fileAcl.AddAccessRule(denyFileRule)
 | ||
|                     fileInfo.SetAccessControl(fileAcl)
 | ||
| 
 | ||
|                     ' —— 5. 注册启动项 —— 
 | ||
|                     runKey.SetValue(valueName, $"""{targetPath}""")
 | ||
|                 End If
 | ||
|             End Using
 | ||
| 
 | ||
|         Catch ex As UnauthorizedAccessException
 | ||
|             MessageBox.Show("需要以管理员身份运行此程序!" & vbCrLf &
 | ||
|                         ex.Message, "权限不足",
 | ||
|                         MessageBoxButtons.OK,
 | ||
|                         MessageBoxIcon.Warning)
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             MessageBox.Show("操作失败:" & vbCrLf & ex.Message,
 | ||
|                         "错误", MessageBoxButtons.OK,
 | ||
|                         MessageBoxIcon.Error)
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
|     '获取进程白名单'
 | ||
|     Private Async Function GetRemoteTextAndPopulateAllowedProcesses() As Task(Of String)
 | ||
|         '使用TLS12安全协议连接
 | ||
|         ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
 | ||
|         Dim url As String = $"{ApiEndPoint}/mm-machine/whiteProcess?machineId={全局变量_id}"
 | ||
|         Dim req = CType(WebRequest.Create(url), HttpWebRequest)
 | ||
|         req.Method = "GET"
 | ||
|         req.Timeout = 10000
 | ||
|         req.Proxy = Nothing
 | ||
|         Try
 | ||
|             Using resp = CType(req.GetResponse(), HttpWebResponse)
 | ||
|                 If resp.StatusCode <> HttpStatusCode.OK Then
 | ||
|                     Throw New Exception($"HTTP 请求失败,状态码:{CInt(resp.StatusCode)} {resp.StatusDescription}")
 | ||
|                 End If
 | ||
| 
 | ||
|                 Dim remoteText As String
 | ||
|                 Using sr As New StreamReader(resp.GetResponseStream(), Encoding.UTF8)
 | ||
|                     remoteText = sr.ReadToEnd()
 | ||
|                 End Using
 | ||
| 
 | ||
|                 '反序列化对象'
 | ||
|                 Dim heart As HeartResult = serializer.Deserialize(Of HeartResult)(remoteText)
 | ||
| 
 | ||
|                 If heart IsNot Nothing Then
 | ||
|                     allowedProcesses.Clear()
 | ||
|                     Dim 是否为密码 As Boolean = False
 | ||
|                     Dim lineCount As Integer = 0
 | ||
|                     Dim groupCount As Integer = 0
 | ||
|                     全局变量_进程限制 = heart.tl
 | ||
|                     全局变量_应用限制 = heart.al
 | ||
|                     全局变量_拦截记录间隔 = heart.ii
 | ||
|                     全局变量_心跳时间 = heart.hi * 1000
 | ||
| 
 | ||
|                     If heart.ki = 0 Then
 | ||
|                         全局变量_关键字心跳时间 = 60 * 1000
 | ||
|                     Else
 | ||
|                         全局变量_关键字心跳时间 = heart.ki * 1000
 | ||
|                     End If
 | ||
| 
 | ||
|                     全局变量_关键字采集 = heart.kl
 | ||
| 
 | ||
|                     For Each line As String In heart.c.Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.RemoveEmptyEntries)
 | ||
|                         lineCount += 1
 | ||
|                         Dim procName = line.Trim().Replace("<br />", "")
 | ||
|                         If procName <> "" Then
 | ||
|                             allowedProcesses.Add(procName)
 | ||
|                             TextBox2.AppendText(procName & vbCrLf)
 | ||
|                         End If
 | ||
|                     Next
 | ||
| 
 | ||
|                     If lineCount <= 10 Then
 | ||
|                         MessageBox.Show("当前后台进程数小于10条,为防止不必要的进程被移除,将不会进行进程检测!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning)
 | ||
|                     Else
 | ||
|                         '写入文件
 | ||
|                         Dim outputDir As String = "C:\ProgramData\Vls"
 | ||
|                         If Not Directory.Exists(outputDir) Then
 | ||
|                             Directory.CreateDirectory(outputDir)
 | ||
|                         End If
 | ||
| 
 | ||
|                         Dim filePath As String = Path.Combine(outputDir, "list")
 | ||
|                         Await Task.Run(Sub()
 | ||
|                                            File.WriteAllLines(filePath, allowedProcesses)
 | ||
|                                        End Sub)
 | ||
| 
 | ||
|                         StartMonitorLoop()
 | ||
|                     End If
 | ||
| 
 | ||
|                     Dim groupLines As String() = heart.g.Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.RemoveEmptyEntries)
 | ||
| 
 | ||
|                     If Not groupLines Is Nothing And groupLines.Length > 0 Then
 | ||
|                         allGroupApplication.Clear()
 | ||
| 
 | ||
|                         For Each line As String In groupLines
 | ||
|                             groupCount += 1
 | ||
|                             Dim procName = line.Trim().Replace("<br />", "")
 | ||
|                             If procName <> "" Then
 | ||
|                                 allGroupApplication.Add(procName)
 | ||
|                                 txt_groupItems.BeginInvoke(Sub()
 | ||
|                                                                txt_groupItems.AppendText(procName & vbCrLf)
 | ||
|                                                            End Sub)
 | ||
|                             End If
 | ||
|                         Next
 | ||
|                     End If
 | ||
| 
 | ||
|                     If groupCount > 0 Then
 | ||
|                         Await SaveFile("apps", allGroupApplication.ToArray)
 | ||
| 
 | ||
|                         If heart.al = 1 Then
 | ||
|                             InsertGroup(allGroupApplication.ToArray, False)
 | ||
|                         End If
 | ||
|                     End If
 | ||
| 
 | ||
|                 End If
 | ||
|                 Return remoteText
 | ||
|             End Using
 | ||
| 
 | ||
|         Catch webEx As WebException
 | ||
|             Dim statusDesc = ""
 | ||
|             If webEx.Response IsNot Nothing Then
 | ||
|                 Dim r = CType(webEx.Response, HttpWebResponse)
 | ||
|                 statusDesc = $"(状态码:{CInt(r.StatusCode)} {r.StatusDescription})"
 | ||
|             End If
 | ||
|             Throw New Exception("WebException: " & webEx.Message & statusDesc, webEx)
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             Throw New Exception("请求过程中发生错误: " & ex.Message, ex)
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 停止任务
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="sender"></param>
 | ||
|     ''' <param name="e"></param>
 | ||
|     Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
 | ||
|         Const runKeyPath As String = "Software\Microsoft\Windows\CurrentVersion\Run"
 | ||
|         Const valueName As String = "XNwhin"
 | ||
|         Button1.Enabled = False
 | ||
| 
 | ||
|         ' 修改为新的路径
 | ||
|         Dim targetDir As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Vls")
 | ||
|         Dim targetPath As String = Path.Combine(targetDir, Path.GetFileName(Application.ExecutablePath))
 | ||
|         Dim everyone = New SecurityIdentifier(WellKnownSidType.WorldSid, Nothing)
 | ||
| 
 | ||
|         ' 1) 删除启动项
 | ||
|         Try
 | ||
|             Using runKey = Registry.CurrentUser.OpenSubKey(runKeyPath, writable:=True)
 | ||
|                 If runKey IsNot Nothing AndAlso runKey.GetValue(valueName) IsNot Nothing Then
 | ||
|                     runKey.DeleteValue(valueName)
 | ||
|                 End If
 | ||
|             End Using
 | ||
|         Catch ex As Exception
 | ||
|             MessageBox.Show($"删除启动项失败:{ex.Message}", "错误",
 | ||
|                     MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         End Try
 | ||
| 
 | ||
|         ' 2) 恢复文件 ACL,移除“拒绝删除”
 | ||
|         If File.Exists(targetPath) Then
 | ||
|             Try
 | ||
|                 Dim fileInfo = New FileInfo(targetPath)
 | ||
|                 Dim fileAcl = fileInfo.GetAccessControl(AccessControlSections.All)
 | ||
|                 ' 先移除所有针对 Everyone 的显式规则
 | ||
|                 fileAcl.PurgeAccessRules(everyone)
 | ||
|                 ' 恢复继承(把父目录的 ACL 拷回来)
 | ||
|                 fileAcl.SetAccessRuleProtection(isProtected:=False, preserveInheritance:=True)
 | ||
|                 fileInfo.SetAccessControl(fileAcl)
 | ||
|             Catch ex As Exception
 | ||
|                 ' 如果这里失败也不阻止后续删除尝试
 | ||
|             End Try
 | ||
| 
 | ||
|             ' 3) 去掉只读/系统属性再删除,或安排重启删除
 | ||
|             Try
 | ||
|                 Dim attrs = File.GetAttributes(targetPath)
 | ||
|                 attrs = attrs And Not FileAttributes.ReadOnly And Not FileAttributes.System
 | ||
|                 File.SetAttributes(targetPath, attrs)
 | ||
|                 File.Delete(targetPath)
 | ||
|             Catch ex As Exception
 | ||
|                 Try
 | ||
|                     ' 文件占用,安排下次重启时删除
 | ||
|                     MoveFileEx(targetPath, Nothing, &H4)
 | ||
|                     MessageBox.Show("文件正在使用中,已安排在下次重启时删除。",
 | ||
|                             "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
|                 Catch ex2 As Exception
 | ||
|                     MessageBox.Show($"无法删除文件:{ex2.Message}", "错误",
 | ||
|                             MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|                 End Try
 | ||
|             End Try
 | ||
|         End If
 | ||
| 
 | ||
|         ' 4) 恢复并删除整个目录
 | ||
|         If Directory.Exists(targetDir) Then
 | ||
|             Try
 | ||
|                 Dim dirInfo = New DirectoryInfo(targetDir)
 | ||
|                 Dim dirAcl = dirInfo.GetAccessControl(AccessControlSections.All)
 | ||
|                 dirAcl.PurgeAccessRules(everyone)
 | ||
|                 dirAcl.SetAccessRuleProtection(isProtected:=False, preserveInheritance:=True)
 | ||
|                 dirInfo.SetAccessControl(dirAcl)
 | ||
|             Catch
 | ||
|             End Try
 | ||
| 
 | ||
|             Try
 | ||
|                 Directory.Delete(targetDir, recursive:=True)
 | ||
|             Catch
 | ||
|                 ' 目录可能还有锁定或文件残留,忽略
 | ||
|             End Try
 | ||
|         End If
 | ||
| 
 | ||
|         Try
 | ||
|             RemoveGroup()
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error($"移除组策略失败{ex.StackTrace}")
 | ||
|         End Try
 | ||
| 
 | ||
|         If IsNetworkAvailable() = True Then
 | ||
|             '如果有网络,那么执行日志输出错误,避免出错
 | ||
|             Await Task.Run(Async Function()
 | ||
|                                Await 日志输出(全局变量_id, "3", 全局变量_BIOS识别码) '卸载软件
 | ||
|                            End Function)
 | ||
|         End If
 | ||
|         Button1.Enabled = True
 | ||
|         MessageBox.Show("已完成卸载操作。", "提示",
 | ||
|                 MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
|     End Sub
 | ||
|     Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
 | ||
|         ' 获取当前程序的程序集
 | ||
|         Dim assembly As Assembly = Assembly.GetExecutingAssembly()
 | ||
|         ' 获取程序集版本
 | ||
|         Dim version As Version = assembly.GetName().Version
 | ||
|         全局变量_程序版本 = version.ToString
 | ||
| 
 | ||
|         EnsureElevated()
 | ||
| 
 | ||
|         '先注册热键 防止网络连接失败后无法唤出程序'
 | ||
|         If Not RegisterHotKey(Me.Handle, HOTKEY_ID, MOD_CONTROL Or MOD_ALT, AscW("N"c)) Then
 | ||
|             MessageBox.Show("注册热键失败!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         End If
 | ||
| 
 | ||
|         If Not AddClipboardFormatListener(Me.Handle) Then
 | ||
|             MessageBox.Show("无法注册剪贴板监听:" & Marshal.GetLastWin32Error())
 | ||
|         End If
 | ||
| 
 | ||
|         '加载关键字缓存'
 | ||
|         Task.Run(Async Function()
 | ||
|                      LoadFileKeywords()
 | ||
|                      Await InitLocalKeywords("")
 | ||
|                  End Function)
 | ||
| 
 | ||
| 
 | ||
|         Await JudgeAppVersion()
 | ||
|     End Sub
 | ||
|     Public Function IsNetworkAvailable() As Boolean
 | ||
|         Return NetworkInterface.GetIsNetworkAvailable()
 | ||
|     End Function
 | ||
|     Public Async Function Delay(ByVal milliseconds As Integer) As Task
 | ||
|         Await Task.Delay(milliseconds)
 | ||
|     End Function
 | ||
|     Private Async Sub PromptLoop()
 | ||
|         Do
 | ||
|             'Logger.Info("循环中1")
 | ||
|             Try
 | ||
|                 If IsNetworkAvailable() = True Then
 | ||
|                     是否断网 = True
 | ||
|                 Else
 | ||
|                     Me.BeginInvoke(Sub()
 | ||
|                                        Me.Text = $"管理端 - 无网络"
 | ||
|                                    End Sub)
 | ||
|                     是否断网 = False
 | ||
|                 End If
 | ||
| 
 | ||
|                 If 是否断网 = True AndAlso Not 全局变量_id = "" Then
 | ||
|                     ' 心跳输出,获取白名单进程列表字符串
 | ||
|                     Dim 白名单进程 As String = String.Empty
 | ||
|                     Await Task.Run(Async Function()
 | ||
|                                        白名单进程 = Await 日志输出(全局变量_id, "7", 全局变量_BIOS识别码)
 | ||
|                                    End Function)
 | ||
| 
 | ||
|                     Await InitLocalData(白名单进程)
 | ||
|                     '保存设置缓存'
 | ||
|                     Await SaveSetting()
 | ||
|                 Else
 | ||
|                     ' 断网了就不传日志了
 | ||
|                 End If
 | ||
|                 Await Task.Delay(全局变量_心跳时间)
 | ||
| 
 | ||
|             Catch ex As Exception
 | ||
| 
 | ||
|             End Try
 | ||
|         Loop
 | ||
|     End Sub
 | ||
| 
 | ||
|     Public Sub StartPromptLoopOnce()
 | ||
|         SyncLock promptLoopLock
 | ||
|             If Not promptLoopStarted Then
 | ||
|                 promptLoopTask = Task.Run(Sub()
 | ||
|                                               PromptLoop()
 | ||
|                                           End Sub)
 | ||
|                 promptLoopStarted = True
 | ||
|                 Logger.Info("PromptLoop task started.")
 | ||
|             Else
 | ||
|                 Logger.Info("PromptLoop task is already running.")
 | ||
|             End If
 | ||
|         End SyncLock
 | ||
|     End Sub
 | ||
|     ''' <summary>
 | ||
|     ''' 重新覆盖本地数据
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="白名单进程"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function InitLocalData(白名单进程 As String) As Task(Of String)
 | ||
|         Dim errResult As String = String.Empty
 | ||
| 
 | ||
|         Try
 | ||
|             '反序列化对象'
 | ||
|             Dim heart As HeartResult = serializer.Deserialize(Of HeartResult)(白名单进程)
 | ||
| 
 | ||
|             If heart IsNot Nothing Then
 | ||
|                 If heart.code <> 0 Then
 | ||
|                     Return heart.msg
 | ||
|                 End If
 | ||
| 
 | ||
|                 '重启电脑'
 | ||
|                 If heart.rb Then
 | ||
|                     RebootComputer(True)
 | ||
| 
 | ||
|                     Return ""
 | ||
|                 End If
 | ||
| 
 | ||
|                 Dim oldHeart As Integer = 0
 | ||
|                 Dim oldKeywordHeart As Integer = 0
 | ||
|                 If Not 全局变量_心跳时间 = String.Empty Then
 | ||
|                     oldHeart = Convert.ToInt32(全局变量_心跳时间)
 | ||
|                 End If
 | ||
| 
 | ||
|                 If Not 全局变量_关键字心跳时间 = String.Empty Then
 | ||
|                     oldKeywordHeart = Convert.ToInt32(全局变量_关键字心跳时间)
 | ||
|                 End If
 | ||
| 
 | ||
|                 Dim oldApp As Integer = 全局变量_应用限制
 | ||
|                 全局变量_进程限制 = heart.tl
 | ||
|                 全局变量_应用限制 = heart.al
 | ||
|                 全局变量_拦截记录间隔 = heart.ii
 | ||
|                 全局变量_关键字采集 = heart.kl
 | ||
|                 Dim limitText As String = ""
 | ||
| 
 | ||
|                 If 全局变量_应用限制 = 1 Then
 | ||
|                     limitText = "已应用"
 | ||
|                 Else
 | ||
|                     limitText = "未应用"
 | ||
|                 End If
 | ||
| 
 | ||
|                 lbl_appLimit.BeginInvoke(Sub()
 | ||
|                                              lbl_appLimit.Text = limitText
 | ||
|                                          End Sub)
 | ||
| 
 | ||
|                 If Not heart.c = "" Then
 | ||
|                     ' 清空原来的集合和文本框
 | ||
|                     allowedProcesses.Clear()
 | ||
|                     TextBox2.BeginInvoke(Sub()
 | ||
|                                              TextBox2.Clear()
 | ||
|                                          End Sub)
 | ||
|                     Await SaveTaskWhiteListFile(heart)
 | ||
|                 End If
 | ||
| 
 | ||
|                 Await SaveAppWhiteListFile(heart, oldApp)
 | ||
| 
 | ||
|                 If heart.hi > 0 Then
 | ||
|                     全局变量_心跳时间 = heart.hi * 1000
 | ||
|                     TextBox3.BeginInvoke(Sub()
 | ||
|                                              TextBox3.Text = heart.hi
 | ||
|                                          End Sub)
 | ||
|                 End If
 | ||
|                 If heart.ki > 0 Then
 | ||
|                     全局变量_关键字心跳时间 = heart.ki * 1000
 | ||
|                 Else
 | ||
|                     全局变量_关键字心跳时间 = 60 * 1000
 | ||
|                 End If
 | ||
| 
 | ||
|                 '心跳改变了直接重启定时任务 或者没初始化的时候'
 | ||
|                 If (oldHeart <> heart.hi * 1000 And heart.hi > 0) Or monitorTask Is Nothing Then
 | ||
|                     StartMonitorLoop()
 | ||
|                 End If
 | ||
| 
 | ||
|                 '关键字心跳改变或是没初始化时'
 | ||
|                 If (heart.ki > 0 And oldKeywordHeart <> heart.ki * 1000) Or keywordMonitorTask Is Nothing Then
 | ||
|                     StartKeywordMonitorLoop()
 | ||
|                 End If
 | ||
| 
 | ||
|             Else
 | ||
|                 errResult = "没有返回值"
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             errResult = ex.Message
 | ||
|         End Try
 | ||
| 
 | ||
|         Return errResult
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 更新进程白名单文件
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="heart"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function SaveTaskWhiteListFile(heart As HeartResult) As Task
 | ||
|         ' 逐行处理,加入集合并显示
 | ||
|         Dim lines = heart.c.Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.RemoveEmptyEntries)
 | ||
|         For Each rawLine As String In lines
 | ||
|             Dim procName = rawLine.Trim().Replace("<br/>", "")
 | ||
|             If procName <> "" Then
 | ||
|                 allowedProcesses.Add(procName)
 | ||
|                 TextBox2.BeginInvoke(Sub()
 | ||
|                                          TextBox2.AppendText(procName & vbCrLf)
 | ||
|                                      End Sub)
 | ||
|             End If
 | ||
|         Next
 | ||
| 
 | ||
|         Dim outputDir As String = "C:\ProgramData\Vls"
 | ||
|         If Not Directory.Exists(outputDir) Then
 | ||
|             Directory.CreateDirectory(outputDir)
 | ||
|         End If
 | ||
| 
 | ||
|         Dim filePath As String = Path.Combine(outputDir, "list")
 | ||
|         Await Task.Run(Sub()
 | ||
|                            File.WriteAllLines(filePath, allowedProcesses)
 | ||
|                        End Sub)
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 更新应用进程白名单文件
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="heart"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Async Function SaveAppWhiteListFile(heart As HeartResult, old As Integer) As Task
 | ||
|         Try
 | ||
|             Dim oldList As HashSet(Of String) = allGroupApplication
 | ||
|             '待添加的允许程序'
 | ||
|             Dim addList As List(Of String) = New List(Of String)
 | ||
|             '待删除的允许程序'
 | ||
|             'Dim delList As List(Of String) = New List(Of String)
 | ||
|             Dim apps = heart.g.Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.RemoveEmptyEntries)
 | ||
| 
 | ||
|             '有数据就重新覆盖缓存和存储'
 | ||
|             If apps.Length > 0 Then
 | ||
|                 Await SaveFile("apps", apps)
 | ||
|                 allGroupApplication.Clear()
 | ||
| 
 | ||
|                 For Each item As String In apps
 | ||
|                     allGroupApplication.Add(item)
 | ||
|                 Next
 | ||
| 
 | ||
|                 txt_groupItems.BeginInvoke(Sub()
 | ||
|                                                txt_groupItems.Clear()
 | ||
|                                            End Sub)
 | ||
| 
 | ||
|                 For Each app As String In apps
 | ||
|                     txt_groupItems.BeginInvoke(Sub()
 | ||
|                                                    txt_groupItems.AppendText(app & vbCrLf)
 | ||
|                                                End Sub)
 | ||
|                 Next
 | ||
|             End If
 | ||
| 
 | ||
|             '限制变为不限制'
 | ||
|             If old <> 2 And heart.al = 2 Then
 | ||
|                 RemoveGroup()
 | ||
| 
 | ||
|                 '不限制变为限制'
 | ||
|             ElseIf old <> 1 And heart.al = 1 Then
 | ||
|                 InsertGroup(allGroupApplication.ToArray, False)
 | ||
|             ElseIf heart.al = 1 Then
 | ||
|                 For Each item As String In apps
 | ||
|                     addList.Add(item)
 | ||
|                 Next
 | ||
| 
 | ||
|                 InsertGroup(addList.ToArray, False)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error($"操作应用限制失败:{ex.StackTrace}")
 | ||
|         End Try
 | ||
| 
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 保存数据到文件
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="fileName"></param>
 | ||
|     ''' <param name="apps"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Shared Async Function SaveFile(fileName As String, apps() As String) As Task
 | ||
|         Dim outputDir As String = "C:\ProgramData\Vls"
 | ||
|         If Not Directory.Exists(outputDir) Then
 | ||
|             Directory.CreateDirectory(outputDir)
 | ||
|         End If
 | ||
| 
 | ||
|         Dim filePath As String = Path.Combine(outputDir, fileName)
 | ||
| 
 | ||
|         Using writer As New StreamWriter(filePath, False)
 | ||
|             For Each app As String In apps
 | ||
|                 Await writer.WriteLineAsync(app)
 | ||
|             Next
 | ||
|         End Using
 | ||
|     End Function
 | ||
| 
 | ||
|     Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
 | ||
|         Dim exeDir As String = Application.StartupPath
 | ||
|         Dim txtPath As String = Path.Combine(exeDir, "ProcessList.txt")
 | ||
| 
 | ||
|         Try
 | ||
|             '获取所有进程名,去重并排序
 | ||
|             Dim uniqueNames = Process.GetProcesses() _
 | ||
|                 .Select(Function(p) p.ProcessName) _
 | ||
|                 .Distinct(StringComparer.OrdinalIgnoreCase) _
 | ||
|                 .OrderBy(Function(name) name)
 | ||
| 
 | ||
|             Using writer As New StreamWriter(txtPath, False, System.Text.Encoding.UTF8)
 | ||
|                 For Each name As String In uniqueNames
 | ||
|                     writer.WriteLine(name)
 | ||
|                 Next
 | ||
|             End Using
 | ||
| 
 | ||
|             MessageBox.Show($"去重后的进程名列表已保存到:{txtPath}", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             MessageBox.Show("导出进程名列表时发生错误:" & vbCrLf & ex.Message,
 | ||
|                             "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         End Try
 | ||
|     End Sub
 | ||
| 
 | ||
|     Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
 | ||
|         Me.Hide()
 | ||
|     End Sub
 | ||
| 
 | ||
|     '设置设备编号'
 | ||
|     Private Async Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
 | ||
|         Dim textToWrite As String = TextBox1.Text
 | ||
|         Button3.Enabled = False
 | ||
| 
 | ||
|         If textToWrite = "" Then
 | ||
|             MessageBox.Show("您的机器号或心跳未正确填写呢?", "Err", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return
 | ||
|         End If
 | ||
| 
 | ||
|         Try
 | ||
|             '使用TLS12安全协议连接
 | ||
|             ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
 | ||
|             Dim url As String = $"{ApiEndPoint}/mm-machine/checkMachine?machineId={textToWrite}&biosId={全局变量_BIOS识别码}"
 | ||
| 
 | ||
|             Dim req = CType(WebRequest.Create(url), HttpWebRequest)
 | ||
| 
 | ||
|             req.Method = "GET"
 | ||
|             req.Timeout = 10000
 | ||
|             req.Proxy = Nothing
 | ||
| 
 | ||
|             Using resp = CType(req.GetResponse(), HttpWebResponse)
 | ||
|                 If resp.StatusCode <> HttpStatusCode.OK Then
 | ||
|                     Throw New Exception($"HTTP 请求失败,状态码:{CInt(resp.StatusCode)} {resp.StatusDescription}")
 | ||
|                 End If
 | ||
| 
 | ||
|                 Dim remoteText As String
 | ||
|                 Using sr As New StreamReader(resp.GetResponseStream(), Encoding.UTF8)
 | ||
|                     remoteText = sr.ReadToEnd()
 | ||
| 
 | ||
|                     Dim errMsg As String = Await InitLocalData(remoteText)
 | ||
| 
 | ||
|                     If errMsg <> String.Empty Then
 | ||
|                         TextBox1.BeginInvoke(Sub()
 | ||
|                                                  TextBox1.Text = 全局变量_id
 | ||
|                                              End Sub)
 | ||
|                         MessageBox.Show(errMsg)
 | ||
|                         Button3.BeginInvoke(Sub()
 | ||
|                                                 Button3.Enabled = True
 | ||
|                                             End Sub)
 | ||
|                         Return
 | ||
|                     End If
 | ||
| 
 | ||
|                     全局变量_id = textToWrite
 | ||
|                     Await SaveSetting()
 | ||
|                     StartMonitorLoop()
 | ||
|                 End Using
 | ||
| 
 | ||
|                 If 是否断网 = True Then
 | ||
|                     Await Task.Run(Async Function()
 | ||
|                                        Await 日志输出(全局变量_id, "2", 全局变量_BIOS识别码) '安装软件
 | ||
|                                    End Function)
 | ||
|                 End If
 | ||
|             End Using
 | ||
|         Catch ex As Exception
 | ||
|             Button3.BeginInvoke(Sub()
 | ||
|                                     Button3.Enabled = True
 | ||
|                                 End Sub)
 | ||
|             ' 其他异常处理
 | ||
|             MessageBox.Show("发生错误: " & ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return
 | ||
|         End Try
 | ||
| 
 | ||
|         Try
 | ||
|             'Await SaveSetting()
 | ||
| 
 | ||
|             If IsNetworkAvailable() = True Then
 | ||
|                 '如果有网络,那么执行日志输出错误,避免出错
 | ||
|                 Await Task.Run(Async Function()
 | ||
|                                    Await 日志输出(textToWrite, "5", 全局变量_BIOS识别码) ' 修改机器号
 | ||
|                                End Function)
 | ||
|             End If
 | ||
|             Await Task.WhenAll(AddStartupEntry())
 | ||
|             全局变量_id = textToWrite
 | ||
| 
 | ||
|             MessageBox.Show("机器号及心跳已保存!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
|         Catch ex As UnauthorizedAccessException
 | ||
|             ' 如果没有权限,显示错误信息
 | ||
|             MessageBox.Show("没有权限写入该文件。请检查权限设置。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         Catch ex As Exception
 | ||
|             ' 其他异常处理
 | ||
|             MessageBox.Show("发生错误: " & ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         Finally
 | ||
|             Button3.BeginInvoke(Sub()
 | ||
|                                     Button3.Enabled = True
 | ||
|                                 End Sub)
 | ||
|         End Try
 | ||
|     End Sub
 | ||
| 
 | ||
|     Private Async Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
 | ||
|         ' 获取TextBox2中的内容
 | ||
|         Dim content As String = TextBox2.Text
 | ||
| 
 | ||
|         ' 按行分割内容
 | ||
|         Dim lines As String() = content.Split(New String() {Environment.NewLine}, StringSplitOptions.None)
 | ||
| 
 | ||
|         ' 用 HashSet 来跟踪已经添加过的行(大小写不敏感)
 | ||
|         Dim seen As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
 | ||
|         Dim filteredLines As New List(Of String)()
 | ||
| 
 | ||
|         ' 遍历所有行:去除空行、重复行
 | ||
|         For Each line As String In lines
 | ||
|             If Not String.IsNullOrWhiteSpace(line) AndAlso seen.Add(line) Then
 | ||
|                 filteredLines.Add(line)
 | ||
|             End If
 | ||
|         Next
 | ||
| 
 | ||
|         ' 重新组合结果
 | ||
|         Dim result As String = String.Join(Environment.NewLine, filteredLines)
 | ||
| 
 | ||
|         ' 如果缺少 “taskmgr”,则弹出提示框
 | ||
|         If result.IndexOf("taskmgr", StringComparison.OrdinalIgnoreCase) < 0 Then
 | ||
|             Dim dr As DialogResult = MessageBox.Show(
 | ||
|             "您当前提交未提交任务管理器:taskmgr,是否继续提交?",
 | ||
|             "提示",
 | ||
|             MessageBoxButtons.YesNo,
 | ||
|             MessageBoxIcon.Warning
 | ||
|         )
 | ||
|             If dr = DialogResult.No Then
 | ||
|                 ' 用户选择 “否”,直接退出,不提交
 | ||
|                 Return
 | ||
|             End If
 | ||
|         End If
 | ||
| 
 | ||
|         If filteredLines.Count > 0 Then
 | ||
|             allowedProcesses = New HashSet(Of String)(filteredLines)
 | ||
|         End If
 | ||
| 
 | ||
|         ' 输出去重后的内容
 | ||
|         'Console.WriteLine(result)
 | ||
| 
 | ||
|         ' 异步更新数据
 | ||
|         Await Task.Run(Async Function()
 | ||
|                            Await 更新数据(result)
 | ||
|                        End Function)
 | ||
|     End Sub
 | ||
| 
 | ||
|     Async Function 更新数据(ByVal 数据 As String) As Task
 | ||
|         Dim url As String = $"{ApiEndPoint}/mm-machine/machineWhite"
 | ||
| 
 | ||
|         ' 要发送的 POST 数据
 | ||
|         Dim postData As String = 数据
 | ||
|         '使用TLS12安全协议连接
 | ||
|         ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
 | ||
|         ' 创建请求对象
 | ||
|         Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
 | ||
|         request.Method = "POST"
 | ||
|         request.ContentType = "application/x-www-form-urlencoded"
 | ||
|         request.Proxy = Nothing
 | ||
| 
 | ||
|         Try
 | ||
|             ' 获取响应
 | ||
|             Dim formData As New List(Of KeyValuePair(Of String, String))()
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("machineId", 全局变量_id))
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("biosId", 全局变量_BIOS识别码))
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("content", postData))
 | ||
|             Dim content As New FormUrlEncodedContent(formData)
 | ||
| 
 | ||
|             Dim response As HttpResponseMessage = Await client.PostAsync(url, content)
 | ||
| 
 | ||
|             If response.IsSuccessStatusCode Then
 | ||
|                 Dim responseText As String = Await response.Content.ReadAsStringAsync()
 | ||
|                 If responseText = "成功更新数据" Then
 | ||
|                     ' 处理传递过来的数据并将其添加到 allowedProcesses 集合
 | ||
|                     Dim newData As String() = 数据.Split(New String() {vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
 | ||
| 
 | ||
|                     ' 先移除 allowedProcesses 中不在 newData 中的项
 | ||
|                     For Each item As String In allowedProcesses.ToList()
 | ||
|                         If Not newData.Contains(item) Then
 | ||
|                             allowedProcesses.Remove(item)
 | ||
|                         End If
 | ||
|                     Next
 | ||
| 
 | ||
|                     ' 然后将新的数据添加到集合中,集合会自动去重
 | ||
|                     For Each item As String In newData
 | ||
|                         allowedProcesses.Add(item)
 | ||
|                     Next
 | ||
|                 End If
 | ||
|                 Label2.BeginInvoke(Sub()
 | ||
|                                        Label2.Text = "更新完成!" & " 时间: " & DateTime.Now.ToString("HH:mm:ss")
 | ||
|                                    End Sub)
 | ||
|             Else
 | ||
|                 MessageBox.Show("更新数据失败 ", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             End If
 | ||
|         Catch ex As WebException
 | ||
|             Using reader As New StreamReader(ex.Response.GetResponseStream())
 | ||
|                 Dim errorText As String = reader.ReadToEnd()
 | ||
|                 Logger.Error("请求失败: " & errorText)
 | ||
|             End Using
 | ||
|         End Try
 | ||
|     End Function
 | ||
|     Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
 | ||
|         ListBox1.Items.Clear()
 | ||
|     End Sub
 | ||
| 
 | ||
|     Public Async Function 日志输出(
 | ||
|     ByVal mid As String,
 | ||
|     ByVal type As String,
 | ||
|     ByVal biosId As String,
 | ||
|     Optional ByVal processName As String = ""
 | ||
| ) As Task(Of String)
 | ||
|         Try
 | ||
|             If mid = "" Then
 | ||
|                 Return ""
 | ||
|             End If
 | ||
| 
 | ||
|             ' 根据 type 是否为 6 来构造 URL
 | ||
|             Dim url As String
 | ||
|             url = $"{ApiEndPoint}/mm-machine/machineLog"
 | ||
| 
 | ||
|             ' 使用 TLS1.2 安全协议连接
 | ||
|             ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
 | ||
| 
 | ||
|             ' 创建 HttpWebRequest 对象
 | ||
|             Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
 | ||
|             request.Method = "POST"
 | ||
|             request.ContentType = "application/x-www-form-urlencoded"
 | ||
|             request.Proxy = Nothing
 | ||
| 
 | ||
|             ' 构造 FormData 参数
 | ||
|             Dim formData As New List(Of KeyValuePair(Of String, String))()
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("machineId", mid))
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("biosId", biosId))
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("type", type.ToString()))
 | ||
|             formData.Add(New KeyValuePair(Of String, String)("remark", processName))
 | ||
|             Dim content As New FormUrlEncodedContent(formData)
 | ||
| 
 | ||
|             Dim response As HttpResponseMessage = Await client.PostAsync(url, content)
 | ||
| 
 | ||
|             ' 发送请求并获取响应
 | ||
|             If response.IsSuccessStatusCode Then
 | ||
|                 Dim responseContent As String = Await response.Content.ReadAsStringAsync()
 | ||
|                 Return responseContent
 | ||
|             Else
 | ||
|                 Return ""
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Return ""
 | ||
|         End Try
 | ||
| 
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 写入组策略
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="sender"></param>
 | ||
|     ''' <param name="e"></param>
 | ||
|     Private Sub btn_groupSet_Click(sender As Object, e As EventArgs)
 | ||
|         ' 检查文本框是否为空
 | ||
|         If String.IsNullOrWhiteSpace(txt_groupItems.Text) Then
 | ||
|             MessageBox.Show("请输入至少一个项目!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return
 | ||
|         End If
 | ||
| 
 | ||
|         ' 分割字符串为数组,去除空项并修剪空格
 | ||
|         Dim apps As String() = txt_groupItems.Text _
 | ||
|         .Split({vbCrLf, vbLf, vbCr}, StringSplitOptions.RemoveEmptyEntries) _
 | ||
|         .Select(Function(item) item.Trim()) _
 | ||
|         .Where(Function(item) Not String.IsNullOrEmpty(item)) _
 | ||
|         .ToArray()
 | ||
| 
 | ||
|         apps = InsertGroup(apps, True)
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 新增分组数据
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="apps"></param>
 | ||
|     ''' <param name="showMessage">是否显示消息</param>
 | ||
|     ''' <returns></returns>
 | ||
|     Private Function InsertGroup(apps() As String, Optional ByVal showMessage As Boolean = False) As String()
 | ||
|         '如果没有内容'
 | ||
|         If apps.Length = 0 Then
 | ||
|             If showMessage Then
 | ||
|                 If showMessage Then
 | ||
|                     MessageBox.Show("请先设置限制项", "错误",
 | ||
|                                 MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|                 End If
 | ||
|             End If
 | ||
|         Else
 | ||
|             Try
 | ||
|                 '添加本身程序'112255
 | ||
|                 Dim currentAppName As String = Path.GetFileName(Application.ExecutablePath)
 | ||
|                 '默认把本程序、记事本、浏览器加入到允许'
 | ||
|                 apps = apps.Concat({currentAppName, "notepad.exe", "msedge.exe"}).ToArray()
 | ||
| 
 | ||
|                 Using key As RegistryKey = Registry.CurrentUser.CreateSubKey(
 | ||
|                         "Software\Microsoft\Windows\CurrentVersion\Policies\Explorer",
 | ||
|                         RegistryKeyPermissionCheck.ReadWriteSubTree)
 | ||
| 
 | ||
|                     key.SetValue("RestrictRun", 1, RegistryValueKind.DWord)
 | ||
|                 End Using
 | ||
| 
 | ||
|                 Using runKey As RegistryKey = Registry.CurrentUser.CreateSubKey(
 | ||
|             "Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\RestrictRun",
 | ||
|             RegistryKeyPermissionCheck.ReadWriteSubTree)
 | ||
| 
 | ||
|                     ' 先把旧的都删了
 | ||
|                     Dim valueNames = runKey.GetValueNames()
 | ||
|                     For Each valueName As String In valueNames
 | ||
|                         runKey.DeleteValue(valueName, throwOnMissingValue:=False)
 | ||
|                     Next
 | ||
| 
 | ||
|                     ' 再写新的白名单
 | ||
|                     For i As Integer = 0 To apps.Length - 1
 | ||
|                         runKey.SetValue((i + 1).ToString(), apps(i), RegistryValueKind.String)
 | ||
|                     Next
 | ||
|                 End Using
 | ||
| 
 | ||
|                 RefreshGroup()
 | ||
| 
 | ||
|                 If showMessage Then
 | ||
|                     MessageBox.Show("策略已写入并已通知 Explorer 刷新,马上生效!", "完成",
 | ||
|                             MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
|                 End If
 | ||
| 
 | ||
|             Catch ex As Exception
 | ||
|                 If showMessage Then
 | ||
|                     MessageBox.Show("写入注册表出错:" & ex.Message, "错误",
 | ||
|                                     MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|                 End If
 | ||
| 
 | ||
|             End Try
 | ||
|         End If
 | ||
| 
 | ||
|         Return apps
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 刷新策略
 | ||
|     ''' </summary>
 | ||
|     Private Shared Sub RefreshGroup()
 | ||
|         '    Dim result As IntPtr = IntPtr.Zero
 | ||
|         '    SendMessageTimeout(
 | ||
|         '    New IntPtr(HWND_BROADCAST),
 | ||
|         '    WM_SETTINGCHANGE,
 | ||
|         '    IntPtr.Zero,
 | ||
|         '    "Policy",            ' 刷新策略
 | ||
|         '    SMTO_NORMAL,
 | ||
|         '    2000,                ' 超时 2 秒
 | ||
|         '    result
 | ||
|         ')
 | ||
|         Try
 | ||
|             Dim result As Boolean = SendNotifyMessage(
 | ||
|                 New IntPtr(HWND_BROADCAST),
 | ||
|                 WM_SETTINGCHANGE,
 | ||
|                 IntPtr.Zero,
 | ||
|                 "Policy"
 | ||
|             )
 | ||
| 
 | ||
|             If Not result Then
 | ||
|                 Dim errorCode As Integer = Marshal.GetLastWin32Error()
 | ||
|                 Logger.Error($"SendNotifyMessage 失败,错误码:{errorCode}")
 | ||
|             Else
 | ||
|                 Logger.Info("组策略刷新消息已发送")
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error($"刷新组策略失败:{ex.Message}")
 | ||
|         End Try
 | ||
|     End Sub
 | ||
| 
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 移除分组策略
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="showMessage">是否显示提示</param>
 | ||
|     Private Shared Sub RemoveGroup(Optional showMessage As Boolean = False)
 | ||
|         ' 检查文本框是否为空
 | ||
|         Try
 | ||
|             Using key As RegistryKey = Registry.CurrentUser.OpenSubKey(
 | ||
|                     "Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", True)
 | ||
|                 If key IsNot Nothing Then
 | ||
|                     key.DeleteValue("RestrictRun", throwOnMissingValue:=False)
 | ||
|                 End If
 | ||
|             End Using
 | ||
| 
 | ||
|             Using runKey As RegistryKey = Registry.CurrentUser.OpenSubKey(
 | ||
|                     "Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\RestrictRun", True)
 | ||
|                 If runKey IsNot Nothing Then
 | ||
|                     For Each name As String In runKey.GetValueNames()
 | ||
|                         runKey.DeleteValue(name, throwOnMissingValue:=False)
 | ||
|                     Next
 | ||
|                 End If
 | ||
|             End Using
 | ||
| 
 | ||
|             Registry.CurrentUser.DeleteSubKeyTree(
 | ||
|                 "Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\RestrictRun",
 | ||
|                 throwOnMissingSubKey:=False)
 | ||
| 
 | ||
|             RefreshGroup()
 | ||
| 
 | ||
|             If showMessage Then
 | ||
|                 MessageBox.Show("已清除所有 RestrictRun 白名单并关闭策略,Explorer 已刷新。",
 | ||
|                             "完成", MessageBoxButtons.OK, MessageBoxIcon.Information)
 | ||
|             End If
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
|             If showMessage Then
 | ||
|                 MessageBox.Show("撤销策略时出错:" & ex.Message,
 | ||
|                             "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             End If
 | ||
| 
 | ||
|         End Try
 | ||
|     End Sub
 | ||
| 
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 启动或重启定时任务
 | ||
|     ''' </summary>
 | ||
|     Public Sub StartMonitorLoop()
 | ||
|         ' 如果之前的任务正在运行,先取消并等待它完成
 | ||
|         If monitorTask IsNot Nothing AndAlso Not monitorTask.IsCompleted AndAlso Not monitorTask.IsCanceled Then
 | ||
|             monitorCancellationTokenSource.Cancel()
 | ||
|             Try
 | ||
|                 monitorTask.Wait(10000) ' 最多等待 10 秒
 | ||
|             Catch ex As OperationCanceledException
 | ||
|                 ' 任务被取消,这是预期行为
 | ||
|             Catch ex As Exception
 | ||
|                 Logger.Error($"停止旧任务时发生错误: {ex.StackTrace}")
 | ||
|             Finally
 | ||
|                 monitorCancellationTokenSource.Dispose()
 | ||
|                 monitorCancellationTokenSource = New CancellationTokenSource() ' 创建新的 CancellationTokenSource
 | ||
|             End Try
 | ||
|         ElseIf monitorTask IsNot Nothing Then
 | ||
|             monitorTask.Dispose() ' 释放已完成的任务资源
 | ||
|             monitorCancellationTokenSource.Dispose()
 | ||
|             monitorCancellationTokenSource = New CancellationTokenSource() ' 创建新的 CancellationTokenSource
 | ||
|         Else
 | ||
|             monitorCancellationTokenSource = New CancellationTokenSource() ' 首次启动创建
 | ||
|         End If
 | ||
| 
 | ||
|         monitorTask = Task.Run(Function() As Task
 | ||
|                                    Return MonitorLoopAsync(DateTime.UtcNow.Millisecond, monitorCancellationTokenSource.Token)
 | ||
|                                End Function)
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 停止定时任务
 | ||
|     ''' </summary>
 | ||
|     Public Sub StopMonitorLoop()
 | ||
|         If monitorTask IsNot Nothing AndAlso Not monitorTask.IsCompleted AndAlso Not monitorTask.IsCanceled Then
 | ||
|             monitorCancellationTokenSource.Cancel()
 | ||
|             Try
 | ||
|                 monitorTask.Wait(5000) ' 最多等待 5 秒
 | ||
|             Catch ex As OperationCanceledException
 | ||
|                 ' 任务被取消
 | ||
|             Catch ex As Exception
 | ||
|                 Logger.Error($"停止任务时发生错误: {ex.StackTrace}")
 | ||
|             Finally
 | ||
|                 monitorCancellationTokenSource.Dispose()
 | ||
|                 monitorTask.Dispose()
 | ||
|                 monitorTask = Nothing
 | ||
|             End Try
 | ||
|         End If
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 启动或重启定时任务
 | ||
|     ''' </summary>
 | ||
|     Public Sub StartKeywordMonitorLoop()
 | ||
|         SyncLock keywordLoopLock
 | ||
|             ' 如果之前的任务正在运行,先取消并等待它完成
 | ||
|             If keywordMonitorTask IsNot Nothing AndAlso
 | ||
|                 Not keywordMonitorTask.IsCompleted AndAlso
 | ||
|                 Not keywordMonitorTask.IsCanceled AndAlso
 | ||
|                 Not keywordMonitorTask.IsFaulted Then
 | ||
|                 monitorKeywordCancellationTokenSource.Cancel()
 | ||
|                 Try
 | ||
|                     keywordMonitorTask.Wait(10000) ' 最多等待 10 秒
 | ||
|                 Catch ex As OperationCanceledException
 | ||
|                     ' 任务被取消,这是预期行为
 | ||
|                 Catch ex As Exception
 | ||
|                     Logger.Error($"停止旧任务时发生错误: {ex.StackTrace}")
 | ||
|                 Finally
 | ||
|                     monitorKeywordCancellationTokenSource.Dispose()
 | ||
|                     monitorKeywordCancellationTokenSource = New CancellationTokenSource() ' 创建新的 CancellationTokenSource
 | ||
|                 End Try
 | ||
|             ElseIf keywordMonitorTask IsNot Nothing Then
 | ||
|                 keywordMonitorTask.Dispose() ' 释放已完成的任务资源
 | ||
|                 monitorKeywordCancellationTokenSource.Dispose()
 | ||
|                 monitorKeywordCancellationTokenSource = New CancellationTokenSource() ' 创建新的 CancellationTokenSource
 | ||
|             Else
 | ||
|                 monitorKeywordCancellationTokenSource = New CancellationTokenSource() ' 首次启动创建
 | ||
|             End If
 | ||
| 
 | ||
|             keywordMonitorTask = Task.Run(Function() As Task
 | ||
|                                               Return KeywordMonitorLoopAsync(monitorKeywordCancellationTokenSource.Token)
 | ||
|                                           End Function)
 | ||
|         End SyncLock
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 停止定时任务
 | ||
|     ''' </summary>
 | ||
|     Public Sub StopKeywordMonitorLoop()
 | ||
|         If keywordMonitorTask IsNot Nothing AndAlso Not keywordMonitorTask.IsCompleted AndAlso Not keywordMonitorTask.IsCanceled Then
 | ||
|             monitorKeywordCancellationTokenSource.Cancel()
 | ||
|             Try
 | ||
|                 keywordMonitorTask.Wait(5000) ' 最多等待 5 秒
 | ||
|             Catch ex As OperationCanceledException
 | ||
|                 ' 任务被取消
 | ||
|             Catch ex As Exception
 | ||
|                 Logger.Error($"停止任务时发生错误: {ex.StackTrace}")
 | ||
|             Finally
 | ||
|                 monitorKeywordCancellationTokenSource.Dispose()
 | ||
|                 keywordMonitorTask.Dispose()
 | ||
|                 keywordMonitorTask = Nothing
 | ||
|             End Try
 | ||
|         End If
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 获取关键词数据
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function GetKeywords(machineId As String) As Task(Of KeywordItem)
 | ||
|         Dim result As KeywordItem = New KeywordItem
 | ||
| 
 | ||
|         Try
 | ||
|             Dim url As String = $"{ApiEndPoint}/mm-machine/keywords?machineId={machineId}"
 | ||
| 
 | ||
|             Dim response As HttpResponseMessage = Await client.GetAsync(url)
 | ||
|             If response.IsSuccessStatusCode Then
 | ||
|                 Dim responseText As String = Await response.Content.ReadAsStringAsync()
 | ||
| 
 | ||
|                 If responseText <> "" Then
 | ||
|                     '反序列化对象'
 | ||
|                     result = serializer.Deserialize(Of KeywordItem)(responseText)
 | ||
|                 Else
 | ||
|                     Logger.Error("没有新内容")
 | ||
|                 End If
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("获取关键字失败:" & ex.StackTrace)
 | ||
|         End Try
 | ||
| 
 | ||
|         Return result
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 缓存关键字
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function InitLocalKeywords(machineId As String) As Task
 | ||
|         Try
 | ||
|             Dim resp As KeywordItem = Await GetKeywords(machineId)
 | ||
| 
 | ||
|             '只要有一项有数据就覆盖
 | ||
|             If (resp.l IsNot Nothing AndAlso resp.l.Length > 0) OrElse (resp.k IsNot Nothing AndAlso resp.k.Length > 0) OrElse
 | ||
|             (resp.li IsNot Nothing AndAlso resp.li.Length > 0) Then
 | ||
|                 Dim cache As String = serializer.Serialize(resp)
 | ||
|                 Dim content As String = StringEncryption.EncryptStringAES(cache, StringEncryption.KeyBase64, StringEncryption.IVBase64)
 | ||
| 
 | ||
|                 全局变量_关键字 = resp
 | ||
| 
 | ||
|                 '保存到文件'
 | ||
|                 Await SaveFile("keywords", {content})
 | ||
|             End If
 | ||
| 
 | ||
| 
 | ||
|         Catch ex As Exception
 | ||
| 
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 判断是否需要写入到远端
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function JudgeKeywords(content As String) As Task
 | ||
|         Dim req As KeywordItemReq = New KeywordItemReq
 | ||
| 
 | ||
| 
 | ||
|         If 全局变量_关键字.k IsNot Nothing Then
 | ||
|             For Each item As String In 全局变量_关键字.k
 | ||
|                 req.type = 0
 | ||
|                 req.content = content
 | ||
|                 '关键字内容'
 | ||
|                 If 是否断网 = True AndAlso content.Contains(item) Then
 | ||
|                     Await SaveKeywordLog({req})
 | ||
|                 ElseIf 是否断网 = False AndAlso content.Contains(item) Then
 | ||
|                     全局变量_采集的文本.Add(req)
 | ||
|                     Exit For
 | ||
|                 End If
 | ||
|             Next
 | ||
|         End If
 | ||
| 
 | ||
|         If 全局变量_关键字.l IsNot Nothing Then
 | ||
|             For Each item As String In 全局变量_关键字.l
 | ||
|                 '文本长度'
 | ||
|                 Dim len As Integer = Convert.ToInt32(item)
 | ||
|                 req.type = 1
 | ||
|                 req.content = content
 | ||
| 
 | ||
|                 If 是否断网 = True AndAlso len > 0 AndAlso content.Length = len Then
 | ||
|                     Await SaveKeywordLog({req})
 | ||
|                     Exit For
 | ||
|                 ElseIf 是否断网 = False AndAlso len > 0 AndAlso content.Length = len Then
 | ||
|                     全局变量_采集的文本.Add(req)
 | ||
|                     Exit For
 | ||
|                 End If
 | ||
|             Next
 | ||
|         End If
 | ||
| 
 | ||
| 
 | ||
|         '长度限制 忽略符号、空格、换行'
 | ||
|         If Not 全局变量_关键字.li Is Nothing Then
 | ||
|             For Each item As String In 全局变量_关键字.li
 | ||
|                 Dim len As Integer = Convert.ToInt32(item)
 | ||
|                 req.type = 2
 | ||
|                 req.content = content
 | ||
| 
 | ||
|                 If 是否断网 = True AndAlso len > 0 AndAlso CheckTextLengthIgnoringCustomChars(content, len, ignoreChars) Then
 | ||
|                     Await SaveKeywordLog({req})
 | ||
|                     Exit For
 | ||
|                 ElseIf 是否断网 = False AndAlso len > 0 AndAlso CheckTextLengthIgnoringCustomChars(content, len, ignoreChars) Then
 | ||
|                     全局变量_采集的文本.Add(req)
 | ||
|                     Exit For
 | ||
|                 End If
 | ||
|             Next
 | ||
|         End If
 | ||
| 
 | ||
| 
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 判断文本长度,忽略特定符号,空格,换行
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="text"></param>
 | ||
|     ''' <param name="expectedLength"></param>
 | ||
|     ''' <param name="charsToIgnore"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Function CheckTextLengthIgnoringCustomChars(ByVal text As String, ByVal expectedLength As Integer, ByVal charsToIgnore As HashSet(Of Char)) As Boolean
 | ||
|         Dim actualLength As Integer = 0
 | ||
|         For Each ca As Char In text
 | ||
|             If Not charsToIgnore.Contains(ca) AndAlso Char.IsLetterOrDigit(ca) Then
 | ||
|                 actualLength += 1
 | ||
|             End If
 | ||
|         Next
 | ||
|         Return actualLength = expectedLength
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 保存记录
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="keyword"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function SaveKeywordLog(keyword As KeywordItemReq()) As Task
 | ||
|         Try
 | ||
|             Dim url As String = $"{ApiEndPoint}/mm-risk-log/save"
 | ||
|             Dim data As New With {.machineId = 全局变量_id, .biosId = 全局变量_BIOS识别码, .content = keyword.ToList}
 | ||
|             Dim jsonData As String = serializer.Serialize(data)
 | ||
|             ' 设置请求的 Content-Type 为 application/json
 | ||
|             Dim content As New StringContent(jsonData, Encoding.UTF8, "application/json")
 | ||
| 
 | ||
|             Dim response As HttpResponseMessage = Await client.PostAsync(url, content)
 | ||
| 
 | ||
|             ' 发送请求并获取响应
 | ||
|             If response.IsSuccessStatusCode Then
 | ||
|                 Dim responseContent As String = Await response.Content.ReadAsStringAsync()
 | ||
|                 Logger.Error("保存关键字记录失败:" & responseContent)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("保存关键字失败 err:" & ex.StackTrace)
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 读取本地存储
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Function LoadFileKeywords()
 | ||
|         Try
 | ||
|             Dim lines As String() = GetFileContent("c:\ProgramData\Vls\keywords")
 | ||
| 
 | ||
|             If lines.Length > 0 Then
 | ||
|                 Dim content As String = lines.First
 | ||
|                 Dim desContent As String = StringEncryption.DecryptStringAES(content, StringEncryption.KeyBase64, StringEncryption.IVBase64)
 | ||
|                 Dim data As KeywordItem = serializer.Deserialize(Of KeywordItem)(desContent)
 | ||
| 
 | ||
|                 If data.l.Length > 0 OrElse data.k.Length > 0 Then
 | ||
|                     全局变量_关键字 = data
 | ||
|                 End If
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("读取本地存储失败" & ex.StackTrace)
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 获取本地文件内容
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="path"></param>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Function GetFileContent(filePath As String) As String()
 | ||
|         Dim result As String() = {}
 | ||
|         Try
 | ||
|             If File.Exists(filePath) Then
 | ||
|                 ' 读取所有行
 | ||
|                 result = File.ReadAllLines(filePath)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("读取文件失败" & ex.StackTrace)
 | ||
|         End Try
 | ||
| 
 | ||
|         Return result
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 保存配置
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function SaveSetting() As Task
 | ||
|         Dim config As SetConfig = New SetConfig
 | ||
|         config.MachineId = 全局变量_id
 | ||
|         config.BiosId = 全局变量_BIOS识别码
 | ||
|         config.Heart = 全局变量_心跳时间
 | ||
|         config.TaskLimit = 全局变量_进程限制
 | ||
|         config.AppLimit = 全局变量_应用限制
 | ||
|         config.Keyword = 全局变量_关键字采集
 | ||
|         config.InterceptTimeInterval = 全局变量_拦截记录间隔
 | ||
| 
 | ||
| 
 | ||
|         If 全局变量_关键字心跳时间 = "" OrElse 全局变量_关键字心跳时间 < 1000 Then
 | ||
|             config.KeywordHeart = 60
 | ||
|         Else
 | ||
|             config.KeywordHeart = CInt(全局变量_关键字心跳时间) / 1000
 | ||
|         End If
 | ||
| 
 | ||
|         If 全局变量_心跳时间 = "" OrElse 全局变量_心跳时间 < 1000 Then
 | ||
|             config.Heart = 60
 | ||
|         Else
 | ||
|             config.Heart = CInt(全局变量_心跳时间) / 1000
 | ||
|         End If
 | ||
| 
 | ||
|         Dim newJsonString As String = serializer.Serialize(config)
 | ||
| 
 | ||
|         Await SaveFile("device.json", {newJsonString})
 | ||
| 
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 初始化配置
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function InitSetting() As Task(Of Boolean)
 | ||
|         ' 读取配置项文件路径
 | ||
|         Dim filePath As String = "C:\ProgramData\Vls\device.json"
 | ||
|         If Not File.Exists(filePath) Then
 | ||
|             MessageBox.Show("配置文件不存在,请在软件后台手动设置机器序号!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return False
 | ||
|         End If
 | ||
|         ' 读取所有行
 | ||
|         Dim jsonString As String = File.ReadAllText(filePath)
 | ||
|         Dim config As SetConfig = serializer.Deserialize(Of SetConfig)(jsonString)
 | ||
| 
 | ||
|         ' 第一行:机器序号
 | ||
|         Dim machineId As String = ""
 | ||
|         If config IsNot Nothing AndAlso Not config.MachineId = "" Then
 | ||
|             machineId = config.MachineId.Trim()
 | ||
|         End If
 | ||
| 
 | ||
|         If String.IsNullOrEmpty(machineId) Then
 | ||
|             MessageBox.Show("当前机器序号为空,请在软件后台手动设置机器序号!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return False
 | ||
|         End If
 | ||
| 
 | ||
|         ' 将第一行写入 TextBox1 并赋值给全局变量
 | ||
|         TextBox1.Text = machineId
 | ||
|         全局变量_id = machineId
 | ||
| 
 | ||
|         ' 第二行:其它配置,写入 TextBox3(若没有第二行,则保持空)
 | ||
|         If Not config.Heart = "" Then
 | ||
|             TextBox3.Text = config.Heart.Trim()
 | ||
|             全局变量_心跳时间 = CInt(config.Heart.Trim()) * 1000
 | ||
|         Else
 | ||
|             TextBox3.Text = ""
 | ||
|         End If
 | ||
| 
 | ||
|         '第三行:关键字心跳'
 | ||
|         If Not config.KeywordHeart = "" Then
 | ||
|             全局变量_关键字心跳时间 = CInt(config.KeywordHeart.Trim) * 1000
 | ||
|         Else
 | ||
|             全局变量_关键字心跳时间 = 60 * 1000
 | ||
|         End If
 | ||
| 
 | ||
|         If 全局变量_id = "" Or 全局变量_心跳时间 = "" OrElse 全局变量_关键字心跳时间 = "" Then
 | ||
|             MessageBox.Show("您的机器号或心跳时间未正确填写呢?", "Err", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Return False
 | ||
|         End If
 | ||
| 
 | ||
|         全局变量_进程限制 = config.TaskLimit
 | ||
|         全局变量_应用限制 = config.AppLimit
 | ||
|         全局变量_拦截记录间隔 = config.InterceptTimeInterval
 | ||
| 
 | ||
|         Return True
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 获取最后的版本
 | ||
|     ''' </summary>
 | ||
|     ''' <returns></returns>
 | ||
|     Public Async Function GetLastVersion() As Task(Of AppVersion)
 | ||
|         Dim versionResult As AppVersion = New AppVersion
 | ||
| 
 | ||
|         Try
 | ||
|             Dim url As String = $"{ApiEndPoint}/mm-app-version/last"
 | ||
| 
 | ||
|             Dim response As HttpResponseMessage = Await client.GetAsync(url)
 | ||
|             ' 发送请求并获取响应
 | ||
|             If response.IsSuccessStatusCode Then
 | ||
|                 Dim responseContent As String = Await response.Content.ReadAsStringAsync()
 | ||
|                 versionResult = serializer.Deserialize(Of AppVersion)(responseContent)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("获取程序版本失败:" & ex.StackTrace)
 | ||
|         End Try
 | ||
| 
 | ||
|         Return versionResult
 | ||
|     End Function
 | ||
| 
 | ||
|     Public Async Function JudgeAppVersion() As Task
 | ||
|         Try
 | ||
|             Dim app As AppVersion = Await GetLastVersion()
 | ||
|             Dim filePath As String = "C:\ProgramData\Vls\Load.exe"
 | ||
| 
 | ||
|             '版本不一致'
 | ||
|             If app IsNot Nothing AndAlso Not app.version = 全局变量_程序版本 AndAlso Not app.path = "" Then
 | ||
|                 Await Updater.StartUpdateAsync(filePath, app.path)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             Logger.Error("获取版本失败" & ex.StackTrace)
 | ||
|         End Try
 | ||
|     End Function
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 重启电脑
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="sender"></param>
 | ||
|     ''' <param name="e"></param>
 | ||
|     Private Sub btn_restart_Click(sender As Object, e As EventArgs)
 | ||
|         RebootComputer(True)
 | ||
|     End Sub
 | ||
| 
 | ||
|     ''' <summary>
 | ||
|     ''' 重启计算机
 | ||
|     ''' </summary>
 | ||
|     ''' <param name="force">如果为 True,则强制关闭正在运行的应用程序。</param>
 | ||
|     ''' <remarks>
 | ||
|     ''' 需要提升的权限才能重启计算机。
 | ||
|     ''' </remarks>
 | ||
|     Sub RebootComputer(force As Boolean)
 | ||
|         Dim si As New ProcessStartInfo("shutdown", "/r /t 30")
 | ||
|         si.CreateNoWindow = True
 | ||
|         si.UseShellExecute = True  ' 需要设置为 True 才能使用 Verb
 | ||
|         If force Then
 | ||
|             si.Arguments &= " /f"  ' 强制关闭应用程序
 | ||
|         End If
 | ||
| 
 | ||
|         Try
 | ||
|             Dim p As Process = Process.Start(si)
 | ||
|             p.WaitForExit() ' 等待进程结束,确保重启命令已发送
 | ||
|         Catch ex As System.ComponentModel.Win32Exception
 | ||
|             If ex.NativeErrorCode = 5 Then ' 5 是拒绝访问的错误代码
 | ||
|                 MessageBox.Show("需要管理员权限才能重启计算机。", "权限不足", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             Else
 | ||
|                 MessageBox.Show("重启计算机失败: " & ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|             End If
 | ||
|         Catch ex As Exception
 | ||
|             MessageBox.Show("重启计算机失败: " & ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
 | ||
|         End Try
 | ||
|     End Sub
 | ||
| End Class |