PortCheck/Form1.cs

425 lines
20 KiB
C#
Raw Normal View History

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Linq;
using Microsoft.Win32; // Для работы с реестром
using System.Diagnostics; // Для Process
using EthernetSpeedMonitor;
using System.IO;
namespace PortCheck
{
public partial class Form1 : Form
{
private static readonly string logFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"EthernetMonitor.log");
private static readonly string speedLogFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"EthernetSpeed.txt");
private void LogSpeedChange(string oldSpeed, string newSpeed, string interfaceName)
{
try
{
string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}: " +
$"Интерфейс: {interfaceName}, " +
$"Изменение скорости: {oldSpeed} -> {newSpeed}";
// Добавляем запись в файл логирования скорости
File.AppendAllText(speedLogFilePath, logEntry + Environment.NewLine);
// Также добавляем в общий лог
LogMessage($"Зафиксировано изменение скорости Ethernet: {oldSpeed} -> {newSpeed} на интерфейсе {interfaceName}");
}
catch (Exception ex)
{
// Логируем ошибку записи в основной лог
LogMessage($"Ошибка при записи в файл логирования скорости: {ex.Message}");
Debug.WriteLine($"Error writing to speed log: {ex.Message}");
}
}
private string previousSpeedInfo = string.Empty;
private void LogMessage(string message)
{
try
{
File.AppendAllText(logFilePath,
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}: {message}{Environment.NewLine}");
}
catch
{
// Игнорируем ошибки записи лога
}
}
// Метод для отображения неотложного уведомления
private void ShowUrgentNotification(string message, string title)
{
// Логируем сообщение
LogMessage($"ВАЖНО: {title} - {message}");
// Настраиваем и показываем уведомление
notifyIconMain.BalloonTipTitle = title;
notifyIconMain.BalloonTipText = message;
notifyIconMain.BalloonTipIcon = ToolTipIcon.Warning; // Используем иконку предупреждения
// Показываем на 10 секунд (10000 мс)
notifyIconMain.ShowBalloonTip(10000);
}
// Ключ реестра для автозапуска
private const string AutorunRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
// Имя значения в реестре (используем имя приложения)
private readonly string AutorunValueName = Application.ProductName;
public Form1()
{
InitializeComponent();
}
// --- События формы ---
private void Form1_Load(object sender, EventArgs e)
{
try
{
// Скрываем форму при запуске
this.Visible = false;
this.Hide();
// Явно устанавливаем видимость иконки в трее
if (notifyIconMain.Icon == null)
{
// Попытка загрузить иконку из ресурсов
try
{
notifyIconMain.Icon = Properties.Resources.Network_37044; // Если иконка в ресурсах проекта
}
catch
{
// Если не получилось, используем значок приложения
notifyIconMain.Icon = this.Icon;
// Если и это не сработало, используем стандартную иконку
if (notifyIconMain.Icon == null)
notifyIconMain.Icon = SystemIcons.Application;
}
}
notifyIconMain.Visible = true;
// Первоначальная проверка скорости
UpdateNetworkSpeedInfo();
// Запускаем таймер
timerUpdate.Enabled = true;
LogMessage("Приложение запущено");
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при инициализации: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Скрытие окна вместо закрытия по кнопке "X" (если бы оно было видимым)
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Если закрытие инициировано пользователем (а не системой или Application.Exit())
// Можно добавить логику, чтобы не закрывать, а сворачивать,
// но т.к. форма невидима, лучше обработать выход через меню.
// Важно убрать иконку при реальном выходе!
if (e.CloseReason == CloseReason.UserClosing)
{
// Если хочешь, чтобы крестик просто сворачивал (не актуально для невидимой формы)
// e.Cancel = true;
// this.WindowState = FormWindowState.Minimized;
// this.Hide();
}
else // При Application.Exit() или выключении Windows
{
CleanupNotifyIcon();
}
}
// --- Логика получения скорости ---
private void UpdateNetworkSpeedInfo()
{
try
{
// Получаем информацию о скорости и имя интерфейса
var speedInfo = GetActiveEthernetSpeedInfo();
string currentSpeedInfo = speedInfo.Speed;
string interfaceName = speedInfo.InterfaceName;
// Проверяем, изменилась ли скорость
if (!string.IsNullOrEmpty(previousSpeedInfo) &&
!currentSpeedInfo.Equals(previousSpeedInfo, StringComparison.OrdinalIgnoreCase) &&
currentSpeedInfo != "Disconnected" && previousSpeedInfo != "Disconnected")
{
// Отправляем неотложное уведомление о смене скорости
ShowUrgentNotification(
$"Скорость порта изменилась с {previousSpeedInfo} на {currentSpeedInfo}",
"Изменение скорости Ethernet");
// Записываем изменение скорости в специальный лог
LogSpeedChange(previousSpeedInfo, currentSpeedInfo, interfaceName);
}
// Обновляем предыдущее значение скорости
previousSpeedInfo = currentSpeedInfo;
// Обновляем текст подсказки иконки
notifyIconMain.Text = $"Ethernet: {currentSpeedInfo}";
}
catch (Exception ex)
{
// Логируем ошибку
LogMessage($"Ошибка при обновлении информации о скорости: {ex.Message}");
Debug.WriteLine($"Error updating speed: {ex.Message}");
notifyIconMain.Text = "Ethernet: Error";
}
}
// Создаем структуру для возврата информации об интерфейсе и скорости
private struct EthernetSpeedInfo
{
public string Speed { get; set; }
public string InterfaceName { get; set; }
}
private EthernetSpeedInfo GetActiveEthernetSpeedInfo()
{
var result = new EthernetSpeedInfo
{
Speed = "Disconnected",
InterfaceName = "Unknown"
};
// Ищем активные Ethernet адаптеры
var activeEthernet = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(ni =>
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet && // Тип Ethernet
ni.OperationalStatus == OperationalStatus.Up && // Статус "включен"
ni.Supports(NetworkInterfaceComponent.IPv4) && // Поддерживает IPv4
ni.GetIPProperties().GatewayAddresses.Any()); // Имеет шлюз
if (activeEthernet == null)
{
// Если не нашли по шлюзу, попробуем просто первый активный Ethernet
activeEthernet = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(ni =>
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
ni.OperationalStatus == OperationalStatus.Up);
}
if (activeEthernet != null)
{
// Сохраняем имя интерфейса
result.InterfaceName = activeEthernet.Name;
// Скорость в битах в секунду
long speedBps = activeEthernet.Speed;
if (speedBps <= 0)
{
result.Speed = "N/A"; // Скорость не определена
return result;
}
// Переводим в Мбит/с
long speedMbps = speedBps / 1_000_000;
// Простое округление до стандартных значений для наглядности
if (speedMbps >= 9500) result.Speed = "10 Gbps";
else if (speedMbps >= 4500) result.Speed = "5 Gbps";
else if (speedMbps >= 2000) result.Speed = "2.5 Gbps";
else if (speedMbps >= 900) result.Speed = "1 Gbps"; // Гигабит
else if (speedMbps >= 90) result.Speed = "100 Mbps"; // 100 Мегабит
else if (speedMbps >= 9) result.Speed = "10 Mbps"; // 10 Мегабит
else result.Speed = $"{speedMbps} Mbps"; // Если нестандартная скорость
}
return result;
}
private string GetActiveEthernetSpeed()
{
// Ищем активные Ethernet адаптеры
var activeEthernet = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(ni =>
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet && // Тип Ethernet
ni.OperationalStatus == OperationalStatus.Up && // Статус "включен"
ni.Supports(NetworkInterfaceComponent.IPv4) && // Поддерживает IPv4 (часто хороший индикатор активности)
ni.GetIPProperties().GatewayAddresses.Any()); // Имеет шлюз (очень хороший индикатор основного подключения)
if (activeEthernet == null)
{
// Если не нашли по шлюзу, попробуем просто первый активный Ethernet
activeEthernet = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(ni =>
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
ni.OperationalStatus == OperationalStatus.Up);
}
if (activeEthernet != null)
{
// Скорость в битах в секунду
long speedBps = activeEthernet.Speed;
if (speedBps <= 0)
{
return "N/A"; // Скорость не определена
}
// Переводим в Мбит/с
long speedMbps = speedBps / 1_000_000;
// Простое округление до стандартных значений для наглядности
if (speedMbps >= 9500) return "10 Gbps";
if (speedMbps >= 4500) return "5 Gbps";
if (speedMbps >= 2000) return "2.5 Gbps";
if (speedMbps >= 900) return "1 Gbps"; // Гигабит
if (speedMbps >= 90) return "100 Mbps"; // 100 Мегабит
if (speedMbps >= 9) return "10 Mbps"; // 10 Мегабит
return $"{speedMbps} Mbps"; // Если нестандартная скорость
}
else
{
return "Disconnected"; // Не найдено активного Ethernet адаптера
}
}
// --- Обработчики событий компонентов ---
private void timerUpdate_Tick(object sender, EventArgs e)
{
UpdateNetworkSpeedInfo();
}
private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
{
// Открываем форму настроек
using (SettingsForm settingsForm = new SettingsForm())
{
// Передаем текущие настройки в форму
settingsForm.StartWithWindows = IsAutoStartEnabled();
settingsForm.UpdateIntervalSeconds = timerUpdate.Interval / 1000; // Переводим мс в секунды
if (settingsForm.ShowDialog() == DialogResult.OK)
{
// Применяем настройки из формы
SetAutoStart(settingsForm.StartWithWindows);
timerUpdate.Interval = settingsForm.UpdateIntervalSeconds * 1000; // Переводим секунды в мс
}
}
}
private void checkNowToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateNetworkSpeedInfo(); // Выполняем проверку немедленно
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
// Корректный выход из приложения
CleanupNotifyIcon(); // Убираем иконку перед выходом
Application.Exit();
}
// Двойной клик по иконке тоже может открывать настройки
private void notifyIconMain_MouseDoubleClick(object sender, MouseEventArgs e)
{
settingsToolStripMenuItem_Click(sender, e);
}
// --- Логика автозапуска ---
private bool IsAutoStartEnabled()
{
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(AutorunRegistryKey, false)) // false - только чтение
{
if (key == null) return false;
object value = key.GetValue(AutorunValueName);
// Проверяем, что значение не null и совпадает с путем к нашему приложению
return value != null && value.ToString().Equals(Application.ExecutablePath, StringComparison.OrdinalIgnoreCase);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error checking autorun: {ex.Message}");
return false; // В случае ошибки считаем, что автозапуск отключен
}
}
private void SetAutoStart(bool enable)
{
try
{
// Открываем ключ с правом записи
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(AutorunRegistryKey, true))
{
if (key == null)
{
// Если ключа нет, возможно, его нужно создать (хотя обычно он есть)
// Registry.CurrentUser.CreateSubKey(AutorunRegistryKey); // Потребует повышенных прав? Скорее всего нет для HKCU
// key = Registry.CurrentUser.OpenSubKey(AutorunRegistryKey, true);
// Если создать не удалось или не хочется, просто выходим
Debug.WriteLine($"Registry key '{AutorunRegistryKey}' not found.");
MessageBox.Show($"Не удалось получить доступ к ключу реестра:\n{AutorunRegistryKey}\n\nАвтозапуск не может быть изменен.", "Ошибка реестра", MessageBoxButtons.OK, MessageBoxIcon.Error);
return; // Не можем продолжить
}
if (enable)
{
// Добавляем или обновляем значение
key.SetValue(AutorunValueName, Application.ExecutablePath);
}
else
{
// Удаляем значение, если оно существует
if (key.GetValue(AutorunValueName) != null)
{
key.DeleteValue(AutorunValueName, false); // false - не вызывать исключение, если значения нет
}
}
}
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Нет прав для изменения настроек автозапуска в реестре.", "Ошибка доступа", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch (Exception ex)
{
Debug.WriteLine($"Error setting autorun: {ex.Message}");
MessageBox.Show($"Произошла ошибка при изменении настроек автозапуска:\n{ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// --- Очистка ---
private void CleanupNotifyIcon()
{
if (notifyIconMain != null)
{
notifyIconMain.Visible = false;
notifyIconMain.Dispose();
notifyIconMain = null; // Помогает сборщику мусора
}
}
}
}