using System; using System.Drawing; using System.IO; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Windows.Forms; using Microsoft.Win32.SafeHandles; using XP.Hardware.RaySource.Comet; using XP.Hardware.RaySource.Comet.Host.Pipe; using XP.Hardware.RaySource.Comet.Host.Properties; using XP.Hardware.RaySource.Comet.Messages; using XP.Hardware.RaySource.Comet.Messages.Responses; namespace XP.Hardware.RaySource.Comet.Host { /// /// XplorePlane Comet Host 主窗体 /// 集成托盘图标、管道通信、PVI 客户端生命周期和功能测试按钮 /// public partial class XplorePlaneCometHost : Form { #region 管道通信常量和字段 /// /// 命令管道名称(客户端写 → Host 读) /// private const string CmdPipeName = "XP.Hardware.RaySource.Comet.Cmd"; /// /// 响应管道名称(Host 写 → 客户端读) /// private const string RspPipeName = "XP.Hardware.RaySource.Comet.Rsp"; /// /// 写入锁,防止命令响应和推送消息交错 /// private static readonly object WriteLock = new object(); /// /// 管道是否已连接,用于控制日志是否推送到管道 /// private volatile bool _isPipeConnected; /// /// 管道轮询定时器 /// private System.Windows.Forms.Timer _pipeTimer; /// /// 命令管道服务端 /// private NamedPipeServerStream _cmdPipe; /// /// 响应管道服务端 /// private NamedPipeServerStream _rspPipe; /// /// 管道读取器 /// private StreamReader _pipeReader; /// /// 管道写入器 /// private StreamWriter _pipeWriter; /// /// 是否正在等待客户端连接 /// private bool _isWaitingConnection; /// /// 异步连接结果(命令管道) /// private IAsyncResult _cmdConnectResult; /// /// 异步连接结果(响应管道) /// private IAsyncResult _rspConnectResult; /// /// Win32 PeekNamedPipe API,用于非阻塞检测管道中是否有可读数据 /// StreamReader.Peek() 在异步模式 NamedPipe 上不可靠: /// 当内部缓冲区为空时,Peek 调用底层同步 Read,异步管道会返回 0 字节, /// 导致 StreamReader 误判为 EOF,后续所有读取永远返回 -1/null /// [DllImport("kernel32.dll", SetLastError = true)] private static extern bool PeekNamedPipe( SafePipeHandle hNamedPipe, IntPtr lpBuffer, uint nBufferSize, IntPtr lpBytesRead, out uint lpTotalBytesAvail, IntPtr lpBytesLeftThisMessage); /// /// 检查命令管道中是否有可读数据(非阻塞) /// private bool HasPipeData() { if (_cmdPipe == null || !_cmdPipe.IsConnected) return false; bool result = PeekNamedPipe( _cmdPipe.SafePipeHandle, IntPtr.Zero, 0, IntPtr.Zero, out uint bytesAvailable, IntPtr.Zero); return result && bytesAvailable > 0; } #endregion #region Comet Timer常量 /// /// 连接状态定时器 /// private System.Windows.Forms.Timer _pviConnectTimer; /// /// 看门狗定时器 /// private System.Windows.Forms.Timer _watchDogTimer; /// /// 心跳闪烁状态(true=绿色,false=灰色) /// private bool _heartbeatToggle; #endregion public XplorePlaneCometHost() { InitializeComponent(); InitializeTrayIcon(); SetupLogger(); SubscribeLocalEvents(); StartPipeLoop(); StartCometPviTimer(); } #region 托盘图标 /// /// 初始化系统托盘图标和右键菜单 /// private void InitializeTrayIcon() { var contextMenu = new ContextMenuStrip(); contextMenu.Items.Add("XplorePlane Comet Host", null, null).Enabled = false; contextMenu.Items.Add(new ToolStripSeparator()); contextMenu.Items.Add("测试窗口|Test(&S)", null, (s, e) => { this.ShowInTaskbar = true; this.Show(); this.WindowState = FormWindowState.Normal; this.Activate(); }); contextMenu.Items.Add("退出|Exit(&X)", null, OnExitClick); _notifyIcon = new NotifyIcon { Icon = Resource.Comet_Host_Icon, Text = "XP.Hardware.RaySource.Comet.Host", Visible = true, ContextMenuStrip = contextMenu }; _notifyIcon.DoubleClick += (s, e) => { this.ShowInTaskbar = true; this.Show(); this.WindowState = FormWindowState.Normal; this.Activate(); }; } #endregion #region 统一日志 /// /// 设置统一日志回调 /// 界面日志始终输出,管道推送仅在管道连接后生效 /// private void SetupLogger() { CometPviClient.SetLogger((level, message, logArgs) => { // 始终输出到界面 string formatted = logArgs != null && logArgs.Length > 0 ? FormatLogMessage(message, logArgs) : message; AppendLog($"[{level}] {formatted}"); // 管道已连接时,同步推送到主进程 if (_isPipeConnected) { var logResponse = new LogResponse { Success = true, PushType = "Log", Level = level.ToString(), Message = message, Args = logArgs != null ? Array.ConvertAll(logArgs, a => a?.ToString() ?? "") : null }; PushNotifier.SendPush(logResponse); } }); } #endregion #region 管道通信 /// /// 启动管道通信:创建管道并开始异步等待连接,启动轮询定时器 /// private void StartPipeLoop() { // 创建管道 _cmdPipe = new NamedPipeServerStream(CmdPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); _rspPipe = new NamedPipeServerStream(RspPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); // 异步等待客户端连接 _cmdConnectResult = _cmdPipe.BeginWaitForConnection(null, null); _rspConnectResult = _rspPipe.BeginWaitForConnection(null, null); _isWaitingConnection = true; AppendLog("[管道] 等待客户端连接..."); // 启动定时器轮询(50ms 间隔) _pipeTimer = new System.Windows.Forms.Timer(); _pipeTimer.Interval = 50; _pipeTimer.Tick += PipeTimer_Tick; _pipeTimer.Start(); } /// /// 是否正在处理管道命令,防止 DoEvents 期间 Timer 重入 /// private bool _isProcessingCommand; /// /// 定时器回调:检查管道连接状态和读取命令 /// private void PipeTimer_Tick(object sender, EventArgs e) { // 防止 HandleInitialize 中 DoEvents 导致的 Timer 重入 if (_isProcessingCommand) return; try { // 阶段1:等待客户端连接 if (_isWaitingConnection) { if (_cmdConnectResult.IsCompleted && _rspConnectResult.IsCompleted) { _cmdPipe.EndWaitForConnection(_cmdConnectResult); _rspPipe.EndWaitForConnection(_rspConnectResult); _pipeReader = new StreamReader(_cmdPipe); _pipeWriter = new StreamWriter(_rspPipe) { AutoFlush = true }; // 初始化推送管理器 PushNotifier.Initialize(_pipeWriter, WriteLock); // 订阅 PVI 推送事件 SubscribePviPushEvents(); _isPipeConnected = true; _isWaitingConnection = false; AppendLog("[管道] 客户端已连接"); } return; } // 阶段2:轮询读取命令 if (!_cmdPipe.IsConnected) { AppendLog("[管道] 客户端已断开"); CleanupPipe(); return; } // 检查管道中是否有可读数据(非阻塞) // 使用 Win32 PeekNamedPipe 替代 StreamReader.Peek() // StreamReader.Peek() 在异步模式 NamedPipe 上会误判 EOF,导致后续命令永远无法读取 if (!HasPipeData()) return; _isProcessingCommand = true; try { string line = _pipeReader.ReadLine(); if (line == null) { AppendLog("[管道] 客户端已关闭连接"); CleanupPipe(); return; } AppendLog($"[管道] 收到命令:{line}", Color.Cyan); var command = MessageSerializer.DeserializeCommand(line); if (command == null) { var errorResponse = new OperationResponse { Success = false, ErrorMessage = "命令反序列化失败" }; WriteResponse(_pipeWriter, errorResponse); return; } var response = CommandDispatcher.Dispatch(command); WriteResponse(_pipeWriter, response); if (CommandDispatcher.ShouldExit) { AppendLog("[管道] 收到断开命令,管道循环退出"); CleanupPipe(); } } finally { _isProcessingCommand = false; } } catch (Exception ex) { AppendLog($"[管道] 通信异常:{ex.Message}", Color.Red); CleanupPipe(); } } /// /// 清理管道资源 /// private void CleanupPipe() { _pipeTimer?.Stop(); _isPipeConnected = false; try { _pipeReader?.Dispose(); } catch { } try { _pipeWriter?.Dispose(); } catch { } try { _cmdPipe?.Dispose(); } catch { } try { _rspPipe?.Dispose(); } catch { } _pipeReader = null; _pipeWriter = null; _cmdPipe = null; _rspPipe = null; } /// /// 线程安全地写入响应到管道 /// private static void WriteResponse(StreamWriter writer, RaySourceResponse response) { var json = MessageSerializer.Serialize(response); lock (WriteLock) { writer.WriteLine(json); } } #endregion #region PVI 管道推送事件 /// /// 订阅 CometPviClient 事件,通过 PushNotifier 推送给主进程 /// private void SubscribePviPushEvents() { CometPviClient.StatusChanged += (sender, status) => { PushNotifier.SendPush(new StatusResponse { Success = true, PushType = "StatusChanged", SetVoltage = status.SetVoltage, ActualVoltage = status.ActualVoltage, SetCurrent = status.SetCurrent, ActualCurrent = status.ActualCurrent, IsXRayOn = status.IsXRayOn, WarmUpStatus = status.WarmUpStatus, VacuumStatus = status.VacuumStatus, StartUpStatus = status.StartUpStatus, AutoCenterStatus = status.AutoCenterStatus, FilamentAdjustStatus = status.FilamentAdjustStatus, IsInterlockActive = status.IsInterlockActive, WatchdogStatus = status.WatchdogStatus, PowerMode = status.PowerMode, TxiStatus = status.TxiStatus }); }; CometPviClient.XRayStateChanged += (sender, isXRayOn) => { PushNotifier.SendPush(new OperationResponse { Success = true, PushType = "XRayStateChanged", Data = isXRayOn }); }; CometPviClient.ErrorOccurred += (sender, errorMessage) => { PushNotifier.SendPush(new OperationResponse { Success = false, PushType = "ErrorOccurred", ErrorMessage = errorMessage }); }; CometPviClient.ConnectionStateChanged += (sender, state) => { PushNotifier.SendPush(new OperationResponse { Success = true, PushType = "ConnectionStateChanged", Data = state.ToString() }); }; } #endregion #region Comet Timer事件 private void StartCometPviTimer() { // 启动连接状态定时器轮询(100ms 间隔) _pviConnectTimer = new System.Windows.Forms.Timer(); _pviConnectTimer.Interval = 100; _pviConnectTimer.Tick += PviConnectTimer_Tick; _pviConnectTimer.Start(); // 启动看门狗定时器轮询(1000ms 间隔) _watchDogTimer = new System.Windows.Forms.Timer(); _watchDogTimer.Interval = 1000; _watchDogTimer.Tick += WatchDogTimer_Tick; _watchDogTimer.Start(); } private void PviConnectTimer_Tick(object sender, EventArgs e) { try { bool bRaySourceConnected = CometPviClient.ReadRaySourceConnectStatus(); // 根据当前连接状态更新标签 var state = CometPviClient.CurrentConnectionState; switch (state) { case PviConnectionState.RaySourceConnected: _lblPviState.Text = "射线源就绪"; _lblPviState.ForeColor = Color.Green; break; case PviConnectionState.VariablesConnected: _lblPviState.Text = "变量已连接"; _lblPviState.ForeColor = Color.DarkGoldenrod; break; case PviConnectionState.ServiceConnected: _lblPviState.Text = "Service已连接"; _lblPviState.ForeColor = Color.Orange; break; default: _lblPviState.Text = "未连接"; _lblPviState.ForeColor = Color.Red; break; } } catch (Exception ex) { AppendLog($"[错误] 连接状态定时器出错失败:{ex.Message}", Color.Red); } } private void WatchDogTimer_Tick(object sender, EventArgs e) { try { CometPviClient.SetWatchDog(); // 心跳闪烁:绿色/灰色交替 _heartbeatToggle = !_heartbeatToggle; _lblHeartbeat.ForeColor = _heartbeatToggle ? Color.LimeGreen : Color.Gray; } catch (Exception ex) { _lblHeartbeat.ForeColor = Color.Red; AppendLog($"[错误] 看门狗定时器出错失败:{ex.Message}", Color.Red); } } #endregion #region 本地界面事件订阅 /// /// 订阅 CometPviClient 事件,将状态输出到界面 /// private void SubscribeLocalEvents() { // 订阅连接状态变更 CometPviClient.ConnectionStateChanged += (sender, state) => { AppendLog($"[连接状态] {state}"); SafeInvoke(() => { switch (state) { case PviConnectionState.RaySourceConnected: _lblConnectionState.Text = "状态: 射线源已连接"; _lblConnectionState.ForeColor = Color.Green; _btnConnectVariables.Enabled = false; _btnDisconnect.Enabled = true; _btnInitialize.Enabled = false; break; case PviConnectionState.ServiceConnected: _lblConnectionState.Text = "状态: PVI Service 已连接"; _lblConnectionState.ForeColor = Color.Orange; _btnConnectVariables.Enabled = true; _btnDisconnect.Enabled = true; _btnInitialize.Enabled = false; break; case PviConnectionState.VariablesConnected: _lblConnectionState.Text = "状态: 变量已连接"; _lblConnectionState.ForeColor = Color.DarkGoldenrod; SetOperationButtonsEnabled(true); _btnConnectVariables.Enabled = false; break; case PviConnectionState.Disconnected: _lblConnectionState.Text = "状态: 已断开"; _lblConnectionState.ForeColor = Color.Red; SetOperationButtonsEnabled(false); _btnConnectVariables.Enabled = false; _btnDisconnect.Enabled = false; _btnInitialize.Enabled = true; break; } }); }; // 订阅状态更新 CometPviClient.StatusChanged += (sender, status) => { AppendLog($"[状态更新] 电压={status.ActualVoltage}kV, 电流={status.ActualCurrent}μA, XRay={status.IsXRayOn}"); }; // 订阅射线状态变更 CometPviClient.XRayStateChanged += (sender, isOn) => { AppendLog($"[射线状态] XRay {(isOn ? "已开启" : "已关闭")}"); }; // 订阅错误事件 CometPviClient.ErrorOccurred += (sender, errorMsg) => { AppendLog($"[错误] {errorMsg}", Color.Red); }; } /// /// 格式化日志消息,替换占位符 /// private string FormatLogMessage(string message, object[] args) { try { string result = message; for (int i = 0; i < args.Length; i++) { result = result.Replace("{" + i + "}", args[i]?.ToString() ?? "null"); } return result; } catch { return message; } } #endregion #region 按钮事件处理 private void OnInitialize(object sender, EventArgs e) { try { _btnInitialize.Enabled = false; AppendLog("[操作] 开始初始化 PVI 连接..."); CometPviClient.Initialize( _txtIpAddress.Text, (int)_nudPort.Value, _txtCpuName.Text, (int)_nudSourcePort.Value, (int)_nudStationNumber.Value); } catch (Exception ex) { AppendLog($"[错误] 初始化失败:{ex.Message}", Color.Red); _btnInitialize.Enabled = true; } } private void OnConnectVariables(object sender, EventArgs e) { try { AppendLog("[操作] 开始连接 PVI 变量..."); CometPviClient.ConnectVariables(); } catch (Exception ex) { AppendLog($"[错误] 连接变量失败:{ex.Message}", Color.Red); } } private void OnDisconnect(object sender, EventArgs e) { try { AppendLog("[操作] 断开连接..."); CometPviClient.Disconnect(); } catch (Exception ex) { AppendLog($"[错误] 断开连接失败:{ex.Message}", Color.Red); } } private void OnTurnOn(object sender, EventArgs e) { try { AppendLog("[操作] 开启高压..."); CometPviClient.TurnOn(); AppendLog("[操作] TurnOn 命令已发送"); } catch (Exception ex) { AppendLog($"[错误] TurnOn 失败:{ex.Message}", Color.Red); } } private void OnTurnOff(object sender, EventArgs e) { try { AppendLog("[操作] 关闭高压..."); CometPviClient.TurnOff(); AppendLog("[操作] TurnOff 命令已发送"); } catch (Exception ex) { AppendLog($"[错误] TurnOff 失败:{ex.Message}", Color.Red); } } private void OnSetVoltage(object sender, EventArgs e) { try { float voltage = (float)_nudVoltage.Value; AppendLog($"[操作] 设置电压:{voltage} kV"); CometPviClient.SetVoltage(voltage); AppendLog($"[操作] SetVoltage 命令已发送,电压={voltage}kV"); } catch (Exception ex) { AppendLog($"[错误] SetVoltage 失败:{ex.Message}", Color.Red); } } private void OnSetCurrent(object sender, EventArgs e) { try { float current = (float)_nudCurrent.Value; AppendLog($"[操作] 设置电流:{current} μA"); CometPviClient.SetCurrent(current); AppendLog($"[操作] SetCurrent 命令已发送,电流={current}μA"); } catch (Exception ex) { AppendLog($"[错误] SetCurrent 失败:{ex.Message}", Color.Red); } } private void OnReadVoltage(object sender, EventArgs e) { try { float voltage = CometPviClient.ReadVoltage(); AppendLog($"[读取] 实际电压:{voltage} kV"); } catch (Exception ex) { AppendLog($"[错误] ReadVoltage 失败:{ex.Message}", Color.Red); } } private void OnReadCurrent(object sender, EventArgs e) { try { float current = CometPviClient.ReadCurrent(); AppendLog($"[读取] 实际电流:{current} μA"); } catch (Exception ex) { AppendLog($"[错误] ReadCurrent 失败:{ex.Message}", Color.Red); } } private void OnReadSystemStatus(object sender, EventArgs e) { try { var status = CometPviClient.ReadSystemStatus(); AppendLog("========== 系统状态 =========="); AppendLog($" 设定电压: {status.SetVoltage} kV | 实际电压: {status.ActualVoltage} kV"); AppendLog($" 设定电流: {status.SetCurrent} μA | 实际电流: {status.ActualCurrent} μA"); AppendLog($" 射线状态: {(status.IsXRayOn ? "开启" : "关闭")}"); AppendLog($" 暖机: {status.WarmUpStatus} | 真空: {status.VacuumStatus}"); AppendLog($" 训机: {status.StartUpStatus} | 自动定心: {status.AutoCenterStatus}"); AppendLog($" 灯丝调整: {status.FilamentAdjustStatus}"); AppendLog($" 连锁: {(status.IsInterlockActive ? "激活" : "未激活")} | 看门狗: {status.WatchdogStatus}"); AppendLog($" 功率模式: {status.PowerMode} | TXI: {status.TxiStatus}"); AppendLog("=============================="); } catch (Exception ex) { AppendLog($"[错误] ReadSystemStatus 失败:{ex.Message}", Color.Red); } } private void OnReadErrors(object sender, EventArgs e) { try { var errors = CometPviClient.ReadErrors(); AppendLog("========== 错误信息 =========="); AppendLog($" 系统错误: {errors.SystemError}"); AppendLog($" HSG错误: {errors.HSGError}"); AppendLog($" 管错误: {errors.TubeError}"); AppendLog($" 管真空错误: {errors.TubeVacError}"); AppendLog("=============================="); } catch (Exception ex) { AppendLog($"[错误] ReadErrors 失败:{ex.Message}", Color.Red); } } private void OnWarmUp(object sender, EventArgs e) { try { AppendLog("[维护] 执行暖机设置...", Color.Yellow); CometPviClient.WarmUp(); AppendLog("[维护] 暖机设置指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] 暖机设置失败:{ex.Message}", Color.Red); } } private void OnTraining(object sender, EventArgs e) { try { AppendLog("[维护] 执行训机设置...", Color.Yellow); CometPviClient.Training(); AppendLog("[维护] 训机设置指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] 训机设置失败:{ex.Message}", Color.Red); } } private void OnFilamentCalibration(object sender, EventArgs e) { try { AppendLog("[维护] 执行灯丝校准...", Color.Yellow); CometPviClient.FilamentCalibration(); AppendLog("[维护] 灯丝校准指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] 灯丝校准失败:{ex.Message}", Color.Red); } } private void OnAutoCenter(object sender, EventArgs e) { try { AppendLog("[维护] 执行全部电压自动定心...", Color.Yellow); CometPviClient.AutoCenter(); AppendLog("[维护] 自动定心指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] 自动定心失败:{ex.Message}", Color.Red); } } private void OnTxiOn(object sender, EventArgs e) { try { AppendLog("[维护] 执行 TXI ON...", Color.Yellow); CometPviClient.TxiOn(); AppendLog("[维护] TXI ON 指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] TXI ON 失败:{ex.Message}", Color.Red); } } private void OnTxiOff(object sender, EventArgs e) { try { AppendLog("[维护] 执行 TXI OFF...", Color.Yellow); CometPviClient.TxiOff(); AppendLog("[维护] TXI OFF 指令已发送", Color.Lime); } catch (Exception ex) { AppendLog($"[错误] TXI OFF 失败:{ex.Message}", Color.Red); } } #endregion #region 辅助方法 /// /// 设置操作类按钮的启用状态 /// private void SetOperationButtonsEnabled(bool enabled) { _btnTurnOn.Enabled = enabled; _btnTurnOff.Enabled = enabled; _btnSetVoltage.Enabled = enabled; _btnSetCurrent.Enabled = enabled; _btnReadVoltage.Enabled = enabled; _btnReadCurrent.Enabled = enabled; _btnReadSystemStatus.Enabled = enabled; _btnReadErrors.Enabled = enabled; _btnWarmUp.Enabled = enabled; _btnTraining.Enabled = enabled; _btnFilamentCalibration.Enabled = enabled; _btnAutoCenter.Enabled = enabled; _btnTxiOn.Enabled = enabled; _btnTxiOff.Enabled = enabled; } /// /// 线程安全地追加日志到 RichTextBox /// private void AppendLog(string message, Color? color = null) { SafeInvoke(() => { var timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); var logLine = $"[{timestamp}] {message}\n"; _rtbLog.SelectionStart = _rtbLog.TextLength; _rtbLog.SelectionLength = 0; _rtbLog.SelectionColor = color ?? Color.LightGreen; _rtbLog.AppendText(logLine); _rtbLog.ScrollToCaret(); }); } /// /// 线程安全地在 UI 线程执行操作 /// private void SafeInvoke(Action action) { if (this.IsDisposed) return; if (this.InvokeRequired) { try { this.Invoke(action); } catch (ObjectDisposedException) { } } else { action(); } } #endregion #region 窗体关闭和退出 /// /// 窗体加载后立即隐藏,默认只显示托盘图标 /// protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.Visible = false; this.ShowInTaskbar = false; this.WindowState = FormWindowState.Minimized; } /// /// 关闭窗体时最小化到托盘,不退出应用 /// private void OnFormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; this.Hide(); this.ShowInTaskbar = false; _notifyIcon.ShowBalloonTip(1000, "XplorePlane Comet Host", "程序已最小化到系统托盘", ToolTipIcon.Info); } } /// /// 托盘菜单退出(已禁用,仅提示) /// private void OnExitClick(object sender, EventArgs e) { MessageBox.Show("XplorePlane Comet Host does not allow manual exit; it will close along with the shutdown of XplorePlane.\r\nXplorePlane Comet Host不允许手动退出,它会跟随XplorePlane的关闭一并退出。", "XplorePlane Comet Host Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } /// /// 强制退出按钮点击 — 需要输入密码 Hexagon 才可退出 /// Force exit button click — requires password "Hexagon" to exit /// private void OnForceExitClick(object sender, EventArgs e) { // 使用自定义输入对话框获取密码 | Use custom input dialog to get password using (var dlg = new ForceExitPasswordDialog()) { if (dlg.ShowDialog(this) == DialogResult.OK && dlg.EnteredPassword == "Hexagon") { AppendLog("[系统] 强制退出已授权,正在退出... | Force exit authorized, exiting...", Color.Orange); ColseForm(sender, e); } else if (dlg.DialogResult == DialogResult.OK) { // 密码错误 | Wrong password MessageBox.Show("密码错误,无法退出。\r\nIncorrect password, cannot exit.", "XplorePlane Comet Host", MessageBoxButtons.OK, MessageBoxIcon.Error); AppendLog("[警告] 强制退出尝试失败:密码错误 | Force exit attempt failed: wrong password", Color.Red); } } } /// /// 托盘菜单退出 /// private void ColseForm(object sender, EventArgs e) { CleanupPipe(); try { CometPviClient.Dispose(); } catch { } if (_notifyIcon != null) { _notifyIcon.Visible = false; _notifyIcon.Dispose(); _notifyIcon = null; } // 移除 FormClosing 拦截,允许窗体真正关闭 this.FormClosing -= OnFormClosing; Application.Exit(); } #endregion } }