summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Environment.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Environment.cs')
-rw-r--r--src/mscorlib/src/System/Environment.cs1154
1 files changed, 445 insertions, 709 deletions
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs
index 5ee30bb9ba..835219a01c 100644
--- a/src/mscorlib/src/System/Environment.cs
+++ b/src/mscorlib/src/System/Environment.cs
@@ -32,17 +32,16 @@ namespace System {
using System.Diagnostics.Contracts;
[ComVisible(true)]
- public enum EnvironmentVariableTarget {
+ public enum EnvironmentVariableTarget
+ {
Process = 0,
-#if FEATURE_WIN32_REGISTRY
User = 1,
Machine = 2,
-#endif
}
[ComVisible(true)]
- public static class Environment {
-
+ public static partial class Environment
+ {
// Assume the following constants include the terminating '\0' - use <, not <=
const int MaxEnvVariableValueLength = 32767; // maximum length for environment variable name and value
// System environment variables are stored in the registry, and have
@@ -89,11 +88,10 @@ namespace System {
}
}
- [System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal String GetResourceString(String key) {
if (key == null || key.Length == 0) {
- Contract.Assert(false, "Environment::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
+ Debug.Assert(false, "Environment::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
return "[Resource lookup failed - null or empty resource name]";
}
@@ -125,11 +123,6 @@ namespace System {
return userData.m_retVal;
}
- #if FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
- #else
- [System.Security.SecuritySafeCritical]
- #endif
private void GetResourceStringCode(Object userDataIn)
{
GetResourceStringUserData userData = (GetResourceStringUserData) userDataIn;
@@ -189,14 +182,11 @@ namespace System {
String s = rh.SystemResMgr.GetString(key, null);
rh.currentlyLoading.RemoveAt(rh.currentlyLoading.Count - 1); // Pop
- Contract.Assert(s!=null, "Managed resource string lookup failed. Was your resource name misspelled? Did you rebuild mscorlib after adding a resource to resources.txt? Debug this w/ cordbg and bug whoever owns the code that called Environment.GetResourceString. Resource name was: \""+key+"\"");
+ Debug.Assert(s!=null, "Managed resource string lookup failed. Was your resource name misspelled? Did you rebuild mscorlib after adding a resource to resources.txt? Debug this w/ cordbg and bug whoever owns the code that called Environment.GetResourceString. Resource name was: \""+key+"\"");
userData.m_retVal = s;
}
- #if FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
- #endif
[PrePrepareMethod]
private void GetResourceStringBackoutCode(Object userDataIn, bool exceptionThrown)
{
@@ -248,32 +238,24 @@ namespace System {
**Exceptions: None
==============================================================================*/
public static extern int TickCount {
- [System.Security.SecuritySafeCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
// Terminates this process with the given exit code.
- [System.Security.SecurityCritical] // auto-generated
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
internal static extern void _Exit(int exitCode);
- [System.Security.SecuritySafeCritical] // auto-generated
-#pragma warning disable 618
- [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
-#pragma warning restore 618
public static void Exit(int exitCode) {
_Exit(exitCode);
}
public static extern int ExitCode {
- [System.Security.SecuritySafeCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
- [System.Security.SecuritySafeCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
set;
}
@@ -281,11 +263,9 @@ namespace System {
// Note: The CLR's Watson bucketization code looks at the caller of the FCALL method
// to assign blame for crashes. Don't mess with this, such as by making it call
// another managed helper method, unless you consult with some CLR Watson experts.
- [System.Security.SecurityCritical]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void FailFast(String message);
- [System.Security.SecurityCritical]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void FailFast(String message, uint exitCode);
@@ -302,44 +282,9 @@ namespace System {
// if the exception object is preallocated, the runtime will use the callsite's
// IP for bucketing. If the exception object is not preallocated, it will use the bucket
// details contained in the object (if any).
- [System.Security.SecurityCritical]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void FailFast(String message, Exception exception);
-#if !FEATURE_CORECLR
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- [SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods.
- [SuppressUnmanagedCodeSecurity]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- internal static extern void TriggerCodeContractFailure(ContractFailureKind failureKind, String message, String condition, String exceptionAsString);
-
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- [SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods.
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool GetIsCLRHosted();
-
- internal static bool IsCLRHosted {
- [SecuritySafeCritical]
- get { return GetIsCLRHosted(); }
- }
-
- public static String CommandLine {
- [System.Security.SecuritySafeCritical] // auto-generated
- get {
- new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
-
- String commandLine = null;
- GetCommandLine(JitHelpers.GetStringHandleOnStack(ref commandLine));
- return commandLine;
- }
- }
-
- [System.Security.SecurityCritical] // auto-generated
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
- private static extern void GetCommandLine(StringHandleOnStack retString);
-#endif // !FEATURE_CORECLR
-
/*===============================CurrentDirectory===============================
**Action: Provides a getter and setter for the current directory. The original
** current directory is the one from which the process was started.
@@ -353,9 +298,6 @@ namespace System {
return Directory.GetCurrentDirectory();
}
- #if FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
- #endif
set {
Directory.SetCurrentDirectory(value);
}
@@ -363,22 +305,12 @@ namespace System {
// Returns the system directory (ie, C:\WinNT\System32).
public static String SystemDirectory {
-#if FEATURE_CORECLR
- [System.Security.SecurityCritical]
-#else
- [System.Security.SecuritySafeCritical] // auto-generated
-#endif
get {
StringBuilder sb = new StringBuilder(Path.MaxPath);
int r = Win32Native.GetSystemDirectory(sb, Path.MaxPath);
- Contract.Assert(r < Path.MaxPath, "r < Path.MaxPath");
+ Debug.Assert(r < Path.MaxPath, "r < Path.MaxPath");
if (r==0) __Error.WinIOError();
String path = sb.ToString();
-
-#if !FEATURE_CORECLR
- // Do security check
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
-#endif
return path;
}
@@ -387,11 +319,10 @@ namespace System {
// Returns the windows directory (ie, C:\WinNT).
// Used by NLS+ custom culures only at the moment.
internal static String InternalWindowsDirectory {
- [System.Security.SecurityCritical] // auto-generated
get {
StringBuilder sb = new StringBuilder(Path.MaxPath);
int r = Win32Native.GetWindowsDirectory(sb, Path.MaxPath);
- Contract.Assert(r < Path.MaxPath, "r < Path.MaxPath");
+ Debug.Assert(r < Path.MaxPath, "r < Path.MaxPath");
if (r==0) __Error.WinIOError();
String path = sb.ToString();
@@ -399,11 +330,10 @@ namespace System {
}
}
- [System.Security.SecuritySafeCritical] // auto-generated
public static String ExpandEnvironmentVariables(String name)
{
if (name == null)
- throw new ArgumentNullException("name");
+ throw new ArgumentNullException(nameof(name));
Contract.EndContractBlock();
if (name.Length == 0) {
@@ -442,63 +372,6 @@ namespace System {
int size;
-#if !FEATURE_CORECLR
- bool isFullTrust = CodeAccessSecurityEngine.QuickCheckForAllDemands();
-
- // Do a security check to guarantee we can read each of the
- // individual environment variables requested here.
- String[] varArray = name.Split(new char[] {'%'});
- StringBuilder vars = isFullTrust ? null : new StringBuilder();
-
- bool fJustExpanded = false; // to accommodate expansion alg.
-
- for(int i=1; i<varArray.Length-1; i++) { // Skip first and last tokens
- // ExpandEnvironmentStrings' greedy algorithm expands every
- // non-boundary %-delimited substring, provided the previous
- // has not been expanded.
- // if "foo" is not expandable, and "PATH" is, then both
- // %foo%PATH% and %foo%foo%PATH% will expand PATH, but
- // %PATH%PATH% will expand only once.
- // Therefore, if we've just expanded, skip this substring.
- if (varArray[i].Length == 0 || fJustExpanded == true)
- {
- fJustExpanded = false;
- continue; // Nothing to expand
- }
- // Guess a somewhat reasonable initial size, call the method, then if
- // it fails (ie, the return value is larger than our buffer size),
- // make a new buffer & try again.
- blob.Length = 0;
- String envVar = "%" + varArray[i] + "%";
- size = Win32Native.ExpandEnvironmentStrings(envVar, blob, currentSize);
- if (size == 0)
- Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
-
- // some environment variable might be changed while this function is called
- while (size > currentSize) {
- currentSize = size;
- blob.Capacity = currentSize;
- blob.Length = 0;
- size = Win32Native.ExpandEnvironmentStrings(envVar, blob, currentSize);
- if (size == 0)
- Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
- }
-
- if (!isFullTrust) {
- String temp = blob.ToString();
- fJustExpanded = (temp != envVar);
- if (fJustExpanded) { // We expanded successfully, we need to do String comparison here
- // since %FOO% can become %FOOD
- vars.Append(varArray[i]);
- vars.Append(';');
- }
- }
- }
-
- if (!isFullTrust)
- new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand();
-#endif // !FEATURE_CORECLR
-
blob.Length = 0;
size = Win32Native.ExpandEnvironmentStrings(name, blob, currentSize);
if (size == 0)
@@ -519,7 +392,6 @@ namespace System {
}
public static String MachineName {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
// UWP Debug scenarios
@@ -531,9 +403,6 @@ namespace System {
// In future release of operating systems, you might be able to rename a machine without
// rebooting. Therefore, don't cache this machine name.
-#if !FEATURE_CORECLR
- new EnvironmentPermission(EnvironmentPermissionAccess.Read, "COMPUTERNAME").Demand();
-#endif
StringBuilder buf = new StringBuilder(MaxMachineNameLength);
int len = MaxMachineNameLength;
if (Win32Native.GetComputerName(buf, ref len) == 0)
@@ -542,20 +411,17 @@ namespace System {
}
}
- [SecurityCritical]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern Int32 GetProcessorCount();
public static int ProcessorCount {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
return GetProcessorCount();
}
}
public static int SystemPageSize {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
(new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
Win32Native.SYSTEM_INFO info = new Win32Native.SYSTEM_INFO();
@@ -571,11 +437,9 @@ namespace System {
**Arguments: None
**Exceptions: None.
==============================================================================*/
- [System.Security.SecuritySafeCritical] // auto-generated
public static String[] GetCommandLineArgs()
{
new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
-#if FEATURE_CORECLR
/*
* There are multiple entry points to a hosted app.
* The host could use ::ExecuteAssembly() or ::CreateDelegate option
@@ -591,145 +455,37 @@ namespace System {
*/
if(s_CommandLineArgs != null)
return (string[])s_CommandLineArgs.Clone();
-#endif
+
return GetCommandLineArgsNative();
}
- [System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern String[] GetCommandLineArgsNative();
-#if !FEATURE_CORECLR
- // We need to keep this Fcall since it is used in AppDomain.cs.
- // If we call GetEnvironmentVariable from AppDomain.cs, we will use StringBuilder class.
- // That has side effect to change the ApartmentState of the calling Thread to MTA.
- // So runtime can't change the ApartmentState of calling thread any more.
- [System.Security.SecurityCritical] // auto-generated
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern String nativeGetEnvironmentVariable(String variable);
-#endif //!FEATURE_CORECLR
-
-#if FEATURE_CORECLR
private static string[] s_CommandLineArgs = null;
private static void SetCommandLineArgs(string[] cmdLineArgs)
{
s_CommandLineArgs = cmdLineArgs;
}
-#endif
-
- /*============================GetEnvironmentVariable============================
- **Action:
- **Returns:
- **Arguments:
- **Exceptions:
- ==============================================================================*/
- [System.Security.SecuritySafeCritical] // auto-generated
- public static String GetEnvironmentVariable(String variable)
- {
- if (variable == null)
- throw new ArgumentNullException("variable");
- Contract.EndContractBlock();
-
- if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
- // Environment variable accessors are not approved modern API.
- // Behave as if the variable was not found in this case.
- return null;
- }
-
-#if !FEATURE_CORECLR
- (new EnvironmentPermission(EnvironmentPermissionAccess.Read, variable)).Demand();
-#endif //!FEATURE_CORECLR
-
- StringBuilder blob = StringBuilderCache.Acquire(128); // A somewhat reasonable default size
- int requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
-
- if (requiredSize == 0) { // GetEnvironmentVariable failed
- if (Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND) {
- StringBuilderCache.Release(blob);
- return null;
- }
- }
-
- while (requiredSize > blob.Capacity) { // need to retry since the environment variable might be changed
- blob.Capacity = requiredSize;
- blob.Length = 0;
- requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
- }
- return StringBuilderCache.GetStringAndRelease(blob);
- }
- [System.Security.SecuritySafeCritical] // auto-generated
- public static string GetEnvironmentVariable( string variable, EnvironmentVariableTarget target)
- {
- if (variable == null)
- {
- throw new ArgumentNullException("variable");
- }
- Contract.EndContractBlock();
-
- if (target == EnvironmentVariableTarget.Process)
- {
- return GetEnvironmentVariable(variable);
- }
-
-#if FEATURE_WIN32_REGISTRY
- (new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
-
- if( target == EnvironmentVariableTarget.Machine) {
- using (RegistryKey environmentKey =
- Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) {
-
- Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!");
- if (environmentKey == null) {
- return null;
- }
-
- string value = environmentKey.GetValue(variable) as string;
- return value;
- }
- }
- else if( target == EnvironmentVariableTarget.User) {
- using (RegistryKey environmentKey =
- Registry.CurrentUser.OpenSubKey("Environment", false)) {
-
- Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!");
- if (environmentKey == null) {
- return null;
- }
-
- string value = environmentKey.GetValue(variable) as string;
- return value;
- }
- }
- else
-#endif // FEATURE_WIN32_REGISTRY
- {
- throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
- }
- }
-
- /*===========================GetEnvironmentVariables============================
- **Action: Returns an IDictionary containing all enviroment variables and their values.
- **Returns: An IDictionary containing all environment variables and their values.
- **Arguments: None.
- **Exceptions: None.
- ==============================================================================*/
- [System.Security.SecurityCritical] // auto-generated
private unsafe static char[] GetEnvironmentCharArray()
{
char[] block = null;
// Make sure pStrings is not leaked with async exceptions
RuntimeHelpers.PrepareConstrainedRegions();
- try {
+ try
+ {
}
- finally {
- char * pStrings = null;
+ finally
+ {
+ char* pStrings = null;
try
{
pStrings = Win32Native.GetEnvironmentStrings();
- if (pStrings == null) {
+ if (pStrings == null)
+ {
throw new OutOfMemoryException();
}
@@ -739,7 +495,7 @@ namespace System {
// CreateProcess page (null-terminated array of null-terminated strings).
// Search for terminating \0\0 (two unicode \0's).
- char * p = pStrings;
+ char* p = pStrings;
while (!(*p == '\0' && *(p + 1) == '\0'))
p++;
@@ -747,7 +503,7 @@ namespace System {
block = new char[len];
fixed (char* pBlock = block)
- String.wstrcpy(pBlock, pStrings, len);
+ string.wstrcpy(pBlock, pStrings, len);
}
finally
{
@@ -759,275 +515,12 @@ namespace System {
return block;
}
- [System.Security.SecuritySafeCritical] // auto-generated
- public static IDictionary GetEnvironmentVariables()
- {
- if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
- // Environment variable accessors are not approved modern API.
- // Behave as if no environment variables are defined in this case.
- return new Hashtable(0);
- }
-
-#if !FEATURE_CORECLR
- bool isFullTrust = CodeAccessSecurityEngine.QuickCheckForAllDemands();
- StringBuilder vars = isFullTrust ? null : new StringBuilder();
- bool first = true;
-#endif
-
- char[] block = GetEnvironmentCharArray();
-
- Hashtable table = new Hashtable(20);
-
- // Copy strings out, parsing into pairs and inserting into the table.
- // The first few environment variable entries start with an '='!
- // The current working directory of every drive (except for those drives
- // you haven't cd'ed into in your DOS window) are stored in the
- // environment block (as =C:=pwd) and the program's exit code is
- // as well (=ExitCode=00000000) Skip all that start with =.
- // Read docs about Environment Blocks on MSDN's CreateProcess page.
-
- // Format for GetEnvironmentStrings is:
- // (=HiddenVar=value\0 | Variable=value\0)* \0
- // See the description of Environment Blocks in MSDN's
- // CreateProcess page (null-terminated array of null-terminated strings).
- // Note the =HiddenVar's aren't always at the beginning.
-
- for(int i=0; i<block.Length; i++) {
- int startKey = i;
- // Skip to key
- // On some old OS, the environment block can be corrupted.
- // Someline will not have '=', so we need to check for '\0'.
- while(block[i]!='=' && block[i] != '\0') {
- i++;
- }
-
- if(block[i] == '\0') {
- continue;
- }
-
- // Skip over environment variables starting with '='
- if (i-startKey==0) {
- while(block[i]!=0) {
- i++;
- }
- continue;
- }
- String key = new String(block, startKey, i-startKey);
- i++; // skip over '='
- int startValue = i;
- while(block[i]!=0) {
- // Read to end of this entry
- i++;
- }
-
- String value = new String(block, startValue, i-startValue);
- // skip over 0 handled by for loop's i++
- table[key]=value;
-
-#if !FEATURE_CORECLR
- if (!isFullTrust) {
- if( first) {
- first = false;
- }
- else {
- vars.Append(';');
- }
- vars.Append(key);
- }
-#endif
- }
-
-#if !FEATURE_CORECLR
- if (!isFullTrust)
- new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand();
-#endif
- return table;
- }
-
-#if FEATURE_WIN32_REGISTRY
- internal static IDictionary GetRegistryKeyNameValuePairs(RegistryKey registryKey) {
- Hashtable table = new Hashtable(20);
-
- if (registryKey != null) {
- string[] names = registryKey.GetValueNames();
- foreach( string name in names) {
- string value = registryKey.GetValue(name, "").ToString();
- table.Add(name, value);
- }
- }
- return table;
- }
-#endif
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public static IDictionary GetEnvironmentVariables( EnvironmentVariableTarget target) {
- if( target == EnvironmentVariableTarget.Process) {
- return GetEnvironmentVariables();
- }
-
-#if FEATURE_WIN32_REGISTRY
- (new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
-
- if( target == EnvironmentVariableTarget.Machine) {
- using (RegistryKey environmentKey =
- Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) {
-
- return GetRegistryKeyNameValuePairs(environmentKey);
- }
- }
- else if( target == EnvironmentVariableTarget.User) {
- using (RegistryKey environmentKey =
- Registry.CurrentUser.OpenSubKey("Environment", false)) {
- return GetRegistryKeyNameValuePairs(environmentKey);
- }
- }
- else
-#endif // FEATURE_WIN32_REGISTRY
- {
- throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
- }
- }
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public static void SetEnvironmentVariable(string variable, string value) {
- CheckEnvironmentVariableName(variable);
-
-#if !FEATURE_CORECLR
- new EnvironmentPermission(PermissionState.Unrestricted).Demand();
-#endif
- // explicitly null out value if is the empty string.
- if (String.IsNullOrEmpty(value) || value[0] == '\0') {
- value = null;
- }
- else {
- if( value.Length >= MaxEnvVariableValueLength) {
- throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
- }
- }
-
- if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
- // Environment variable accessors are not approved modern API.
- // so we throw PlatformNotSupportedException.
- throw new PlatformNotSupportedException();
- }
-
- if(!Win32Native.SetEnvironmentVariable(variable, value)) {
- int errorCode = Marshal.GetLastWin32Error();
-
- // Allow user to try to clear a environment variable
- if( errorCode == Win32Native.ERROR_ENVVAR_NOT_FOUND) {
- return;
- }
-
- // The error message from Win32 is "The filename or extension is too long",
- // which is not accurate.
- if( errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE) {
- throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
- }
-
- throw new ArgumentException(Win32Native.GetMessage(errorCode));
- }
- }
-
- private static void CheckEnvironmentVariableName(string variable) {
- if (variable == null) {
- throw new ArgumentNullException("variable");
- }
-
- if( variable.Length == 0) {
- throw new ArgumentException(Environment.GetResourceString("Argument_StringZeroLength"), "variable");
- }
-
- if( variable[0] == '\0') {
- throw new ArgumentException(Environment.GetResourceString("Argument_StringFirstCharIsZero"), "variable");
- }
-
- // Make sure the environment variable name isn't longer than the
- // max limit on environment variable values. (MSDN is ambiguous
- // on whether this check is necessary.)
- if( variable.Length >= MaxEnvVariableValueLength ) {
- throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
- }
-
- if( variable.IndexOf('=') != -1) {
- throw new ArgumentException(Environment.GetResourceString("Argument_IllegalEnvVarName"));
- }
- Contract.EndContractBlock();
- }
-
- [System.Security.SecuritySafeCritical] // auto-generated
- public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) {
- if( target == EnvironmentVariableTarget.Process) {
- SetEnvironmentVariable(variable, value);
- return;
- }
-
- CheckEnvironmentVariableName(variable);
-
- // System-wide environment variables stored in the registry are
- // limited to 1024 chars for the environment variable name.
- if (variable.Length >= MaxSystemEnvVariableLength) {
- throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarName"));
- }
-
- new EnvironmentPermission(PermissionState.Unrestricted).Demand();
- // explicitly null out value if is the empty string.
- if (String.IsNullOrEmpty(value) || value[0] == '\0') {
- value = null;
- }
-#if FEATURE_WIN32_REGISTRY
- if( target == EnvironmentVariableTarget.Machine) {
- using (RegistryKey environmentKey =
- Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", true)) {
-
- Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!");
- if (environmentKey != null) {
- if (value == null)
- environmentKey.DeleteValue(variable, false);
- else
- environmentKey.SetValue(variable, value);
- }
- }
- }
- else if( target == EnvironmentVariableTarget.User) {
- // User-wide environment variables stored in the registry are
- // limited to 255 chars for the environment variable name.
- if (variable.Length >= MaxUserEnvVariableLength) {
- throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
- }
- using (RegistryKey environmentKey =
- Registry.CurrentUser.OpenSubKey("Environment", true)) {
- Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!");
- if (environmentKey != null) {
- if (value == null)
- environmentKey.DeleteValue(variable, false);
- else
- environmentKey.SetValue(variable, value);
- }
- }
- }
- else
- {
- throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
- }
- // send a WM_SETTINGCHANGE message to all windows
- IntPtr r = Win32Native.SendMessageTimeout(new IntPtr(Win32Native.HWND_BROADCAST), Win32Native.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
-
- if (r == IntPtr.Zero) BCLDebug.Assert(false, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
-
-#else // FEATURE_WIN32_REGISTRY
- throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
-#endif
- }
-
-
/*===============================GetLogicalDrives===============================
**Action: Retrieves the names of the logical drives on this machine in the form "C:\".
**Arguments: None.
**Exceptions: IOException.
**Permissions: SystemInfo Permission.
==============================================================================*/
- [System.Security.SecuritySafeCritical] // auto-generated
public static String[] GetLogicalDrives() {
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
@@ -1097,12 +590,10 @@ namespace System {
**Arguments:
**Exceptions:
==============================================================================*/
- [System.Security.SecurityCritical] // auto-generated
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
private static extern long GetWorkingSet();
public static long WorkingSet {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
return GetWorkingSet();
@@ -1117,7 +608,6 @@ namespace System {
**Exceptions:
==============================================================================*/
public static OperatingSystem OSVersion {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
Contract.Ensures(Contract.Result<OperatingSystem>() != null);
@@ -1141,7 +631,7 @@ namespace System {
Version v = new Version(osvi.MajorVersion, osvi.MinorVersion, osvi.BuildNumber, (osviEx.ServicePackMajor << 16) |osviEx.ServicePackMinor);
m_os = new OperatingSystem(id, v, osvi.CSDVersion);
}
- Contract.Assert(m_os != null, "m_os != null");
+ Debug.Assert(m_os != null, "m_os != null");
return m_os;
}
}
@@ -1186,7 +676,6 @@ namespace System {
// Does the current version of Windows have Windows Runtime suppport?
internal static bool IsWinRTSupported {
- [SecuritySafeCritical]
get {
if (!s_CheckedWinRT) {
s_WinRTSupported = WinRTSupported();
@@ -1197,7 +686,6 @@ namespace System {
}
}
- [SecurityCritical]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
@@ -1206,11 +694,9 @@ namespace System {
#endif // FEATURE_CORESYSTEM
- [System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool GetVersion(Microsoft.Win32.Win32Native.OSVERSIONINFO osVer);
- [System.Security.SecurityCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool GetVersionEx(Microsoft.Win32.Win32Native.OSVERSIONINFOEX osVer);
@@ -1222,7 +708,6 @@ namespace System {
**Exceptions:
==============================================================================*/
public static String StackTrace {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
Contract.Ensures(Contract.Result<String>() != null);
@@ -1231,9 +716,6 @@ namespace System {
}
}
-#if FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
-#endif
internal static String GetStackTrace(Exception e, bool needFileInfo)
{
// Note: Setting needFileInfo to true will start up COM and set our
@@ -1250,7 +732,6 @@ namespace System {
return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
}
- [System.Security.SecuritySafeCritical] // auto-generated
private static void InitResourceHelper() {
// Only the default AppDomain should have a ResourceHelper. All calls to
// GetResourceString from any AppDomain delegate to GetResourceStringLocal
@@ -1275,20 +756,13 @@ namespace System {
}
}
-#if !FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal extern static String GetResourceFromDefault(String key);
-#endif
-
// Looks up the resource string value for key.
//
// if you change this method's signature then you must change the code that calls it
// in excep.cpp and probably you will have to visit mscorlib.h to add the new signature
// as well as metasig.h to create the new signature type
-#if FEATURE_CORECLR
- [System.Security.SecurityCritical] // auto-generated
-#endif
+ // NoInlining causes the caller and callee to not be inlined in mscorlib as it is an assumption of StackCrawlMark use
+ [MethodImpl(MethodImplOptions.NoInlining)]
internal static String GetResourceStringLocal(String key) {
if (m_resHelper == null)
InitResourceHelper();
@@ -1296,30 +770,74 @@ namespace System {
return m_resHelper.GetResourceString(key);
}
- [System.Security.SecuritySafeCritical] // auto-generated
internal static String GetResourceString(String key) {
-#if FEATURE_CORECLR
return GetResourceStringLocal(key);
-#else
- return GetResourceFromDefault(key);
-#endif //FEATURE_CORECLR
}
- [System.Security.SecuritySafeCritical] // auto-generated
- internal static String GetResourceString(String key, params Object[] values) {
- String s = GetResourceString(key);
- return String.Format(CultureInfo.CurrentCulture, s, values);
+ // The reason the following overloads exist are to reduce code bloat.
+ // Since GetResourceString is basically only called when exceptions are
+ // thrown, we want the code size to be as small as possible.
+ // Using the params object[] overload works against this since the
+ // initialization of the array is done inline in the caller at the IL
+ // level. So we have overloads that simply wrap the params one, and
+ // the methods they call through to are tagged as NoInlining.
+ // In mscorlib NoInlining causes the caller and callee to not be inlined
+ // as it is an assumption of StackCrawlMark use so it is not added
+ // directly to these methods, but to the ones they call.
+ // That way they do not bloat either the IL or the generated asm.
+
+ internal static string GetResourceString(string key, object val0)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0 });
}
- //The following two internal methods are not used anywhere within the framework,
+ internal static string GetResourceString(string key, object val0, object val1)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0, val1 });
+ }
+
+ internal static string GetResourceString(string key, object val0, object val1, object val2)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0, val1, val2 });
+ }
+
+ internal static string GetResourceString(string key, object val0, object val1, object val2, object val3)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0, val1, val2, val3 });
+ }
+
+ internal static string GetResourceString(string key, object val0, object val1, object val2, object val3, object val4)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0, val1, val2, val3, val4 });
+ }
+
+ internal static string GetResourceString(string key, object val0, object val1, object val2, object val3, object val4, object val5)
+ {
+ return GetResourceStringFormatted(key, new object[] { val0, val1, val2, val3, val4, val5 });
+ }
+
+ internal static String GetResourceString(string key, params object[] values)
+ {
+ return GetResourceStringFormatted(key, values);
+ }
+
+ // NoInlining causes the caller and callee to not be inlined in mscorlib as it is an assumption of StackCrawlMark use
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static String GetResourceStringFormatted(string key, params object[] values)
+ {
+ string rs = GetResourceString(key);
+ return String.Format(CultureInfo.CurrentCulture, rs, values);
+ }
+
+ // The following two internal methods are not used anywhere within the framework,
// but are being kept around as external platforms built on top of us have taken
// dependency by using private reflection on them for getting system resource strings
- internal static String GetRuntimeResourceString(String key) {
+ private static String GetRuntimeResourceString(String key) {
return GetResourceString(key);
}
- internal static String GetRuntimeResourceString(String key, params Object[] values) {
- return GetResourceString(key,values);
+ private static String GetRuntimeResourceString(String key, params Object[] values) {
+ return GetResourceStringFormatted(key,values);
}
public static bool Is64BitProcess {
@@ -1333,7 +851,6 @@ namespace System {
}
public static bool Is64BitOperatingSystem {
- [System.Security.SecuritySafeCritical]
get {
#if BIT64
// 64-bit programs run only on 64-bit
@@ -1348,20 +865,11 @@ namespace System {
}
public static extern bool HasShutdownStarted {
- [System.Security.SecuritySafeCritical] // auto-generated
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
-#if !FEATURE_CORECLR
- // This is the temporary Whidbey stub for compatibility flags
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- [System.Security.SecurityCritical]
- internal static extern bool GetCompatibilityFlag(CompatibilityFlag flag);
-#endif //!FEATURE_CORECLR
-
public static string UserName {
- [System.Security.SecuritySafeCritical] // auto-generated
get {
new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserName").Demand();
@@ -1375,40 +883,13 @@ namespace System {
}
}
- // Note that this is a handle to a process window station, but it does
- // not need to be closed. CloseWindowStation would ignore this handle.
- // We also do handle equality checking as well. This isn't a great fit
- // for SafeHandle. We don't gain anything by using SafeHandle here.
-#if !FEATURE_CORECLR
- private static volatile IntPtr processWinStation; // Doesn't need to be initialized as they're zero-init.
- private static volatile bool isUserNonInteractive;
-#endif
-
- public static bool UserInteractive {
- [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool UserInteractive
+ {
get {
-#if !FEATURE_CORECLR
- IntPtr hwinsta = Win32Native.GetProcessWindowStation();
- if (hwinsta != IntPtr.Zero && processWinStation != hwinsta) {
- int lengthNeeded = 0;
- Win32Native.USEROBJECTFLAGS flags = new Win32Native.USEROBJECTFLAGS();
- if (Win32Native.GetUserObjectInformation(hwinsta, Win32Native.UOI_FLAGS, flags, Marshal.SizeOf(flags),ref lengthNeeded)) {
- if ((flags.dwFlags & Win32Native.WSF_VISIBLE) == 0) {
- isUserNonInteractive = true;
- }
- }
- processWinStation = hwinsta;
- }
-
- // The logic is reversed to avoid static initialization to true
- return !isUserNonInteractive;
-#else
return true;
-#endif
}
}
- [System.Security.SecuritySafeCritical] // auto-generated
public static string GetFolderPath(SpecialFolder folder) {
if (!Enum.IsDefined(typeof(SpecialFolder), folder))
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
@@ -1417,7 +898,6 @@ namespace System {
return InternalGetFolderPath(folder, SpecialFolderOption.None);
}
- [System.Security.SecuritySafeCritical] // auto-generated
public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) {
if (!Enum.IsDefined(typeof(SpecialFolder),folder))
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
@@ -1428,13 +908,11 @@ namespace System {
return InternalGetFolderPath(folder, option);
}
- [System.Security.SecurityCritical]
internal static string UnsafeGetFolderPath(SpecialFolder folder)
{
return InternalGetFolderPath(folder, SpecialFolderOption.None, suppressSecurityChecks: true);
}
- [System.Security.SecurityCritical]
private static string InternalGetFolderPath(SpecialFolder folder, SpecialFolderOption option, bool suppressSecurityChecks = false)
{
#if FEATURE_CORESYSTEM
@@ -1455,13 +933,6 @@ namespace System {
throw new PlatformNotSupportedException();
}
#else // FEATURE_CORESYSTEM
-#if !FEATURE_CORECLR
- if (option == SpecialFolderOption.Create && !suppressSecurityChecks) {
- FileIOPermission createPermission = new FileIOPermission(PermissionState.None);
- createPermission.AllFiles = FileIOPermissionAccess.Write;
- createPermission.Demand();
- }
-#endif
StringBuilder sb = new StringBuilder(Path.MaxPath);
int hresult = Win32Native.SHGetFolderPath(IntPtr.Zero, /* hwndOwner: [in] Reserved */
@@ -1499,14 +970,12 @@ namespace System {
// On CoreCLR we can check with the host if we're not trying to use any special options.
// Otherwise, we need to do a full demand since hosts aren't expecting to handle requests to
// create special folders.
-#if FEATURE_CORECLR
if (option == SpecialFolderOption.None)
{
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, s);
state.EnsureState();
}
else
-#endif // FEATURE_CORECLR
{
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, s).Demand();
}
@@ -1517,7 +986,6 @@ namespace System {
public static string UserDomainName
{
- [System.Security.SecuritySafeCritical] // auto-generated
get {
new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserDomain").Demand();
@@ -1650,7 +1118,7 @@ namespace System {
//
// "MyDocuments" is a better name than "Personal"
//
- MyDocuments = Win32Native.CSIDL_PERSONAL,
+ MyDocuments = Win32Native.CSIDL_PERSONAL,
//
// Represents the program files folder.
//
@@ -1658,101 +1126,7 @@ namespace System {
//
// Represents the folder for components that are shared across applications.
//
- CommonProgramFiles = Win32Native.CSIDL_PROGRAM_FILES_COMMON,
-#if !FEATURE_CORECLR
- //
- // <user name>\Start Menu\Programs\Administrative Tools
- //
- AdminTools = Win32Native.CSIDL_ADMINTOOLS,
- //
- // USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning
- //
- CDBurning = Win32Native.CSIDL_CDBURN_AREA,
- //
- // All Users\Start Menu\Programs\Administrative Tools
- //
- CommonAdminTools = Win32Native.CSIDL_COMMON_ADMINTOOLS,
- //
- // All Users\Documents
- //
- CommonDocuments = Win32Native.CSIDL_COMMON_DOCUMENTS,
- //
- // All Users\My Music
- //
- CommonMusic = Win32Native.CSIDL_COMMON_MUSIC,
- //
- // Links to All Users OEM specific apps
- //
- CommonOemLinks = Win32Native.CSIDL_COMMON_OEM_LINKS,
- //
- // All Users\My Pictures
- //
- CommonPictures = Win32Native.CSIDL_COMMON_PICTURES,
- //
- // All Users\Start Menu
- //
- CommonStartMenu = Win32Native.CSIDL_COMMON_STARTMENU,
- //
- // All Users\Start Menu\Programs
- //
- CommonPrograms = Win32Native.CSIDL_COMMON_PROGRAMS,
- //
- // All Users\Startup
- //
- CommonStartup = Win32Native.CSIDL_COMMON_STARTUP,
- //
- // All Users\Desktop
- //
- CommonDesktopDirectory = Win32Native.CSIDL_COMMON_DESKTOPDIRECTORY,
- //
- // All Users\Templates
- //
- CommonTemplates = Win32Native.CSIDL_COMMON_TEMPLATES,
- //
- // All Users\My Video
- //
- CommonVideos = Win32Native.CSIDL_COMMON_VIDEO,
- //
- // windows\fonts
- //
- Fonts = Win32Native.CSIDL_FONTS,
- //
- // %APPDATA%\Microsoft\Windows\Network Shortcuts
- //
- NetworkShortcuts = Win32Native.CSIDL_NETHOOD,
- //
- // %APPDATA%\Microsoft\Windows\Printer Shortcuts
- //
- PrinterShortcuts = Win32Native.CSIDL_PRINTHOOD,
- //
- // USERPROFILE
- //
- UserProfile = Win32Native.CSIDL_PROFILE,
- //
- // x86 Program Files\Common on RISC
- //
- CommonProgramFilesX86 = Win32Native.CSIDL_PROGRAM_FILES_COMMONX86,
- //
- // x86 C:\Program Files on RISC
- //
- ProgramFilesX86 = Win32Native.CSIDL_PROGRAM_FILESX86,
- //
- // Resource Directory
- //
- Resources = Win32Native.CSIDL_RESOURCES,
- //
- // Localized Resource Directory
- //
- LocalizedResources = Win32Native.CSIDL_RESOURCES_LOCALIZED,
- //
- // %windir%\System32 or %windir%\syswow64
- //
- SystemX86 = Win32Native.CSIDL_SYSTEMX86,
- //
- // GetWindowsDirectory()
- //
- Windows = Win32Native.CSIDL_WINDOWS,
-#endif // !FEATURE_CORECLR
+ CommonProgramFiles = Win32Native.CSIDL_PROGRAM_FILES_COMMON,
}
public static int CurrentManagedThreadId
@@ -1764,5 +1138,367 @@ namespace System {
}
}
+ internal static extern int CurrentProcessorNumber
+ {
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ get;
+ }
+
+ public static string GetEnvironmentVariable(string variable)
+ {
+ if (variable == null)
+ {
+ throw new ArgumentNullException(nameof(variable));
+ }
+
+ // separated from the EnvironmentVariableTarget overload to help with tree shaking in common case
+ return GetEnvironmentVariableCore(variable);
+ }
+
+ public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
+ {
+ if (variable == null)
+ {
+ throw new ArgumentNullException(nameof(variable));
+ }
+
+ ValidateTarget(target);
+
+ return GetEnvironmentVariableCore(variable, target);
+ }
+
+ public static IDictionary GetEnvironmentVariables()
+ {
+ // separated from the EnvironmentVariableTarget overload to help with tree shaking in common case
+ return GetEnvironmentVariablesCore();
+ }
+
+ public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
+ {
+ ValidateTarget(target);
+
+ return GetEnvironmentVariablesCore(target);
+ }
+
+ public static void SetEnvironmentVariable(string variable, string value)
+ {
+ ValidateVariableAndValue(variable, ref value);
+
+ // separated from the EnvironmentVariableTarget overload to help with tree shaking in common case
+ SetEnvironmentVariableCore(variable, value);
+ }
+
+ public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
+ {
+ ValidateVariableAndValue(variable, ref value);
+ ValidateTarget(target);
+
+ SetEnvironmentVariableCore(variable, value, target);
+ }
+
+ private static void ValidateVariableAndValue(string variable, ref string value)
+ {
+ const int MaxEnvVariableValueLength = 32767;
+
+ if (variable == null)
+ {
+ throw new ArgumentNullException(nameof(variable));
+ }
+ if (variable.Length == 0)
+ {
+ throw new ArgumentException(GetResourceString("Argument_StringZeroLength"), nameof(variable));
+ }
+ if (variable[0] == '\0')
+ {
+ throw new ArgumentException(GetResourceString("Argument_StringFirstCharIsZero"), nameof(variable));
+ }
+ if (variable.Length >= MaxEnvVariableValueLength)
+ {
+ throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(variable));
+ }
+ if (variable.IndexOf('=') != -1)
+ {
+ throw new ArgumentException(GetResourceString("Argument_IllegalEnvVarName"), nameof(variable));
+ }
+
+ if (string.IsNullOrEmpty(value) || value[0] == '\0')
+ {
+ // Explicitly null out value if it's empty
+ value = null;
+ }
+ else if (value.Length >= MaxEnvVariableValueLength)
+ {
+ throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(value));
+ }
+ }
+
+ private static void ValidateTarget(EnvironmentVariableTarget target)
+ {
+ if (target != EnvironmentVariableTarget.Process &&
+ target != EnvironmentVariableTarget.Machine &&
+ target != EnvironmentVariableTarget.User)
+ {
+ throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(GetResourceString("Arg_EnumIllegalVal"), target));
+ }
+ }
+
+ private static Dictionary<string, string> GetRawEnvironmentVariables()
+ {
+ // Format for GetEnvironmentStrings is:
+ // (=HiddenVar=value\0 | Variable=value\0)* \0
+ // See the description of Environment Blocks in MSDN's
+ // CreateProcess page (null-terminated array of null-terminated strings).
+ // Note the =HiddenVar's aren't always at the beginning.
+
+ // Copy strings out, parsing into pairs and inserting into the table.
+ // The first few environment variable entries start with an '='.
+ // The current working directory of every drive (except for those drives
+ // you haven't cd'ed into in your DOS window) are stored in the
+ // environment block (as =C:=pwd) and the program's exit code is
+ // as well (=ExitCode=00000000).
+
+ var results = new Dictionary<string, string>();
+ char[] block = GetEnvironmentCharArray();
+ for (int i = 0; i < block.Length; i++)
+ {
+ int startKey = i;
+
+ // Skip to key. On some old OS, the environment block can be corrupted.
+ // Some will not have '=', so we need to check for '\0'.
+ while (block[i] != '=' && block[i] != '\0') i++;
+ if (block[i] == '\0') continue;
+
+ // Skip over environment variables starting with '='
+ if (i - startKey == 0)
+ {
+ while (block[i] != 0) i++;
+ continue;
+ }
+
+ string key = new string(block, startKey, i - startKey);
+ i++; // skip over '='
+
+ int startValue = i;
+ while (block[i] != 0) i++; // Read to end of this entry
+ string value = new string(block, startValue, i - startValue); // skip over 0 handled by for loop's i++
+
+ results[key] = value;
+ }
+ return results;
+ }
+
+ private static string GetEnvironmentVariableCore(string variable)
+ {
+ if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode())
+ {
+ // Environment variable accessors are not approved modern API.
+ // Behave as if the variable was not found in this case.
+ return null;
+ }
+
+ StringBuilder sb = StringBuilderCache.Acquire(128); // A somewhat reasonable default size
+ int requiredSize = Win32Native.GetEnvironmentVariable(variable, sb, sb.Capacity);
+
+ if (requiredSize == 0 && Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND)
+ {
+ StringBuilderCache.Release(sb);
+ return null;
+ }
+
+ while (requiredSize > sb.Capacity)
+ {
+ sb.Capacity = requiredSize;
+ sb.Length = 0;
+ requiredSize = Win32Native.GetEnvironmentVariable(variable, sb, sb.Capacity);
+ }
+
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+
+ private static string GetEnvironmentVariableCore(string variable, EnvironmentVariableTarget target)
+ {
+ if (target == EnvironmentVariableTarget.Process)
+ return GetEnvironmentVariableCore(variable);
+
+#if !FEATURE_WIN32_REGISTRY
+ return null;
+#else
+ RegistryKey baseKey;
+ string keyName;
+
+ if (target == EnvironmentVariableTarget.Machine)
+ {
+ baseKey = Registry.LocalMachine;
+ keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
+ }
+ else if (target == EnvironmentVariableTarget.User)
+ {
+ Debug.Assert(target == EnvironmentVariableTarget.User);
+ baseKey = Registry.CurrentUser;
+ keyName = "Environment";
+ }
+ else
+ {
+ throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ }
+
+ using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
+ {
+ return environmentKey?.GetValue(variable) as string;
+ }
+#endif
+ }
+
+ private static IDictionary GetEnvironmentVariablesCore()
+ {
+ if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode())
+ {
+ // Environment variable accessors are not approved modern API.
+ // Behave as if no environment variables are defined in this case.
+ return new Dictionary<string, string>(0);
+ }
+
+ return GetRawEnvironmentVariables();
+ }
+
+ private static IDictionary GetEnvironmentVariablesCore(EnvironmentVariableTarget target)
+ {
+ if (target == EnvironmentVariableTarget.Process)
+ return GetEnvironmentVariablesCore();
+
+#if !FEATURE_WIN32_REGISTRY
+ // Without registry support we have nothing to return
+ return new Dictionary<string, string>(0);
+#else
+ RegistryKey baseKey;
+ string keyName;
+ if (target == EnvironmentVariableTarget.Machine)
+ {
+ baseKey = Registry.LocalMachine;
+ keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
+ }
+ else if (target == EnvironmentVariableTarget.User)
+ {
+ Debug.Assert(target == EnvironmentVariableTarget.User);
+ baseKey = Registry.CurrentUser;
+ keyName = @"Environment";
+ }
+ else
+ {
+ throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ }
+
+ using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
+ {
+ var table = new Dictionary<string, string>();
+ if (environmentKey != null)
+ {
+ foreach (string name in environmentKey.GetValueNames())
+ {
+ table.Add(name, environmentKey.GetValue(name, "").ToString());
+ }
+ }
+ return table;
+ }
+#endif // FEATURE_WIN32_REGISTRY
+ }
+
+ private static void SetEnvironmentVariableCore(string variable, string value)
+ {
+ // explicitly null out value if is the empty string.
+ if (string.IsNullOrEmpty(value) || value[0] == '\0')
+ value = null;
+
+ if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode())
+ {
+ // Environment variable accessors are not approved modern API.
+ // so we throw PlatformNotSupportedException.
+ throw new PlatformNotSupportedException();
+ }
+
+ if (!Win32Native.SetEnvironmentVariable(variable, value))
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+
+ switch (errorCode)
+ {
+ case Win32Native.ERROR_ENVVAR_NOT_FOUND:
+ // Allow user to try to clear a environment variable
+ return;
+ case Win32Native.ERROR_FILENAME_EXCED_RANGE:
+ // The error message from Win32 is "The filename or extension is too long",
+ // which is not accurate.
+ throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"));
+ default:
+ throw new ArgumentException(Win32Native.GetMessage(errorCode));
+ }
+ }
+ }
+
+ private static void SetEnvironmentVariableCore(string variable, string value, EnvironmentVariableTarget target)
+ {
+ if (target == EnvironmentVariableTarget.Process)
+ {
+ SetEnvironmentVariableCore(variable, value);
+ return;
+ }
+
+#if !FEATURE_WIN32_REGISTRY
+ // other targets ignored
+ return;
+#else
+ // explicitly null out value if is the empty string.
+ if (string.IsNullOrEmpty(value) || value[0] == '\0')
+ value = null;
+
+ RegistryKey baseKey;
+ string keyName;
+
+ if (target == EnvironmentVariableTarget.Machine)
+ {
+ baseKey = Registry.LocalMachine;
+ keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
+ }
+ else if (target == EnvironmentVariableTarget.User)
+ {
+ Debug.Assert(target == EnvironmentVariableTarget.User);
+
+ // User-wide environment variables stored in the registry are limited to 255 chars for the environment variable name.
+ const int MaxUserEnvVariableLength = 255;
+ if (variable.Length >= MaxUserEnvVariableLength)
+ {
+ throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(variable));
+ }
+
+ baseKey = Registry.CurrentUser;
+ keyName = "Environment";
+ }
+ else
+ {
+ throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ }
+
+ using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: true))
+ {
+ if (environmentKey != null)
+ {
+ if (value == null)
+ {
+ environmentKey.DeleteValue(variable, throwOnMissingValue: false);
+ }
+ else
+ {
+ environmentKey.SetValue(variable, value);
+ }
+ }
+ }
+
+ // send a WM_SETTINGCHANGE message to all windows
+ IntPtr r = Win32Native.SendMessageTimeout(new IntPtr(Win32Native.HWND_BROADCAST),
+ Win32Native.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
+
+ if (r == IntPtr.Zero) Debug.Assert(false, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
+#endif // FEATURE_WIN32_REGISTRY
+ }
}
}