1 Commits
Author SHA1 Message Date
ded_ikar e7ea83daa0 fix QoS 2026-05-04 01:50:35 +05:00
10 changed files with 309 additions and 103 deletions
+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
-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();
}
} }
} }
+15
View File
@@ -1,5 +1,6 @@
using System; using System;
using System.Windows; using System.Windows;
using System.Windows.Input;
using QoSManager.Services; using QoSManager.Services;
namespace QoSManager.Views namespace QoSManager.Views
@@ -22,5 +23,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();
}
} }
} }