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; // Помогает сборщику мусора } } } }