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.cs476
1 files changed, 115 insertions, 361 deletions
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs
index 8fa4ce4ff5..b9070ae713 100644
--- a/src/mscorlib/src/System/Environment.cs
+++ b/src/mscorlib/src/System/Environment.cs
@@ -11,7 +11,9 @@
**
**
============================================================*/
-namespace System {
+
+namespace System
+{
using System.IO;
using System.Security;
using System.Resources;
@@ -37,145 +39,37 @@ namespace System {
Machine = 2,
}
- public static partial class Environment
+ internal 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
+ private const int MaxEnvVariableValueLength = 32767; // maximum length for environment variable name and value
// System environment variables are stored in the registry, and have
// a size restriction that is separate from both normal environment
// variables and registry value name lengths, according to MSDN.
// MSDN doesn't detail whether the name is limited to 1024, or whether
// that includes the contents of the environment variable.
- const int MaxSystemEnvVariableLength = 1024;
- const int MaxUserEnvVariableLength = 255;
+ private const int MaxSystemEnvVariableLength = 1024;
+ private const int MaxUserEnvVariableLength = 255;
+ private const int MaxMachineNameLength = 256;
- internal sealed class ResourceHelper
+ // 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
+ internal static String GetResourceStringLocal(String key)
{
- internal ResourceHelper(String name) {
- m_name = name;
- }
-
- private String m_name;
- private ResourceManager SystemResMgr;
-
- // To avoid infinite loops when calling GetResourceString. See comments
- // in GetResourceString for this field.
- private List<string> currentlyLoading;
-
- // process-wide state (since this is only used in one domain),
- // used to avoid the TypeInitialization infinite recusion
- // in GetResourceStringCode
- internal bool resourceManagerInited = false;
-
- // Is this thread currently doing infinite resource lookups?
- private int infinitelyRecursingCount;
-
- internal String GetResourceString(String key) {
- if (key == null || key.Length == 0) {
- 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]";
- }
-
- // We have a somewhat common potential for infinite
- // loops with mscorlib's ResourceManager. If "potentially dangerous"
- // code throws an exception, we will get into an infinite loop
- // inside the ResourceManager and this "potentially dangerous" code.
- // Potentially dangerous code includes the IO package, CultureInfo,
- // parts of the loader, some parts of Reflection, Security (including
- // custom user-written permissions that may parse an XML file at
- // class load time), assembly load event handlers, etc. Essentially,
- // this is not a bounded set of code, and we need to fix the problem.
- // Fortunately, this is limited to mscorlib's error lookups and is NOT
- // a general problem for all user code using the ResourceManager.
-
- // The solution is to make sure only one thread at a time can call
- // GetResourceString. Also, since resource lookups can be
- // reentrant, if the same thread comes into GetResourceString
- // twice looking for the exact same resource name before
- // returning, we're going into an infinite loop and we should
- // return a bogus string.
-
- bool lockTaken = false;
- try
- {
- Monitor.Enter(this, ref lockTaken);
-
- // Are we recursively looking up the same resource? Note - our backout code will set
- // the ResourceHelper's currentlyLoading stack to null if an exception occurs.
- if (currentlyLoading != null && currentlyLoading.Count > 0 && currentlyLoading.LastIndexOf(key) != -1)
- {
- // We can start infinitely recursing for one resource lookup,
- // then during our failure reporting, start infinitely recursing again.
- // avoid that.
- if (infinitelyRecursingCount > 0)
- {
- return "[Resource lookup failed - infinite recursion or critical failure detected.]";
- }
- infinitelyRecursingCount++;
-
- // Note: our infrastructure for reporting this exception will again cause resource lookup.
- // This is the most direct way of dealing with that problem.
- string message = $"Infinite recursion during resource lookup within {System.CoreLib.Name}. This may be a bug in {System.CoreLib.Name}, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names. Resource name: {key}";
- Assert.Fail("[Recursive resource lookup bug]", message, Assert.COR_E_FAILFAST, System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
- Environment.FailFast(message);
- }
- if (currentlyLoading == null)
- currentlyLoading = new List<string>();
-
- // Call class constructors preemptively, so that we cannot get into an infinite
- // loop constructing a TypeInitializationException. If this were omitted,
- // we could get the Infinite recursion assert above by failing type initialization
- // between the Push and Pop calls below.
- if (!resourceManagerInited)
- {
- RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
- RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
- RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
- RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
- resourceManagerInited = true;
- }
-
- currentlyLoading.Add(key); // Push
-
- if (SystemResMgr == null)
- {
- SystemResMgr = new ResourceManager(m_name, typeof(Object).Assembly);
- }
- string s = SystemResMgr.GetString(key, null);
- currentlyLoading.RemoveAt(currentlyLoading.Count - 1); // Pop
-
- 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 + "\"");
- return s;
- }
- catch
- {
- if (lockTaken)
- {
- // Backout code - throw away potentially corrupt state
- SystemResMgr = null;
- currentlyLoading = null;
- }
- throw;
- }
- finally
- {
- if (lockTaken)
- {
- Monitor.Exit(this);
- }
- }
- }
+ return SR.GetResourceString(key);
}
- private static volatile ResourceHelper m_resHelper; // Doesn't need to be initialized as they're zero-init.
-
- private const int MaxMachineNameLength = 256;
-
// Private object for locking instead of locking on a public type for SQL reliability work.
private static Object s_InternalSyncObject;
- private static Object InternalSyncObject {
- get {
- if (s_InternalSyncObject == null) {
+ private static Object InternalSyncObject
+ {
+ get
+ {
+ if (s_InternalSyncObject == null)
+ {
Object o = new Object();
Interlocked.CompareExchange<Object>(ref s_InternalSyncObject, o, null);
}
@@ -192,25 +86,28 @@ namespace System {
**Arguments: None
**Exceptions: None
==============================================================================*/
- public static extern int TickCount {
+ public static extern int TickCount
+ {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
-
+
// Terminates this process with the given exit code.
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
internal static extern void _Exit(int exitCode);
- public static void Exit(int exitCode) {
+ public static void Exit(int exitCode)
+ {
_Exit(exitCode);
}
- public static extern int ExitCode {
+ public static extern int ExitCode
+ {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
-
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
set;
}
@@ -246,22 +143,26 @@ namespace System {
==============================================================================*/
internal static String CurrentDirectory
{
- get{
+ get
+ {
return Directory.GetCurrentDirectory();
}
- set {
+ set
+ {
Directory.SetCurrentDirectory(value);
}
}
// Returns the system directory (ie, C:\WinNT\System32).
- internal static String SystemDirectory {
- get {
+ internal static String SystemDirectory
+ {
+ get
+ {
StringBuilder sb = new StringBuilder(Path.MaxPath);
int r = Win32Native.GetSystemDirectory(sb, Path.MaxPath);
Debug.Assert(r < Path.MaxPath, "r < Path.MaxPath");
- if (r==0) __Error.WinIOError();
+ if (r == 0) __Error.WinIOError();
String path = sb.ToString();
return path;
@@ -274,16 +175,11 @@ namespace System {
throw new ArgumentNullException(nameof(name));
Contract.EndContractBlock();
- if (name.Length == 0) {
+ if (name.Length == 0)
+ {
return name;
}
- if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
- // Environment variable accessors are not approved modern API.
- // Behave as if no variables are defined in this case.
- return name;
- }
-
int currentSize = 100;
StringBuilder blob = new StringBuilder(currentSize); // A somewhat reasonable default size
@@ -314,8 +210,9 @@ namespace System {
size = Win32Native.ExpandEnvironmentStrings(name, blob, currentSize);
if (size == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
-
- while (size > currentSize) {
+
+ while (size > currentSize)
+ {
currentSize = size;
blob.Capacity = currentSize;
blob.Length = 0;
@@ -329,32 +226,14 @@ namespace System {
return blob.ToString();
}
- public static String MachineName {
- get {
-
- // UWP Debug scenarios
- if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode())
- {
- // Getting Computer Name is not a supported scenario on Store apps.
- throw new PlatformNotSupportedException();
- }
-
- // In future release of operating systems, you might be able to rename a machine without
- // rebooting. Therefore, don't cache this machine name.
- StringBuilder buf = new StringBuilder(MaxMachineNameLength);
- int len = MaxMachineNameLength;
- if (Win32Native.GetComputerName(buf, ref len) == 0)
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ComputerName"));
- return buf.ToString();
- }
- }
-
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern Int32 GetProcessorCount();
- public static int ProcessorCount {
- get {
+ public static int ProcessorCount
+ {
+ get
+ {
return GetProcessorCount();
}
}
@@ -381,7 +260,7 @@ namespace System {
* So our best bet is to simply use the commandLine that was used to invoke the process.
* in case it is present.
*/
- if(s_CommandLineArgs != null)
+ if (s_CommandLineArgs != null)
return (string[])s_CommandLineArgs.Clone();
return GetCommandLineArgsNative();
@@ -450,91 +329,70 @@ namespace System {
**Arguments: None.
**Exceptions: None.
==============================================================================*/
- public static String NewLine {
- get {
+ public static String NewLine
+ {
+ get
+ {
Contract.Ensures(Contract.Result<String>() != null);
-#if !PLATFORM_UNIX
+#if PLATFORM_WINDOWS
return "\r\n";
#else
return "\n";
-#endif // !PLATFORM_UNIX
+#endif // PLATFORM_WINDOWS
}
}
-
+
/*===================================Version====================================
**Action: Returns the COM+ version struct, describing the build number.
**Returns:
**Arguments:
**Exceptions:
==============================================================================*/
- public static Version Version {
- get {
-
+ public static Version Version
+ {
+ get
+ {
// 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
// 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
// scheme that matched the product version. In order to preserve compatibility with existing libraries, this needs to be hard-coded.
-
- return new Version(4,0,30319,42000);
- }
- }
-
- /*==================================OSVersion===================================
- **Action:
- **Returns:
- **Arguments:
- **Exceptions:
- ==============================================================================*/
- internal static OperatingSystem OSVersion {
- get {
- Contract.Ensures(Contract.Result<OperatingSystem>() != null);
-
- if (m_os==null) { // We avoid the lock since we don't care if two threads will set this at the same time.
-
- Microsoft.Win32.Win32Native.OSVERSIONINFO osvi = new Microsoft.Win32.Win32Native.OSVERSIONINFO();
- if (!GetVersion(osvi)) {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_GetVersion"));
- }
-
- Microsoft.Win32.Win32Native.OSVERSIONINFOEX osviEx = new Microsoft.Win32.Win32Native.OSVERSIONINFOEX();
- if (!GetVersionEx(osviEx))
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_GetVersion"));
-#if PLATFORM_UNIX
- PlatformID id = PlatformID.Unix;
-#else
- PlatformID id = PlatformID.Win32NT;
-#endif // PLATFORM_UNIX
-
- Version v = new Version(osvi.MajorVersion, osvi.MinorVersion, osvi.BuildNumber, (osviEx.ServicePackMajor << 16) |osviEx.ServicePackMinor);
- m_os = new OperatingSystem(id, v, osvi.CSDVersion);
- }
- Debug.Assert(m_os != null, "m_os != null");
- return m_os;
+ return new Version(4, 0, 30319, 42000);
}
}
+#if !FEATURE_PAL
+ private static Lazy<bool> s_IsWindows8OrAbove = new Lazy<bool>(() =>
+ {
+ ulong conditionMask = Win32Native.VerSetConditionMask(0, Win32Native.VER_MAJORVERSION, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_MINORVERSION, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMAJOR, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMINOR, Win32Native.VER_GREATER_EQUAL);
- internal static bool IsWindows8OrAbove {
- get {
- return true;
- }
- }
-
+ // Windows 8 version is 6.2
+ var version = new Win32Native.OSVERSIONINFOEX { MajorVersion = 6, MinorVersion = 2, ServicePackMajor = 0, ServicePackMinor = 0 };
+
+ return Win32Native.VerifyVersionInfoW(version,
+ Win32Native.VER_MAJORVERSION | Win32Native.VER_MINORVERSION | Win32Native.VER_SERVICEPACKMAJOR | Win32Native.VER_SERVICEPACKMINOR,
+ conditionMask);
+ });
+ internal static bool IsWindows8OrAbove => s_IsWindows8OrAbove.Value;
+#endif
+
#if FEATURE_COMINTEROP
- internal static bool IsWinRTSupported {
- get {
- return true;
- }
- }
-#endif // FEATURE_COMINTEROP
-
+ // Does the current version of Windows have Windows Runtime suppport?
+ private static Lazy<bool> s_IsWinRTSupported = new Lazy<bool>(() =>
+ {
+ return WinRTSupported();
+ });
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool GetVersion(Microsoft.Win32.Win32Native.OSVERSIONINFO osVer);
+ internal static bool IsWinRTSupported => s_IsWinRTSupported.Value;
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool GetVersionEx(Microsoft.Win32.Win32Native.OSVERSIONINFOEX osVer);
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool WinRTSupported();
+#endif // FEATURE_COMINTEROP
/*==================================StackTrace==================================
@@ -543,11 +401,13 @@ namespace System {
**Arguments:
**Exceptions:
==============================================================================*/
- public static String StackTrace {
- get {
+ public static String StackTrace
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
+ get
+ {
Contract.Ensures(Contract.Result<String>() != null);
-
- return GetStackTrace(null, true);
+ return Internal.Runtime.Augments.EnvironmentAugments.StackTrace;
}
}
@@ -564,104 +424,19 @@ namespace System {
st = new StackTrace(e, needFileInfo);
// Do no include a trailing newline for backwards compatibility
- return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
- }
-
- private static void InitResourceHelper() {
- // Only the default AppDomain should have a ResourceHelper. All calls to
- // GetResourceString from any AppDomain delegate to GetResourceStringLocal
- // in the default AppDomain via the fcall GetResourceFromDefault.
-
- bool tookLock = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
-
- Monitor.Enter(Environment.InternalSyncObject, ref tookLock);
-
- if (m_resHelper == null) {
- ResourceHelper rh = new ResourceHelper(System.CoreLib.Name);
-
- System.Threading.Thread.MemoryBarrier();
- m_resHelper =rh;
- }
- }
- finally {
- if (tookLock)
- Monitor.Exit(Environment.InternalSyncObject);
- }
- }
-
- // 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
- // 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();
-
- return m_resHelper.GetResourceString(key);
- }
-
- internal static String GetResourceString(String key) {
- return GetResourceStringLocal(key);
- }
-
- // 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 });
- }
-
- 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, params object[] values)
- {
- return GetResourceStringFormatted(key, values);
+ return st.ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
}
- // 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)
+ public static extern bool HasShutdownStarted
{
- string rs = GetResourceString(key);
- return String.Format(CultureInfo.CurrentCulture, rs, values);
- }
-
- public static extern bool HasShutdownStarted {
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
internal static bool UserInteractive
{
- get {
+ get
+ {
return true;
}
}
@@ -684,11 +459,11 @@ namespace System {
// TODO: Consider flushing the executionIdCache on Wait operations or similar
// actions that are likely to result in changing the executing core
[ThreadStatic]
- static int t_executionIdCache;
+ private static int t_executionIdCache;
- const int ExecutionIdCacheShift = 16;
- const int ExecutionIdCacheCountDownMask = (1 << ExecutionIdCacheShift) - 1;
- const int ExecutionIdRefreshRate = 5000;
+ private const int ExecutionIdCacheShift = 16;
+ private const int ExecutionIdCacheCountDownMask = (1 << ExecutionIdCacheShift) - 1;
+ private const int ExecutionIdRefreshRate = 5000;
private static int RefreshExecutionId()
{
@@ -784,19 +559,19 @@ namespace System {
}
if (variable.Length == 0)
{
- throw new ArgumentException(GetResourceString("Argument_StringZeroLength"), nameof(variable));
+ throw new ArgumentException(SR.Argument_StringZeroLength, nameof(variable));
}
if (variable[0] == '\0')
{
- throw new ArgumentException(GetResourceString("Argument_StringFirstCharIsZero"), nameof(variable));
+ throw new ArgumentException(SR.Argument_StringFirstCharIsZero, nameof(variable));
}
if (variable.Length >= MaxEnvVariableValueLength)
{
- throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(variable));
+ throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable));
}
if (variable.IndexOf('=') != -1)
{
- throw new ArgumentException(GetResourceString("Argument_IllegalEnvVarName"), nameof(variable));
+ throw new ArgumentException(SR.Argument_IllegalEnvVarName, nameof(variable));
}
if (string.IsNullOrEmpty(value) || value[0] == '\0')
@@ -806,7 +581,7 @@ namespace System {
}
else if (value.Length >= MaxEnvVariableValueLength)
{
- throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(value));
+ throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(value));
}
}
@@ -816,7 +591,7 @@ namespace System {
target != EnvironmentVariableTarget.Machine &&
target != EnvironmentVariableTarget.User)
{
- throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(GetResourceString("Arg_EnumIllegalVal"), target));
+ throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target));
}
}
@@ -867,13 +642,6 @@ namespace System {
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);
@@ -917,7 +685,7 @@ namespace System {
}
else
{
- throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)target));
}
using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
@@ -929,13 +697,6 @@ namespace System {
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();
}
@@ -963,7 +724,7 @@ namespace System {
}
else
{
- throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)target));
}
using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
@@ -987,13 +748,6 @@ namespace System {
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();
@@ -1006,7 +760,7 @@ namespace System {
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"));
+ throw new ArgumentException(SR.Format(SR.Argument_LongEnvVarValue));
default:
throw new ArgumentException(Win32Native.GetMessage(errorCode));
}
@@ -1045,7 +799,7 @@ namespace System {
const int MaxUserEnvVariableLength = 255;
if (variable.Length >= MaxUserEnvVariableLength)
{
- throw new ArgumentException(GetResourceString("Argument_LongEnvVarValue"), nameof(variable));
+ throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable));
}
baseKey = Registry.CurrentUser;
@@ -1053,7 +807,7 @@ namespace System {
}
else
{
- throw new ArgumentException(GetResourceString("Arg_EnumIllegalVal", (int)target));
+ throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)target));
}
using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: true))
@@ -1066,7 +820,7 @@ namespace System {
}
else
{
- environmentKey.SetValue(variable, value);
+ environmentKey.SetStringValue(variable, value);
}
}
}