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
}
}