Убраны попытки применить переменные окружения к сессии
This commit is contained in:
@@ -42,7 +42,7 @@ dotnet run --project src/Sms.TaskTwo.Avalonia/Sms.TaskTwo.Avalonia.csproj
|
||||
{"SMS_MEAL_SERVER_URL":"URL сервера","SMS_MEAL_API_KEY":"ключ API"}
|
||||
```
|
||||
|
||||
Переменная записывается тем же механизмом, что и остальные, и доступна другим процессам после применения окружения ОС.
|
||||
Переменная записывается тем же механизмом, что и остальные, и доступна другим процессам после перезапуска сессии или приложений.
|
||||
|
||||
## Логирование
|
||||
|
||||
@@ -72,12 +72,10 @@ dotnet run --project src/Sms.TaskTwo.Avalonia/Sms.TaskTwo.Avalonia.csproj
|
||||
### Windows
|
||||
|
||||
- Чтение/запись: реестр `HKEY_CURRENT_USER\Environment`.
|
||||
- **Применить к сессии** (`ReloadEnvironment`): обновляет env текущего процесса и рассылает `WM_SETTINGCHANGE` для других GUI-приложений.
|
||||
|
||||
### Linux
|
||||
|
||||
- Запись в `~/.config/environment.d/` (systemd `KEY=value`).
|
||||
- **Применить к сессии** не поддерживается: переменные подхватываются после перезапуска login-сессии.
|
||||
- Запись в `~/.config/environment.d/` (systemd `KEY=value`); переменные подхватываются после перезапуска login-сессии.
|
||||
|
||||
## Предположения (ТЗ)
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
var managed = LoadManagedFile();
|
||||
managed[name] = value;
|
||||
WriteManagedFileAtomic(managed);
|
||||
System.Environment.SetEnvironmentVariable(name, value);
|
||||
}
|
||||
catch (Exception ex) when (ex is UnauthorizedAccessException or IOException)
|
||||
{
|
||||
@@ -115,8 +114,6 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
|
||||
WriteConfFileAtomic(file, variables);
|
||||
}
|
||||
|
||||
System.Environment.SetEnvironmentVariable(name, null);
|
||||
}
|
||||
catch (Exception ex) when (ex is UnauthorizedAccessException or IOException)
|
||||
{
|
||||
@@ -126,15 +123,6 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
}
|
||||
}
|
||||
|
||||
public EnvironmentReloadResult ReloadEnvironment() =>
|
||||
new()
|
||||
{
|
||||
Success = false,
|
||||
Message =
|
||||
"Применение переменных к сессии в Linux не поддерживается. " +
|
||||
"Значения сохраняются в ~/.config/environment.d/ и подхватываются после перезапуска login-сессии.",
|
||||
};
|
||||
|
||||
private Dictionary<string, string> LoadManagedFile()
|
||||
{
|
||||
if (!File.Exists(_managedFilePath))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32;
|
||||
using Sms.Environment;
|
||||
|
||||
@@ -6,8 +5,6 @@ namespace Sms.Environment.Windows;
|
||||
|
||||
public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
{
|
||||
private const int HWND_BROADCAST = 0xffff;
|
||||
private const int WM_SETTINGCHANGE = 0x001A;
|
||||
private const string EnvironmentKeyPath = "Environment";
|
||||
|
||||
public string? Get(string name) =>
|
||||
@@ -25,8 +22,6 @@ public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath, writable: true)
|
||||
?? Registry.CurrentUser.CreateSubKey(EnvironmentKeyPath, writable: true);
|
||||
key.SetValue(name, value, RegistryValueKind.ExpandString);
|
||||
System.Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.Process);
|
||||
BroadcastEnvironmentChange();
|
||||
}
|
||||
|
||||
public bool Exists(string name) => Get(name) is not null;
|
||||
@@ -79,27 +74,6 @@ public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath, writable: true);
|
||||
key?.DeleteValue(name, throwOnMissingValue: false);
|
||||
System.Environment.SetEnvironmentVariable(name, null, EnvironmentVariableTarget.Process);
|
||||
BroadcastEnvironmentChange();
|
||||
}
|
||||
|
||||
public EnvironmentReloadResult ReloadEnvironment()
|
||||
{
|
||||
var variables = GetUserPersistedEnvironment();
|
||||
foreach (var pair in variables)
|
||||
{
|
||||
System.Environment.SetEnvironmentVariable(pair.Key, pair.Value, EnvironmentVariableTarget.Process);
|
||||
}
|
||||
|
||||
BroadcastEnvironmentChange();
|
||||
|
||||
return new EnvironmentReloadResult
|
||||
{
|
||||
Success = true,
|
||||
Message = variables.Count == 0
|
||||
? "Пользовательских переменных для применения нет."
|
||||
: $"Применено {variables.Count} переменных к текущему процессу и отправлено WM_SETTINGCHANGE для других приложений.",
|
||||
};
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> ToDictionary(System.Collections.IDictionary source)
|
||||
@@ -112,36 +86,4 @@ public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void BroadcastEnvironmentChange()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = NativeMethods.SendMessageTimeout(
|
||||
HWND_BROADCAST,
|
||||
WM_SETTINGCHANGE,
|
||||
IntPtr.Zero,
|
||||
"Environment",
|
||||
0,
|
||||
1000,
|
||||
out _);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Non-critical: new processes still see updated registry values.
|
||||
}
|
||||
}
|
||||
|
||||
private static class NativeMethods
|
||||
{
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr SendMessageTimeout(
|
||||
int hWnd,
|
||||
int msg,
|
||||
IntPtr wParam,
|
||||
string lParam,
|
||||
int fuFlags,
|
||||
int uTimeout,
|
||||
out IntPtr lpdwResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Sms.Environment;
|
||||
|
||||
public sealed class EnvironmentReloadResult
|
||||
{
|
||||
public required bool Success { get; init; }
|
||||
|
||||
public required string Message { get; init; }
|
||||
}
|
||||
@@ -19,6 +19,4 @@ public interface IEnvironmentVariableStore
|
||||
bool IsPersistedInUserStore(string name);
|
||||
|
||||
void RemoveFromUserStore(string name);
|
||||
|
||||
EnvironmentReloadResult ReloadEnvironment();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,*">
|
||||
<Grid Grid.Row="0"
|
||||
Margin="12,12,12,0"
|
||||
ColumnDefinitions="*,Auto,Auto"
|
||||
ColumnDefinitions="*,Auto"
|
||||
ColumnSpacing="8">
|
||||
<CheckBox Content="Отображать все переменные"
|
||||
IsChecked="{Binding ShowAllVariables}"
|
||||
@@ -31,10 +31,6 @@
|
||||
Content="Обновить"
|
||||
Command="{Binding RefreshCommand}"
|
||||
MinWidth="100" />
|
||||
<Button Grid.Column="2"
|
||||
Content="Применить к сессии"
|
||||
Command="{Binding ReloadEnvironmentCommand}"
|
||||
MinWidth="140" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
@@ -62,10 +58,6 @@
|
||||
<TextBlock Foreground="#C62828"
|
||||
Text="{Binding AddVariableError}"
|
||||
IsVisible="{Binding AddVariableError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
<TextBlock Foreground="#2E7D32"
|
||||
Text="{Binding ReloadEnvironmentMessage}"
|
||||
TextWrapping="Wrap"
|
||||
IsVisible="{Binding ReloadEnvironmentMessage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
</StackPanel>
|
||||
|
||||
<Border Grid.Row="3"
|
||||
@@ -107,11 +99,6 @@
|
||||
Binding="{Binding RequiredValue, Mode=TwoWay}"
|
||||
Width="2*"
|
||||
MinWidth="140" />
|
||||
<DataGridTextColumn Header="Актуальное значение"
|
||||
Binding="{Binding ActualValueDisplay}"
|
||||
IsReadOnly="True"
|
||||
Width="2*"
|
||||
MinWidth="140" />
|
||||
<DataGridTextColumn Header="Комментарий"
|
||||
Binding="{Binding Comment, Mode=TwoWay}"
|
||||
Width="240"
|
||||
|
||||
@@ -142,17 +142,6 @@ public sealed class EnvironmentVariablesService
|
||||
|
||||
public string GetDisplayValue(string name) => ResolveRequiredValue(name);
|
||||
|
||||
public string? GetProcessValue(string name) =>
|
||||
_store.GetProcessEnvironment().TryGetValue(name, out var value) ? value : null;
|
||||
|
||||
public EnvironmentReloadResult ReloadEnvironment()
|
||||
{
|
||||
var result = _store.ReloadEnvironment();
|
||||
_log.WriteLine(
|
||||
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [INFO] Reload environment: success={result.Success}; {result.Message}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SaveValue(string name, string value)
|
||||
{
|
||||
var previous = _store.GetUserPersistedValue(name);
|
||||
|
||||
@@ -21,7 +21,6 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
_service = service;
|
||||
_onCustomRemoved = onCustomRemoved;
|
||||
ApplySnapshot(row, suppressSave: true);
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
public string Field { get; }
|
||||
@@ -35,12 +34,6 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private bool _useUserStore;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _actualValue = string.Empty;
|
||||
|
||||
public string ActualValueDisplay =>
|
||||
string.IsNullOrEmpty(ActualValue) ? "<нет>" : ActualValue;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _requiredValue = string.Empty;
|
||||
|
||||
@@ -67,7 +60,6 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
if (value)
|
||||
{
|
||||
_service.SaveValue(Field, RequiredValue);
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,11 +74,8 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
BeginLoad();
|
||||
RequiredValue = _service.GetDisplayValue(Field);
|
||||
EndLoad();
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
partial void OnActualValueChanged(string value) => OnPropertyChanged(nameof(ActualValueDisplay));
|
||||
|
||||
partial void OnRequiredValueChanged(string value)
|
||||
{
|
||||
if (_isLoading || !UseUserStore)
|
||||
@@ -95,7 +84,6 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
}
|
||||
|
||||
_service.SaveValue(Field, value);
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
public event EventHandler? RowAppearanceChanged;
|
||||
@@ -117,11 +105,6 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshActualValue(string? processValue)
|
||||
{
|
||||
ActualValue = processValue ?? string.Empty;
|
||||
}
|
||||
|
||||
public void BeginLoad() => _isLoading = true;
|
||||
|
||||
public void EndLoad() => _isLoading = false;
|
||||
|
||||
@@ -32,27 +32,12 @@ public sealed partial class MainWindowViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private string? _addVariableError;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _reloadEnvironmentMessage;
|
||||
|
||||
partial void OnShowAllVariablesChanged(bool value) => SyncRowsFromService();
|
||||
|
||||
partial void OnNewVariableNameChanged(string value) => AddVariableCommand.NotifyCanExecuteChanged();
|
||||
|
||||
[RelayCommand]
|
||||
private void Refresh()
|
||||
{
|
||||
SyncRowsFromService();
|
||||
RefreshProcessStates();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ReloadEnvironment()
|
||||
{
|
||||
var result = _service.ReloadEnvironment();
|
||||
ReloadEnvironmentMessage = result.Message;
|
||||
RefreshProcessStates();
|
||||
}
|
||||
private void Refresh() => SyncRowsFromService();
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanAddVariable))]
|
||||
private void AddVariable()
|
||||
@@ -142,16 +127,6 @@ public sealed partial class MainWindowViewModel : ObservableObject
|
||||
MoveItem(Rows, currentIndex, targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
RefreshProcessStates();
|
||||
}
|
||||
|
||||
private void RefreshProcessStates()
|
||||
{
|
||||
foreach (var row in Rows)
|
||||
{
|
||||
row.RefreshActualValue(_service.GetProcessValue(row.Field));
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveItem(
|
||||
|
||||
Reference in New Issue
Block a user