using System.Runtime.InteropServices; using Sms.Environment; namespace Sms.Environment.Windows; public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore { private const int HWND_BROADCAST = 0xffff; private const int WM_SETTINGCHANGE = 0x001A; public string? Get(string name) => System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User) ?? System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process); public void Set(string name, string value) { System.Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.User); System.Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.Process); BroadcastEnvironmentChange(); } public bool Exists(string name) => Get(name) is not null; public IReadOnlyDictionary GetAll(IEnumerable names) { var result = new Dictionary(StringComparer.Ordinal); foreach (var name in names) { var value = Get(name); if (value is not null) { result[name] = value; } } return result; } public IReadOnlyDictionary GetProcessEnvironment() => ToDictionary(System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process)); public IReadOnlyDictionary GetUserPersistedEnvironment() => ToDictionary(System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)); public bool IsPersistedInUserStore(string name) => System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User) is not null; public void RemoveFromUserStore(string name) { System.Environment.SetEnvironmentVariable(name, null, EnvironmentVariableTarget.User); System.Environment.SetEnvironmentVariable(name, null, EnvironmentVariableTarget.Process); BroadcastEnvironmentChange(); } private static Dictionary ToDictionary(System.Collections.IDictionary source) { var result = new Dictionary(StringComparer.Ordinal); foreach (string key in source.Keys) { result[key] = source[key]?.ToString() ?? string.Empty; } 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); } }