1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using Internal.Runtime.Augments; 6 using System.Collections; 7 using System.Collections.Generic; 8 using System.IO; 9 using System.Reflection; 10 using System.Runtime.CompilerServices; 11 using System.Text; 12 13 namespace System 14 { 15 public static partial class Environment 16 { GetEnvironmentVariable(string variable)17 public static string GetEnvironmentVariable(string variable) 18 { 19 return EnvironmentAugments.GetEnvironmentVariable(variable); 20 } 21 GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)22 public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) 23 { 24 return EnvironmentAugments.GetEnvironmentVariable(variable, target); 25 } 26 GetEnvironmentVariables()27 public static IDictionary GetEnvironmentVariables() 28 { 29 // To maintain complete compatibility with prior versions we need to return a Hashtable. 30 // We did ship a prior version of Core with LowLevelDictionary, which does iterate the 31 // same (e.g. yields DictionaryEntry), but it is not a public type. 32 // 33 // While we could pass Hashtable back from CoreCLR the type is also defined here. We only 34 // want to surface the local Hashtable. 35 return EnvironmentAugments.EnumerateEnvironmentVariables().ToHashtable(); 36 } 37 GetEnvironmentVariables(EnvironmentVariableTarget target)38 public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target) 39 { 40 // See comments in GetEnvironmentVariables() 41 return EnvironmentAugments.EnumerateEnvironmentVariables(target).ToHashtable(); 42 } 43 ToHashtable(this IEnumerable<KeyValuePair<string, string>> pairs)44 private static Hashtable ToHashtable(this IEnumerable<KeyValuePair<string, string>> pairs) 45 { 46 Hashtable hashTable = new Hashtable(); 47 foreach (KeyValuePair<string, string> pair in pairs) 48 { 49 hashTable.Add(pair.Key, pair.Value); 50 } 51 return hashTable; 52 } 53 SetEnvironmentVariable(string variable, string value)54 public static void SetEnvironmentVariable(string variable, string value) 55 { 56 EnvironmentAugments.SetEnvironmentVariable(variable, value); 57 } 58 SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)59 public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) 60 { 61 EnvironmentAugments.SetEnvironmentVariable(variable, value, target); 62 } 63 64 public static string CommandLine 65 { 66 get 67 { 68 StringBuilder sb = StringBuilderCache.Acquire(); 69 70 foreach (string arg in GetCommandLineArgs()) 71 { 72 bool containsQuotes = false, containsWhitespace = false; 73 foreach (char c in arg) 74 { 75 if (char.IsWhiteSpace(c)) 76 { 77 containsWhitespace = true; 78 } 79 else if (c == '"') 80 { 81 containsQuotes = true; 82 } 83 } 84 85 string quote = containsWhitespace ? "\"" : ""; 86 string formattedArg = containsQuotes && containsWhitespace ? arg.Replace("\"", "\\\"") : arg; 87 88 sb.Append(quote).Append(formattedArg).Append(quote).Append(' '); 89 } 90 91 if (sb.Length > 0) 92 { 93 sb.Length--; 94 } 95 96 return StringBuilderCache.GetStringAndRelease(sb); 97 } 98 } 99 100 public static string CurrentDirectory 101 { 102 get { return CurrentDirectoryCore; } 103 set 104 { 105 if (value == null) 106 { 107 throw new ArgumentNullException(nameof(value)); 108 } 109 110 if (value.Length == 0) 111 { 112 throw new ArgumentException(SR.Argument_PathEmpty, nameof(value)); 113 } 114 115 CurrentDirectoryCore = value; 116 } 117 } 118 119 public static int CurrentManagedThreadId => EnvironmentAugments.CurrentManagedThreadId; 120 Exit(int exitCode)121 public static void Exit(int exitCode) => EnvironmentAugments.Exit(exitCode); 122 FailFast(string message)123 public static void FailFast(string message) => FailFast(message, exception: null); 124 FailFast(string message, Exception exception)125 public static void FailFast(string message, Exception exception) => EnvironmentAugments.FailFast(message, exception); 126 ExpandEnvironmentVariables(string name)127 public static string ExpandEnvironmentVariables(string name) 128 { 129 if (name == null) 130 { 131 throw new ArgumentNullException(nameof(name)); 132 } 133 134 if (name.Length == 0) 135 { 136 return name; 137 } 138 139 return ExpandEnvironmentVariablesCore(name); 140 } 141 GetCommandLineArgs()142 public static string[] GetCommandLineArgs() => EnvironmentAugments.GetCommandLineArgs(); 143 144 public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None); 145 GetFolderPath(SpecialFolder folder, SpecialFolderOption option)146 public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) 147 { 148 if (!Enum.IsDefined(typeof(SpecialFolder), folder)) 149 { 150 throw new ArgumentOutOfRangeException(nameof(folder), folder, SR.Format(SR.Arg_EnumIllegalVal, folder)); 151 } 152 153 if (option != SpecialFolderOption.None && !Enum.IsDefined(typeof(SpecialFolderOption), option)) 154 { 155 throw new ArgumentOutOfRangeException(nameof(option), option, SR.Format(SR.Arg_EnumIllegalVal, option)); 156 } 157 158 return GetFolderPathCore(folder, option); 159 } 160 161 public static bool HasShutdownStarted => EnvironmentAugments.HasShutdownStarted; 162 163 public static bool Is64BitProcess => IntPtr.Size == 8; 164 165 public static bool Is64BitOperatingSystem => Is64BitProcess || Is64BitOperatingSystemWhen32BitProcess; 166 167 public static OperatingSystem OSVersion => s_osVersion.Value; 168 169 public static int ProcessorCount => EnvironmentAugments.ProcessorCount; 170 171 public static string StackTrace 172 { 173 [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts 174 get 175 { 176 return EnvironmentAugments.StackTrace; 177 } 178 } 179 180 public static int TickCount => EnvironmentAugments.TickCount; 181 182 public static bool UserInteractive => true; 183 184 public static Version Version 185 { 186 // Previously this represented the File version of mscorlib.dll. Many other libraries in the framework and outside took dependencies on the first three parts of this version 187 // remaining constant throughout 4.x. From 4.0 to 4.5.2 this was fine since the file version only incremented the last part. Starting with 4.6 we switched to a file versioning 188 // scheme that matched the product version. In order to preserve compatibility with existing libraries, this needs to be hard-coded. 189 get { return new Version(4, 0, 30319, 42000); } 190 } 191 192 public static long WorkingSet 193 { 194 get 195 { 196 // Use reflection to access the implementation in System.Diagnostics.Process.dll. While far from ideal, 197 // we do this to avoid duplicating the Windows, Linux, macOS, and potentially other platform-specific implementations 198 // present in Process. If it proves important, we could look at separating that functionality out of Process into 199 // Common files which could also be included here. 200 Type processType = Type.GetType("System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false); 201 IDisposable currentProcess = processType?.GetTypeInfo().GetDeclaredMethod("GetCurrentProcess")?.Invoke(null, null) as IDisposable; 202 if (currentProcess != null) 203 { 204 try 205 { 206 object result = processType.GetTypeInfo().GetDeclaredProperty("WorkingSet64")?.GetMethod?.Invoke(currentProcess, null); 207 if (result is long) return (long)result; 208 } 209 catch (TargetInvocationException tie) 210 { 211 if(tie.InnerException != null) 212 throw tie.InnerException; 213 214 throw tie; 215 } 216 finally { currentProcess.Dispose(); } 217 } 218 219 // Could not get the current working set. 220 return 0; 221 } 222 } 223 } 224 } 225