7 Commits
Author SHA1 Message Date
ded_ikar e7ea83daa0 fix QoS 2026-05-04 01:50:35 +05:00
ded_ikar ac895d964a Finish merge with remote changes 2026-04-29 15:34:58 +05:00
ded_ikar 3a0bb21323 Add unsupported Windows version handling 2026-04-29 15:29:39 +05:00
ded_ikar d6541f309e Merge pull request 'Обновить README.md' (#1) from fresa-patch-1 into main
Reviewed-on: #1
2026-04-22 14:24:39 +00:00
ded_ikar 29311e06a3 Add Build/ folder to gitignore 2026-04-22 18:46:12 +05:00
ded_ikar 0b7d2927b7 Обновить README.md 2026-04-22 13:41:18 +00:00
fresa ef802d45b4 Обновить README.md 2026-04-22 12:26:28 +00:00
16 changed files with 518 additions and 110 deletions
BIN
View File
Binary file not shown.
+14
View File
@@ -25,6 +25,20 @@ namespace QoSManager
{ {
base.OnStartup(e); base.OnStartup(e);
// Проверка версии Windows
var versionService = new WindowsVersionService();
var windowsInfo = versionService.GetWindowsInfo();
if (!windowsInfo.IsQoSSupported)
{
var warningWindow = new UnsupportedVersionWindow(windowsInfo);
warningWindow.ShowDialog();
// Always exit on unsupported version
Shutdown();
return;
}
// Проверка административных прав // Проверка административных прав
if (!IsAdministrator()) if (!IsAdministrator())
{ {
+1 -1
View File
@@ -11,7 +11,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Resources\icon.ico</ApplicationIcon> <ApplicationIcon>Resources\icon.ico</ApplicationIcon>
<!-- Default optimization properties --> <!-- Basic optimization -->
<DebugType>none</DebugType> <DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols> <DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize> <Optimize>true</Optimize>
+5 -6
View File
@@ -11,18 +11,17 @@
- ✅ Создание QoS-политик для процессов - ✅ Создание QoS-политик для процессов
- ✅ Удаление существующих политик - ✅ Удаление существующих политик
- ✅ Просмотр списка всех политик с нумерацией - ✅ Просмотр списка всех политик с нумерацией
- ✅ Приоритезация трафика (DSCP 1-63) - ✅ Приоритизация трафика (DSCP 1-63)
- ✅ Автоматический конвертер DSCP ↔ TOS значений - ✅ Автоматический конвертер DSCP ↔ TOS значений
- ✅ Современный темный интерфейс с разделителями - ✅ Современный темный интерфейс с разделителями
- ✅ Автоматическое масштабирование под разрешение экрана - ✅ Автоматическое масштабирование под разрешение экрана
- ✅ Логирование действий (отключаемое) (отключаемое) - ✅ Логирование действий (отключаемое)
- ✅ Защита от случайного редактирования полей - ✅ Защита от случайного редактирования полей
## Требования ## Требования
- Windows 10/11 Pro/Enterprise/Education (Home версии не поддерживаются) - Windows 10/11 Pro/Enterprise/Education (Home версии не поддерживаются)
- .NET 8.0 Runtime (для portable версии) - .NET 8.0 Runtime (для portable версии)
- Административные права
## Сборка ## Сборка
@@ -125,9 +124,9 @@ QoSM/
### 📦 Standalone версия (рекомендуется) ### 📦 Standalone версия (рекомендуется)
- Полностью автономная программа - Полностью автономная программа
- Работает на любом Windows 10/11 - Работает на любой Windows 10/11
- Размер: ~72 МБ (один exe файл) - Размер: ~70 МБ (один exe файл)
- Просто скопируйте QoSManager.exe и запускайте - Просто рпаспакуйте QoSManager.exe и запускайте
### ⚡ Portable версия ### ⚡ Portable версия
- Требует установленный .NET 8 Runtime - Требует установленный .NET 8 Runtime
+60 -7
View File
@@ -108,7 +108,7 @@ namespace QoSManager.Services
private string GetPolicyStore() private string GetPolicyStore()
{ {
return $"GPO:{Environment.MachineName}"; return "localhost";
} }
private static string EscapePowerShellString(string value) private static string EscapePowerShellString(string value)
@@ -251,7 +251,7 @@ namespace QoSManager.Services
var escapedName = EscapePowerShellString(policy.Name); var escapedName = EscapePowerShellString(policy.Name);
var escapedProcess = EscapePowerShellString(policy.Process); var escapedProcess = EscapePowerShellString(policy.Process);
var escapedStore = EscapePowerShellString(GetPolicyStore()); var escapedStore = EscapePowerShellString(GetPolicyStore());
var command = $"New-NetQosPolicy -Name '{escapedName}' -AppPathNameMatchCondition '{escapedProcess}' -DSCPAction {policy.DSCP} -PolicyStore '{escapedStore}'"; var command = $"New-NetQosPolicy -Name '{escapedName}' -AppPathNameMatchCondition '{escapedProcess}' -DSCPAction {policy.DSCP} -PolicyStore '{escapedStore}' -NetworkProfile All";
var encodedCommand = Convert.ToBase64String(Encoding.Unicode.GetBytes(command)); var encodedCommand = Convert.ToBase64String(Encoding.Unicode.GetBytes(command));
var startInfo = new ProcessStartInfo var startInfo = new ProcessStartInfo
@@ -291,7 +291,7 @@ namespace QoSManager.Services
{ {
try try
{ {
_logger.LogInformation("Refreshing Group Policy to synchronize with gpedit.msc"); LogInformation("Refreshing Group Policy to synchronize with gpedit.msc");
var startInfo = new ProcessStartInfo var startInfo = new ProcessStartInfo
{ {
FileName = "cmd.exe", FileName = "cmd.exe",
@@ -310,19 +310,19 @@ namespace QoSManager.Services
var output = process.StandardOutput.ReadToEnd(); var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd(); var error = process.StandardError.ReadToEnd();
_logger.LogInformation($"Gpupdate output: {output}"); LogInformation($"Gpupdate output: {output}");
if (!string.IsNullOrEmpty(error)) if (!string.IsNullOrEmpty(error))
{ {
_logger.LogInformation($"Gpupdate error: {error}"); LogInformation($"Gpupdate error: {error}");
} }
if (process.ExitCode == 0) if (process.ExitCode == 0)
{ {
_logger.LogInformation("Group Policy updated successfully"); LogInformation("Group Policy updated successfully");
} }
else else
{ {
_logger.LogInformation($"Group Policy update returned exit code: {process.ExitCode}"); LogInformation($"Group Policy update returned exit code: {process.ExitCode}");
} }
} }
} }
@@ -332,6 +332,59 @@ namespace QoSManager.Services
} }
} }
public void RefreshQoSPolicies()
{
try
{
if (_loggingEnabled)
{
LogInformation("Force refreshing QoS policies to ensure they apply after reboot");
}
// Force update Group Policy
RefreshGroupPolicy();
// Restart QoS service to ensure policies apply
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c sc query QWAVE | find \"STATE\" && net stop QWAVE && net start QWAVE || net start QWAVE",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardOutputEncoding = System.Text.Encoding.UTF8,
StandardErrorEncoding = System.Text.Encoding.UTF8
};
using (var process = Process.Start(startInfo))
{
process.WaitForExit();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
LogInformation($"QoS service restart output: {output}");
if (!string.IsNullOrEmpty(error))
{
LogInformation($"QoS service restart error: {error}");
}
if (process.ExitCode == 0)
{
LogInformation("QoS service restarted successfully");
}
else
{
LogInformation($"QoS service restart returned exit code: {process.ExitCode}");
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing QoS policies");
}
}
public void DeletePolicy(string policyName, bool autoRefreshGPO = true) public void DeletePolicy(string policyName, bool autoRefreshGPO = true)
{ {
try try
+85
View File
@@ -0,0 +1,85 @@
using Microsoft.Win32;
using System;
namespace QoSManager.Services
{
public class WindowsVersionService
{
public enum WindowsEdition
{
Home,
Pro,
Enterprise,
Education,
Unknown
}
public class WindowsInfo
{
public WindowsEdition Edition { get; set; }
public string ProductName { get; set; }
public bool IsQoSSupported { get; set; }
public string VersionString { get; set; }
}
public WindowsInfo GetWindowsInfo()
{
var info = new WindowsInfo();
try
{
// Получаем информацию о версии Windows из реестра
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
{
if (key != null)
{
var productName = key.GetValue("ProductName")?.ToString() ?? "Unknown";
info.ProductName = productName;
info.Edition = ParseEdition(productName);
info.IsQoSSupported = IsQoSSupported(info.Edition);
info.VersionString = $"{productName} ({info.Edition})";
}
}
}
catch (Exception ex)
{
info.ProductName = "Error reading version";
info.Edition = WindowsEdition.Unknown;
info.IsQoSSupported = false;
info.VersionString = $"Error: {ex.Message}";
}
return info;
}
private WindowsEdition ParseEdition(string productName)
{
if (string.IsNullOrEmpty(productName))
return WindowsEdition.Unknown;
productName = productName.ToLowerInvariant();
if (productName.Contains("home"))
return WindowsEdition.Home;
if (productName.Contains("pro"))
return WindowsEdition.Pro;
if (productName.Contains("enterprise"))
return WindowsEdition.Enterprise;
if (productName.Contains("education"))
return WindowsEdition.Education;
return WindowsEdition.Unknown;
}
private bool IsQoSSupported(WindowsEdition edition)
{
return edition switch
{
WindowsEdition.Pro => true,
WindowsEdition.Enterprise => true,
WindowsEdition.Education => true,
_ => false
};
}
}
}
-1
View File
@@ -6,7 +6,6 @@
ResizeMode="NoResize" ResizeMode="NoResize"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"
Background="#2D2D2D" Background="#2D2D2D"
WindowStyle="SingleBorderWindow"
BorderBrush="#444444" BorderBrush="#444444"
BorderThickness="1" BorderThickness="1"
FontFamily="Segoe UI" FontFamily="Segoe UI"
+15
View File
@@ -1,4 +1,5 @@
using System.Windows; using System.Windows;
using System.Windows.Input;
namespace QoSManager.Views namespace QoSManager.Views
{ {
@@ -83,5 +84,19 @@ namespace QoSManager.Views
Result = MessageBoxResult.No; Result = MessageBoxResult.No;
Close(); Close();
} }
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Result = MessageBoxResult.Cancel;
Close();
}
} }
} }
+87 -70
View File
@@ -8,74 +8,75 @@
Background="#1E1E1E"> Background="#1E1E1E">
<Grid Margin="20"> <Grid Margin="20">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Заголовок -->
<StackPanel Grid.Row="0" Margin="0,0,0,20"> <!-- Заголовок -->
<Grid> <StackPanel Grid.Row="0" Margin="0,0,0,20">
<Grid.ColumnDefinitions> <Grid>
<ColumnDefinition Width="*"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Text="Управление QoS-политиками Windows" <StackPanel Grid.Column="0">
FontSize="18" <TextBlock Text="Управление QoS-политиками Windows"
FontWeight="SemiBold" FontSize="18"
Foreground="White"/> FontWeight="SemiBold"
<TextBlock Text="Добавляйте, удаляйте и просматривайте политики для отдельных процессов." Foreground="White"/>
FontSize="12" <TextBlock Text="Создавайте и управляйте QoS-политиками для приоритизации сетевого трафика"
Foreground="#A0A0A0" FontSize="12"
Margin="0,5,0,10"/> Foreground="#CCCCCC"
</StackPanel> Margin="0,5,0,0"/>
</StackPanel>
<StackPanel Grid.Column="1"
Orientation="Horizontal" <StackPanel Grid.Column="1"
VerticalAlignment="Top" Orientation="Horizontal"
Margin="20,0,0,0"> VerticalAlignment="Top">
<CheckBox x:Name="LoggingCheckBox" <TextBlock Text="Статус: "
Content="Вести логи" FontSize="12"
Width="120" Foreground="#CCCCCC"
Height="30" VerticalAlignment="Center"/>
Foreground="White" <TextBlock Text="Активно"
VerticalContentAlignment="Center"/> FontSize="12"
</StackPanel> FontWeight="SemiBold"
</Grid> Foreground="#4CAF50"
</StackPanel> VerticalAlignment="Center"/>
</StackPanel>
</Grid>
<!-- Таблица политик --> </StackPanel>
<DataGrid x:Name="PoliciesDataGrid"
Grid.Row="1" <!-- DataGrid -->
AutoGenerateColumns="False" <DataGrid x:Name="PoliciesDataGrid"
CanUserAddRows="False" Grid.Row="1"
CanUserDeleteRows="False" AutoGenerateColumns="False"
CanUserReorderColumns="False" CanUserAddRows="False"
CanUserResizeRows="False" CanUserDeleteRows="False"
IsReadOnly="True" CanUserReorderColumns="False"
BeginningEdit="PoliciesDataGrid_BeginningEdit" CanUserResizeColumns="True"
CellEditEnding="PoliciesDataGrid_CellEditEnding" CanUserResizeRows="False"
GridLinesVisibility="All" CanUserSortColumns="True"
HorizontalGridLinesBrush="#333333" GridLinesVisibility="Horizontal"
VerticalGridLinesBrush="#555555" HorizontalGridLinesBrush="#3C3C3C"
Background="#2D2D2D" VerticalGridLinesBrush="Transparent"
Foreground="White" Background="#1E1E1E"
BorderBrush="#444444" Foreground="White"
BorderThickness="1" BorderBrush="#3C3C3C"
HeadersVisibility="Column" BorderThickness="1"
SelectionMode="Single" HeadersVisibility="Column"
AlternatingRowBackground="#252525" SelectionMode="Single"
RowHeight="30" AlternatingRowBackground="#252525"
MinRowHeight="25" RowHeight="30"
VirtualizingPanel.IsVirtualizing="True" MinRowHeight="25"
VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True"
ScrollViewer.CanContentScroll="True" VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"> ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<DataGrid.ColumnHeaderStyle> <DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader"> <Style TargetType="DataGridColumnHeader">
@@ -129,7 +130,7 @@
Binding="{Binding Name}" Binding="{Binding Name}"
Width="180" Width="180"
IsReadOnly="True"/> IsReadOnly="True"/>
<DataGridTextColumn Header="Процесс / путь" <DataGridTextColumn Header="Процесс"
Binding="{Binding Process}" Binding="{Binding Process}"
Width="*" Width="*"
IsReadOnly="True"/> IsReadOnly="True"/>
@@ -145,8 +146,23 @@
</DataGrid> </DataGrid>
<!-- Настройки -->
<StackPanel x:Name="SettingsPanel"
Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Left"
Margin="0,20,0,10">
<CheckBox x:Name="LoggingCheckBox"
Content="Вести логи"
Width="120"
Height="30"
Foreground="White"
VerticalContentAlignment="Center"/>
</StackPanel>
<!-- Кнопки --> <!-- Кнопки -->
<StackPanel Grid.Row="2" <StackPanel Grid.Row="3"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,20,0,0"> Margin="0,20,0,0">
@@ -172,6 +188,7 @@
Margin="0,0,10,0" Margin="0,0,10,0"
Style="{StaticResource DarkButtonStyle}"/> Style="{StaticResource DarkButtonStyle}"/>
<Button x:Name="LogButton" <Button x:Name="LogButton"
Content="Открыть лог" Content="Открыть лог"
Width="100" Width="100"
+89 -5
View File
@@ -1,9 +1,15 @@
using System; using System;
using System.Collections;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Data;
using QoSManager.Models; using QoSManager.Models;
using QoSManager.Services; using QoSManager.Services;
@@ -14,7 +20,8 @@ namespace QoSManager.Views
private readonly QoSService _qosService; private readonly QoSService _qosService;
private readonly LoggingService _loggingService; private readonly LoggingService _loggingService;
private readonly ObservableCollection<QoSPolicy> _policies; private readonly ObservableCollection<QoSPolicy> _policies;
private bool _loggingEnabled = true; private bool _loggingEnabled = false;
private bool _isInitialized = false;
public MainWindow() public MainWindow()
{ {
@@ -41,9 +48,22 @@ namespace QoSManager.Views
// Initialize checkbox state // Initialize checkbox state
LoggingCheckBox.IsChecked = _loggingEnabled; LoggingCheckBox.IsChecked = _loggingEnabled;
// Hide settings panel initially and show it after UI is fully loaded
SettingsPanel.Visibility = Visibility.Collapsed;
// Don't log startup - let user enable logging manually if needed // Don't log startup - let user enable logging manually if needed
LoadPolicies(); LoadPolicies();
// Show settings panel and mark initialization as complete after UI loads
Dispatcher.BeginInvoke(() => {
// Always show checkboxes panel with current settings state
SettingsPanel.Visibility = Visibility.Visible;
_isInitialized = true;
// Auto-refresh QoS policies disabled on startup to prevent unwanted behavior
// User must manually enable auto-refresh if needed
});
} }
public ObservableCollection<QoSPolicy> Policies => _policies; public ObservableCollection<QoSPolicy> Policies => _policies;
@@ -65,7 +85,7 @@ namespace QoSManager.Views
{ {
try try
{ {
// Load logging preference from Properties.Settings // Load preferences from Properties.Settings
_loggingEnabled = Properties.Settings.Default.EnableLogging; _loggingEnabled = Properties.Settings.Default.EnableLogging;
} }
catch catch
@@ -78,7 +98,7 @@ namespace QoSManager.Views
{ {
try try
{ {
// Save logging preference to Properties.Settings // Save preferences to Properties.Settings
Properties.Settings.Default.EnableLogging = _loggingEnabled; Properties.Settings.Default.EnableLogging = _loggingEnabled;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
} }
@@ -215,6 +235,40 @@ namespace QoSManager.Views
LoadPolicies(); LoadPolicies();
} }
private void RefreshPoliciesButton_Click(object sender, RoutedEventArgs e)
{
try
{
_loggingService.LogInformation("Force refreshing QoS policies by user request", _loggingEnabled);
// Show progress message
CustomMessageBox.Show(
"Выполняется принудительное перечитывание QoS политик...\n\n" +
"Это может занять несколько секунд.\n" +
"После обновления может потребоваться перезапуск приложений.",
"Перечитывание политик", MessageBoxButton.OK, MessageBoxImage.Information);
// Force refresh QoS policies
_qosService.RefreshQoSPolicies();
// Reload policies list
LoadPolicies();
_loggingService.LogInformation("QoS policies refreshed successfully", _loggingEnabled);
// Show success message
CustomMessageBox.Show(
"QoS политики перечитаны",
"Успешно", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
_loggingService.LogError($"Error refreshing QoS policies: {ex.Message}", _loggingEnabled);
CustomMessageBox.Show($"Ошибка при перечитывании QoS политик:\n\n{ex.Message}",
"Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void LogButton_Click(object sender, RoutedEventArgs e) private void LogButton_Click(object sender, RoutedEventArgs e)
{ {
try try
@@ -235,23 +289,53 @@ namespace QoSManager.Views
_loggingEnabled = true; _loggingEnabled = true;
_qosService.SetLoggingEnabled(_loggingEnabled); _qosService.SetLoggingEnabled(_loggingEnabled);
((App)Application.Current).SetLoggingEnabled(_loggingEnabled); ((App)Application.Current).SetLoggingEnabled(_loggingEnabled);
_loggingService.LogInformation("Логирование включено", _loggingEnabled); if (_isInitialized)
{
_loggingService.LogInformation("Логирование включено", true);
}
} }
private void LoggingCheckBox_Unchecked(object sender, RoutedEventArgs e) private void LoggingCheckBox_Unchecked(object sender, RoutedEventArgs e)
{ {
// Log the disable action before actually disabling // Log the disable action before actually disabling
_loggingService.LogInformation("Логирование отключено пользователем", _loggingEnabled); if (_isInitialized && _loggingEnabled)
{
_loggingService.LogInformation("Логирование отключено пользователем", true);
}
_loggingEnabled = false; _loggingEnabled = false;
_qosService.SetLoggingEnabled(_loggingEnabled); _qosService.SetLoggingEnabled(_loggingEnabled);
((App)Application.Current).SetLoggingEnabled(_loggingEnabled); ((App)Application.Current).SetLoggingEnabled(_loggingEnabled);
} }
private void ExitButton_Click(object sender, RoutedEventArgs e) private void ExitButton_Click(object sender, RoutedEventArgs e)
{ {
Close(); Close();
} }
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
DragMove();
}
}
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
private void MaximizeButton_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
{ {
SaveSettings(); SaveSettings();
+11 -11
View File
@@ -1,23 +1,23 @@
<Window x:Class="QoSManager.Views.PolicyEditWindow" <Window x:Class="QoSManager.Views.PolicyEditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Создание QoS-политики" Title="Создание QoS-политики"
Height="320" Width="500" Height="320" Width="500"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
Background="#1E1E1E" Background="#1E1E1E"
ResizeMode="NoResize"> ResizeMode="NoResize">
<Grid Margin="20"> <Grid Margin="20">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/> <ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
+15 -1
View File
@@ -1,6 +1,7 @@
using System; using System;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Win32; using Microsoft.Win32;
using QoSManager.Models; using QoSManager.Models;
using QoSManager.Services; using QoSManager.Services;
@@ -134,7 +135,7 @@ namespace QoSManager.Views
if (string.IsNullOrWhiteSpace(ProcessTextBox.Text)) if (string.IsNullOrWhiteSpace(ProcessTextBox.Text))
{ {
CustomMessageBox.Show("Укажите процесс или путь к исполняемому файлу.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error); CustomMessageBox.Show("Укажите имя процесса.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
ProcessTextBox.Focus(); ProcessTextBox.Focus();
return false; return false;
} }
@@ -184,5 +185,18 @@ namespace QoSManager.Views
DSCP = dscpValue DSCP = dscpValue
}; };
} }
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
} }
} }
-6
View File
@@ -8,12 +8,6 @@
Background="#2b2b2b" Background="#2b2b2b"
TextElement.Foreground="White"> TextElement.Foreground="White">
<Window.Resources>
<Style TargetType="Window">
<Setter Property="Foreground" Value="White"/>
</Style>
</Window.Resources>
<Grid Margin="10"> <Grid Margin="10">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
+17 -2
View File
@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input;
using QoSManager.Models; using QoSManager.Models;
namespace QoSManager.Views namespace QoSManager.Views
@@ -30,7 +31,7 @@ namespace QoSManager.Views
var processInfo = new ProcessInfo var processInfo = new ProcessInfo
{ {
Id = process.Id, Id = process.Id,
Name = process.ProcessName, Name = (process.ProcessName + ".exe").ToLower(),
Path = process.MainModule?.FileName ?? "Unknown" Path = process.MainModule?.FileName ?? "Unknown"
}; };
@@ -57,7 +58,7 @@ namespace QoSManager.Views
{ {
if (ProcessesDataGrid.SelectedItem is ProcessInfo selectedProcess) if (ProcessesDataGrid.SelectedItem is ProcessInfo selectedProcess)
{ {
SelectedProcess = selectedProcess.Path; SelectedProcess = selectedProcess.Name;
DialogResult = true; DialogResult = true;
Close(); Close();
} }
@@ -68,5 +69,19 @@ namespace QoSManager.Views
DialogResult = false; DialogResult = false;
Close(); Close();
} }
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
} }
} }
+78
View File
@@ -0,0 +1,78 @@
<Window x:Class="QoSManager.Views.UnsupportedVersionWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Неподдерживаемая версия Windows" Height="520" Width="580"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
Background="#2D2D30">
<Grid Margin="25">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Заголовок с иконкой -->
<StackPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,25">
<TextBlock Text="⚠️" FontSize="36" Margin="0,0,15,0" VerticalAlignment="Center"/>
<TextBlock Text="Неподдерживаемая версия Windows"
FontSize="22"
FontWeight="Bold"
Foreground="#E74C3C"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Основное сообщение -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="5">
<TextBlock TextWrapping="Wrap" FontSize="14" LineHeight="24" Margin="0,0,0,20">
<Run Text="Обнаружена версия Windows:" FontWeight="Bold"/>
<LineBreak/>
<Run x:Name="VersionText" Text="{Binding VersionString}" Foreground="#E67E22" FontWeight="Bold"/>
</TextBlock>
<TextBlock TextWrapping="Wrap" FontSize="14" LineHeight="24" Margin="0,0,0,20">
<Run Text="QoS Manager не работает на Windows Home версиях, так как они не поддерживают Group Policy и QoS политики."/>
</TextBlock>
<Border Background="#34495E" CornerRadius="6" Padding="18" Margin="0,0,0,20">
<StackPanel>
<TextBlock Text="Что не поддерживается в Windows Home:" FontWeight="Bold" FontSize="15" Margin="0,0,0,12"/>
<TextBlock Text="• Group Policy Editor (gpedit.msc)" FontSize="14" Margin="10,0,0,8"/>
<TextBlock Text="• PowerShell модуль NetQosPolicy" FontSize="14" Margin="10,0,0,8"/>
<TextBlock Text="• QoS политики на уровне ОС" FontSize="14" Margin="10,0,0,0"/>
</StackPanel>
</Border>
<TextBlock TextWrapping="Wrap" FontSize="14" LineHeight="24" Margin="0,0,0,20">
<Run Text="Для работы приложения требуется:" FontWeight="Bold"/>
</TextBlock>
<Border Background="#27AE60" CornerRadius="6" Padding="18">
<StackPanel>
<TextBlock Text="Поддерживаемые версии Windows:" FontWeight="Bold" FontSize="15" Margin="0,0,0,12" Foreground="White"/>
<TextBlock Text="• Windows 10/11 Pro" FontSize="14" Margin="10,0,0,8" Foreground="White"/>
<TextBlock Text="• Windows 10/11 Enterprise" FontSize="14" Margin="10,0,0,8" Foreground="White"/>
<TextBlock Text="• Windows 10/11 Education" FontSize="14" Margin="10,0,0,0" Foreground="White"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<!-- Buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="2" Margin="0,25,0,0">
<Button x:Name="ExitButton" Content="Выход"
Background="#C0392B"
Foreground="White"
FontSize="16"
FontWeight="Bold"
Padding="40,15"
MinWidth="120"
MinHeight="45"
BorderThickness="0"
Cursor="Hand"
Click="ExitButton_Click"/>
</StackPanel>
</Grid>
</Window>
+41
View File
@@ -0,0 +1,41 @@
using System;
using System.Windows;
using System.Windows.Input;
using QoSManager.Services;
namespace QoSManager.Views
{
public partial class UnsupportedVersionWindow : Window
{
private readonly WindowsVersionService.WindowsInfo _windowsInfo;
public UnsupportedVersionWindow(WindowsVersionService.WindowsInfo windowsInfo)
{
InitializeComponent();
_windowsInfo = windowsInfo;
DataContext = this;
VersionText.Text = _windowsInfo.VersionString;
}
private void ExitButton_Click(object sender, RoutedEventArgs e)
{
// User decided to exit
DialogResult = false;
Close();
}
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
}
}