File: system\environment.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** Class: Environment
**
**
** Purpose: Provides some basic access to some environment 
** functionality.
**
**
============================================================*/
namespace System {
    using System.IO;
    using System.Security;
    using System.Resources;
    using System.Globalization;
    using System.Collections;
    using System.Security.Permissions;
    using System.Text;
    using System.Configuration.Assemblies;
    using System.Runtime.InteropServices;
    using System.Reflection;
    using System.Diagnostics;
    using Microsoft.Win32;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
 
#if !FEATURE_PAL
    [ComVisible(true)]
    public enum EnvironmentVariableTarget {
        Process = 0,
#if FEATURE_WIN32_REGISTRY            
        User = 1,
        Machine = 2,
#endif        
    }
#endif 
 
    [ComVisible(true)]
    public static 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 
        // 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;
 
        internal sealed class ResourceHelper
        {
            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 Stack 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;
 
            // Data representing one individual resource lookup on a thread.
            internal class GetResourceStringUserData
            {
                public ResourceHelper m_resourceHelper;
                public String m_key;
                public CultureInfo m_culture;
                public String m_retVal;
                public bool m_lockWasTaken;
 
                public GetResourceStringUserData(ResourceHelper resourceHelper, String key, CultureInfo culture)
                {
                    m_resourceHelper = resourceHelper;
                    m_key = key;
                    m_culture = culture;
                }
            }
            
            [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?");
                    return "[Resource lookup failed - null or empty resource name]";
                }
                return GetResourceString(key, null);
            }
 
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
            internal String GetResourceString(String key, CultureInfo culture)  {
                if (key == null || key.Length == 0) {
                    Contract.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.  
 
                GetResourceStringUserData userData = new GetResourceStringUserData(this, key, culture);
 
                RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(GetResourceStringCode);
                RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(GetResourceStringBackoutCode);
 
                RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, userData);
                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;
                ResourceHelper rh = userData.m_resourceHelper;
                String key = userData.m_key;
                CultureInfo culture = userData.m_culture;
 
                Monitor.Enter(rh, ref userData.m_lockWasTaken);
 
                // 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 (rh.currentlyLoading != null && rh.currentlyLoading.Count > 0 && rh.currentlyLoading.Contains(key)) {
                    // We can start infinitely recursing for one resource lookup,
                    // then during our failure reporting, start infinitely recursing again.
                    // avoid that.
                    if (rh.infinitelyRecursingCount > 0) {
                        userData.m_retVal = "[Resource lookup failed - infinite recursion or critical failure detected.]";
                        return;
                    }
                    rh.infinitelyRecursingCount++;
                    // This is often a 
 
 
 
 
 
 
                    // 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 mscorlib.  This may be a bug in mscorlib, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names.  Resource name: " + key;
                    Assert.Fail("[mscorlib recursive resource lookup bug]", message, Assert.COR_E_FAILFAST, System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
                    Environment.FailFast(message);
                }
                if (rh.currentlyLoading == null)
                    rh.currentlyLoading = new Stack(4);
 
                // 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 (!rh.resourceManagerInited)
                {
                    // process-critical code here.  No ThreadAbortExceptions
                    // can be thrown here.  Other exceptions percolate as normal.
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                    }
                    finally {
                        RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
                        rh.resourceManagerInited = true; 
                    }
            
                } 
        
                rh.currentlyLoading.Push(key);
 
                if (rh.SystemResMgr == null) {
                    rh.SystemResMgr = new ResourceManager(m_name, typeof(Object).Assembly);
                }
                String s = rh.SystemResMgr.GetString(key, null);
                rh.currentlyLoading.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+"\"");
 
                userData.m_retVal = s;
            }
 
            #if FEATURE_CORECLR
            [System.Security.SecurityCritical] // auto-generated
            #endif
            [PrePrepareMethod]
            private void GetResourceStringBackoutCode(Object userDataIn, bool exceptionThrown)
            {
                GetResourceStringUserData userData = (GetResourceStringUserData) userDataIn;
                ResourceHelper rh = userData.m_resourceHelper;
 
                if (exceptionThrown)
                {
                    if (userData.m_lockWasTaken) 
                    {
                        // Backout code - throw away potentially corrupt state
                        rh.SystemResMgr = null;
                        rh.currentlyLoading = null;
                    }
                }
                // Release the lock, if we took it.
                if (userData.m_lockWasTaken)
                {
                    Monitor.Exit(rh);
                }
            }
        
        }
 
              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 {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
            get {
                if (s_InternalSyncObject == null) {
                    Object o = new Object();
                    Interlocked.CompareExchange<Object>(ref s_InternalSyncObject, o, null);
                }
                return s_InternalSyncObject;
            }
        }
 
 
        private static volatile OperatingSystem m_os;  // Cached OperatingSystem value
 
        /*==================================TickCount===================================
        **Action: Gets the number of ticks since the system was started.
        **Returns: The number of ticks since the system was started.
        **Arguments: None
        **Exceptions: None
        ==============================================================================*/
        public static extern int TickCount {
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.None)]
            [MethodImplAttribute(MethodImplOptions.InternalCall)]
            get;
        }
        
        // Terminates this process with the given exit code.
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
        [SuppressUnmanagedCodeSecurity]
        internal static extern void _Exit(int exitCode);
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
#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
            [ResourceExposure(ResourceScope.None)]
            [MethodImplAttribute(MethodImplOptions.InternalCall)]
            get;
    
            [System.Security.SecuritySafeCritical]  // auto-generated
            [ResourceExposure(ResourceScope.None)]
            [MethodImplAttribute(MethodImplOptions.InternalCall)]
            set;
        }
 
        // 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]
        [ResourceExposure(ResourceScope.Process)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void FailFast(String message);
 
        [System.Security.SecurityCritical]
        [ResourceExposure(ResourceScope.Process)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern void FailFast(String message, uint exitCode);
 
        // This overload of FailFast will allow you to specify the exception object
        // whose bucket details *could* be used when undergoing the failfast process.
        // To be specific:
        //
        // 1) When invoked from within a managed EH clause (fault/finally/catch),
        //    if the exception object is preallocated, the runtime will try to find its buckets
        //    and use them. If the exception object is not preallocated, it will use the bucket
        //    details contained in the object (if any).
        //
        // 2) When invoked from outside the managed EH clauses (fault/finally/catch),
        //    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]
        [ResourceExposure(ResourceScope.Process)]
        [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.
        [ResourceExposure(ResourceScope.None)]
        [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.
        [ResourceExposure(ResourceScope.None)]
        [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
        [ResourceExposure(ResourceScope.None)]
        [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.  
        **Returns: The current directory (from the getter).  Void from the setter.
        **Arguments: The current directory to which to switch to the setter.
        **Exceptions: 
        ==============================================================================*/
        public static String CurrentDirectory
        {
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get{
                return Directory.GetCurrentDirectory();
            }
 
            #if FEATURE_CORECLR
            [System.Security.SecurityCritical] // auto-generated
            #endif
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            set { 
                Directory.SetCurrentDirectory(value);
            }
        }
 
        // 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
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                StringBuilder sb = new StringBuilder(Path.MAX_PATH);
                int r = Win32Native.GetSystemDirectory(sb, Path.MAX_PATH);
                Contract.Assert(r < Path.MAX_PATH, "r < Path.MAX_PATH");
                if (r==0) __Error.WinIOError();
                String path = sb.ToString();
                
#if !FEATURE_CORECLR
                // Do security check
                FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, path);
#endif
 
                return path;
            }
        }
 
#if !FEATURE_PAL
        // 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
            [ResourceExposure(ResourceScope.Machine)]
            [ResourceConsumption(ResourceScope.Machine)]
            get {
                StringBuilder sb = new StringBuilder(Path.MAX_PATH);
                int r = Win32Native.GetWindowsDirectory(sb, Path.MAX_PATH);
                Contract.Assert(r < Path.MAX_PATH, "r < Path.MAX_PATH");
                if (r==0) __Error.WinIOError();
                String path = sb.ToString();
                
                return path;
            }
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        public static String ExpandEnvironmentVariables(String name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            Contract.EndContractBlock();
 
            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
            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)
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            
            while (size > currentSize) {
                currentSize = size;
                blob.Capacity = currentSize;
                blob.Length = 0;
 
                size = Win32Native.ExpandEnvironmentStrings(name, blob, currentSize);
                if (size == 0)
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
 
            return blob.ToString();
        }
#endif // FEATURE_PAL
 
        public static String MachineName {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get {
                // In future release of operating systems, you might be able to rename a machine without
                // rebooting.  Therefore, don't cache this machine name.
                new EnvironmentPermission(EnvironmentPermissionAccess.Read, "COMPUTERNAME").Demand();
                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();
            }
        }
 
        [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();
                Win32Native.GetSystemInfo(ref info);
                return info.dwPageSize;
            }
        }
 
#if !FEATURE_CORECLR
        /*==============================GetCommandLineArgs==============================
        **Action: Gets the command line and splits it appropriately to deal with whitespace,
        **        quotes, and escape characters.
        **Returns: A string array containing your command line arguments.
        **Arguments: None
        **Exceptions: None.
        ==============================================================================*/
        [System.Security.SecuritySafeCritical]  // auto-generated
        public static String[] GetCommandLineArgs() {
            new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
            return GetCommandLineArgsNative();
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern String[] GetCommandLineArgsNative();
        
        // 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
        [ResourceExposure(ResourceScope.Process)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern String nativeGetEnvironmentVariable(String variable);
#endif //!FEATURE_CORECLR
        
        /*============================GetEnvironmentVariable============================
        **Action:
        **Returns:
        **Arguments:
        **Exceptions:
        ==============================================================================*/
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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);
        }
        
#if !FEATURE_PAL
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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));
            }
        }
#endif
 
        /*===========================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
        [ResourceExposure(ResourceScope.Machine)]
        private unsafe static char[] GetEnvironmentCharArray()
        {
            char[] block = null;
 
            // Make sure pStrings is not leaked with async exceptions
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
            }
            finally {
                char * pStrings = null;
 
                try
                {
                    pStrings = Win32Native.GetEnvironmentStrings();
                    if (pStrings == null) {
                        throw new OutOfMemoryException();
                    }
 
                    // 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).
 
                    // Search for terminating \0\0 (two unicode \0's).
                    char * p = pStrings;
                    while (!(*p == '\0' && *(p + 1) == '\0'))
                        p++;
 
                    int len = (int)(p - pStrings + 1);
                    block = new char[len];
 
                    fixed (char* pBlock = block)
                        String.wstrcpy(pBlock, pStrings, len);
                }
                finally
                {
                    if (pStrings != null)
                        Win32Native.FreeEnvironmentStrings(pStrings);
                }
            }
 
            return block;
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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_PAL
        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;
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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));
            }
        }
#endif
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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();
        }
 
#if !FEATURE_PAL
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        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
        }
#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();
                                 
            int drives = Win32Native.GetLogicalDrives();
            if (drives==0)
                __Error.WinIOError();
            uint d = (uint)drives;
            int count = 0;
            while (d != 0) {
                if (((int)d & 1) != 0) count++;
                d >>= 1;
            }
            String[] result = new String[count];
            char[] root = new char[] {'A', ':', '\\'};
            d = (uint)drives;
            count = 0;
            while (d != 0) {
                if (((int)d & 1) != 0) {
                    result[count++] = new String(root);
                }
                d >>= 1;
                root[0]++;
            }
            return result;
        }
        
        /*===================================NewLine====================================
        **Action: A property which returns the appropriate newline string for the given
        **        platform.
        **Returns: \r\n on Win32.
        **Arguments: None.
        **Exceptions: None.
        ==============================================================================*/
        public static String NewLine {
            get {
                Contract.Ensures(Contract.Result<String>() != null);
                return "\r\n";
            }
        }
 
        
        /*===================================Version====================================
        **Action: Returns the COM+ version struct, describing the build number.
        **Returns:
        **Arguments:
        **Exceptions:
        ==============================================================================*/
        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);
            }
        }
 
        
        /*==================================WorkingSet==================================
        **Action:
        **Returns:
        **Arguments:
        **Exceptions:
        ==============================================================================*/
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [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();
            }
        }
 
 
        /*==================================OSVersion===================================
        **Action:
        **Returns:
        **Arguments:
        **Exceptions:
        ==============================================================================*/
        public static OperatingSystem OSVersion {
            [System.Security.SecuritySafeCritical]  // auto-generated
            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"));
 
                    PlatformID id = PlatformID.Win32NT;
 
#if FEATURE_LEGACYNETCF
                    // return platform as WinCE, to ensure apps earlier than WP8 works as expected. 
                    if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
                    {
                        id = PlatformID.WinCE;
                    }
#endif
 
                    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");
                return m_os;
            }
        }
 
#if FEATURE_CORESYSTEM

        internal static bool IsWindows8OrAbove {
            get {
                return true;
            }
        }
 
#if FEATURE_COMINTEROP
        internal static bool IsWinRTSupported {
            get {
                return true;
            }
        }
#endif // FEATURE_COMINTEROP

#else // FEATURE_CORESYSTEM
 
        private static volatile bool s_IsWindows8OrAbove;
        private static volatile bool s_CheckedOSWin8OrAbove;
 
        // Windows 8 version is 6.2
        internal static bool IsWindows8OrAbove {
            get {
                if (!s_CheckedOSWin8OrAbove) {
                    OperatingSystem OS = Environment.OSVersion;
                    s_IsWindows8OrAbove = (OS.Platform == PlatformID.Win32NT && 
                                   ((OS.Version.Major == 6 && OS.Version.Minor >= 2) || (OS.Version.Major > 6)));
                    s_CheckedOSWin8OrAbove = true;
                }
                return s_IsWindows8OrAbove;
            }
        }
 
#if FEATURE_COMINTEROP
        private static volatile bool s_WinRTSupported;
        private static volatile bool s_CheckedWinRT;
 
        // Does the current version of Windows have Windows Runtime suppport?
        internal static bool IsWinRTSupported {
            [SecuritySafeCritical]
            get {
                if (!s_CheckedWinRT) {
                    s_WinRTSupported = WinRTSupported();
                    s_CheckedWinRT = true;
                }
 
                return s_WinRTSupported;
            }
        }
 
        [SecurityCritical]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool WinRTSupported();
#endif // FEATURE_COMINTEROP
 
#endif // FEATURE_CORESYSTEM
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool GetVersion(Microsoft.Win32.Win32Native.OSVERSIONINFO  osVer);
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool GetVersionEx(Microsoft.Win32.Win32Native.OSVERSIONINFOEX  osVer);
 
 
        /*==================================StackTrace==================================
        **Action:
        **Returns:
        **Arguments:
        **Exceptions:
        ==============================================================================*/
        public static String StackTrace {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get {
                Contract.Ensures(Contract.Result<String>() != null);
 
                new EnvironmentPermission(PermissionState.Unrestricted).Demand();
                return GetStackTrace(null, true);
            }
        }
 
        #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
            // apartment state.  Try to not call this when passing "true" 
            // before the EE's ExecuteMainMethod has had a chance to set up the
            // apartment state.  -- 
            StackTrace st;
            if (e == null)
                st = new StackTrace(needFileInfo);
            else
                st = new StackTrace(e, needFileInfo);
 
            // Do no include a trailing newline for backwards compatibility
            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 
            // 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("mscorlib");
 
                    System.Threading.Thread.MemoryBarrier();
                    m_resHelper =rh;
                }
            }
            finally {
                if (tookLock)
                    Monitor.Exit(Environment.InternalSyncObject);
            }
        }
 
#if !FEATURE_CORECLR
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [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
        internal static String GetResourceStringLocal(String key) {
            if (m_resHelper == null)
                InitResourceHelper();
 
            return m_resHelper.GetResourceString(key);
        }
 
        // #threadCultureInfo
        // Currently in silverlight, CurrentCulture and CurrentUICulture are isolated 
        // within an AppDomain. This is in contrast to the desktop, in which cultures 
        // leak across AppDomain boundaries with the thread. 
        // 
        // Note that mscorlib transitions to the default domain to perform resource 
        // lookup. This causes problems for the silverlight changes: since culture isn't
        // passed, resource string lookup won't necessarily use the culture of the thread 
        // originating the request. To get around that problem, we pass the CultureInfo 
        // so that the ResourceManager GetString(x, cultureInfo) overload can be used. 
        // We first perform the same check as in CultureInfo to make sure it's safe to 
        // let the CultureInfo travel across AppDomains. 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        internal static String GetResourceString(String key) {
#if FEATURE_CORECLR
            return GetResourceStringLocal(key);
#else
            return GetResourceFromDefault(key);
#endif //FEATURE_CORECLR
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        internal static String GetResourceString(String key, params Object[] values) {
            String s = GetResourceString(key);
            return String.Format(CultureInfo.CurrentCulture, s, 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 
        [ResourceExposure(ResourceScope.None)]
        internal static String GetRuntimeResourceString(String key) {
            return GetResourceString(key);
        }
 
        [ResourceExposure(ResourceScope.None)]
        internal static String GetRuntimeResourceString(String key, params Object[] values) {
            return GetResourceString(key,values);
        }
 
        public static bool Is64BitProcess {
            get {
                #if WIN32
                    return false;
                #else
                    return true;
                #endif
            }
        }
 
#if !FEATURE_PAL
        public static bool Is64BitOperatingSystem {
            [System.Security.SecuritySafeCritical]
            get {
                #if WIN32                    
                    bool isWow64; // WinXP SP2+ and Win2k3 SP1+
                    return Win32Native.DoesWin32MethodExist(Win32Native.KERNEL32, "IsWow64Process")
                        && Win32Native.IsWow64Process(Win32Native.GetCurrentProcess(), out isWow64)
                        && isWow64;
                #else
                    // 64-bit programs run only on 64-bit
                    //<
                    return true;
                #endif
            }
        }
#endif
 
        public static extern bool HasShutdownStarted {
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
            get;
        }
 
#if !FEATURE_CORECLR
        // This is the temporary Whidbey stub for compatibility flags
        [ResourceExposure(ResourceScope.None)]
        [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();
 
                StringBuilder sb = new StringBuilder(256);
                int size = sb.Capacity;
                if (Win32Native.GetUserName(sb, ref size))
                {
                    return sb.ToString();
                }
                return String.Empty;
            }
        }
 
        // 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_PAL && !FEATURE_CORESYSTEM
        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
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            get {
#if !FEATURE_PAL && !FEATURE_CORESYSTEM
                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
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static string GetFolderPath(SpecialFolder folder) {
            if (!Enum.IsDefined(typeof(SpecialFolder), folder))
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
            Contract.EndContractBlock();
 
            return InternalGetFolderPath(folder, SpecialFolderOption.None);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) {
            if (!Enum.IsDefined(typeof(SpecialFolder),folder))
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
            if (!Enum.IsDefined(typeof(SpecialFolderOption),option))
                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)option));
            Contract.EndContractBlock();
 
            return InternalGetFolderPath(folder, option);
        }
 
        [System.Security.SecurityCritical]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        internal static string UnsafeGetFolderPath(SpecialFolder folder)
        {
            return InternalGetFolderPath(folder, SpecialFolderOption.None, suppressSecurityChecks: true);
        }
 
        [System.Security.SecurityCritical]
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        private static string InternalGetFolderPath(SpecialFolder folder, SpecialFolderOption option, bool suppressSecurityChecks = false)
        {
#if FEATURE_CORESYSTEM
            // This is currently customized for Windows Phone since CoreSystem doesn't support
            // SHGetFolderPath. The allowed folder values are based on the version of .NET CF WP7 was using.
            switch (folder)
            {
                case SpecialFolder.System:
                    return SystemDirectory;
                case SpecialFolder.ApplicationData:
                case SpecialFolder.Favorites:
                case SpecialFolder.Programs:
                case SpecialFolder.StartMenu:
                case SpecialFolder.Startup:
                case SpecialFolder.Personal:
                    throw new PlatformNotSupportedException();
                default:
                    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.MAX_PATH);
            int hresult = Win32Native.SHGetFolderPath(IntPtr.Zero,                    /* hwndOwner: [in] Reserved */
                                                      ((int)folder | (int)option),    /* nFolder:   [in] CSIDL    */
                                                      IntPtr.Zero,                    /* hToken:    [in] access token */
                                                      Win32Native.SHGFP_TYPE_CURRENT, /* dwFlags:   [in] retrieve current path */
                                                      sb);                            /* pszPath:   [out]resultant path */
            String s;
            if (hresult < 0)
            {
                switch (hresult)
                {
                default:
                    // The previous incarnation threw away all errors. In order to limit
                    // breaking changes, we will be permissive about these errors
                    // instead of calling ThowExceptionForHR.
                    //Runtime.InteropServices.Marshal.ThrowExceptionForHR(hresult);
                    break;
                case __HResults.COR_E_PLATFORMNOTSUPPORTED:
                    // This one error is the one we do want to throw.
                    // <
 
                    throw new PlatformNotSupportedException();
                }
 
                // SHGetFolderPath does not initialize the output buffer on error
                s = String.Empty;
            }
            else
            {
                s = sb.ToString();
            }
 
            if (!suppressSecurityChecks)
            {
                // 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();
                }
            }
            return s;
#endif // FEATURE_CORESYSTEM
        }
        
#if !FEATURE_PAL
        public static string UserDomainName
        {
                [System.Security.SecuritySafeCritical]  // auto-generated
                get {
                    new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserDomain").Demand();
 
                    byte[] sid = new byte[1024];
                    int sidLen = sid.Length;
                    StringBuilder domainName = new StringBuilder(1024);
                    uint domainNameLen = (uint) domainName.Capacity;
                    int peUse;
 
                    byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen);
                        if (ret == 1) {                        
                            string samName = domainName.ToString();
                            int index = samName.IndexOf('\\');
                            if( index != -1) {
                                return samName.Substring(0, index);
                            }
                        }
                        domainNameLen = (uint) domainName.Capacity;                    
                    
                    bool success = Win32Native.LookupAccountName(null, UserName, sid, ref sidLen, domainName, ref domainNameLen, out peUse);
                    if (!success)  {
                        int errorCode = Marshal.GetLastWin32Error();
                        throw new InvalidOperationException(Win32Native.GetMessage(errorCode));
                    }
 
                    return domainName.ToString();
                }
            }
#endif // !FEATURE_PAL
        public enum SpecialFolderOption {
            None        = 0,
            Create      = Win32Native.CSIDL_FLAG_CREATE,
            DoNotVerify = Win32Native.CSIDL_FLAG_DONT_VERIFY,
        }
        
//////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!////////
//////!!!!!! Keep the following locations synchronized            !!!!!!////////
//////!!!!!! 1) ndp\clr\src\BCL\Microsoft\Win32\Win32Native.cs    !!!!!!////////
//////!!!!!! 2) ndp\clr\src\BCL\System\Environment.cs             !!!!!!////////
//////!!!!!! 3) rotor\pal\inc\rotor_pal.h                         !!!!!!////////
//////!!!!!! 4) rotor\pal\corunix\shfolder\shfolder.cpp           !!!!!!////////
//////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!////////
        [ComVisible(true)]
        public enum SpecialFolder {
            //  
            //      Represents the file system directory that serves as a common repository for
            //       application-specific data for the current, roaming user. 
            //     A roaming user works on more than one computer on a network. A roaming user's 
            //       profile is kept on a server on the network and is loaded onto a system when the
            //       user logs on. 
            //  
            ApplicationData =  Win32Native.CSIDL_APPDATA,
            //  
            //      Represents the file system directory that serves as a common repository for application-specific data that
            //       is used by all users. 
            //  
            CommonApplicationData =  Win32Native.CSIDL_COMMON_APPDATA,
            //  
            //     Represents the file system directory that serves as a common repository for application specific data that
            //       is used by the current, non-roaming user. 
            //  
            LocalApplicationData =  Win32Native.CSIDL_LOCAL_APPDATA,
            //  
            //     Represents the file system directory that serves as a common repository for Internet
            //       cookies. 
            //  
            Cookies =  Win32Native.CSIDL_COOKIES,
            Desktop = Win32Native.CSIDL_DESKTOP,
            //  
            //     Represents the file system directory that serves as a common repository for the user's
            //       favorite items. 
            //  
            Favorites =  Win32Native.CSIDL_FAVORITES,
            //  
            //     Represents the file system directory that serves as a common repository for Internet
            //       history items. 
            //  
            History =  Win32Native.CSIDL_HISTORY,
            //  
            //     Represents the file system directory that serves as a common repository for temporary 
            //       Internet files. 
            //  
            InternetCache =  Win32Native.CSIDL_INTERNET_CACHE,
            //  
            //      Represents the file system directory that contains
            //       the user's program groups. 
            //  
            Programs =  Win32Native.CSIDL_PROGRAMS,
            MyComputer =  Win32Native.CSIDL_DRIVES,
            MyMusic =  Win32Native.CSIDL_MYMUSIC,
            MyPictures = Win32Native.CSIDL_MYPICTURES,
            //      "My Videos" folder
            MyVideos = Win32Native.CSIDL_MYVIDEO,
            //  
            //     Represents the file system directory that contains the user's most recently used
            //       documents. 
            //  
            Recent =  Win32Native.CSIDL_RECENT,
            //  
            //     Represents the file system directory that contains Send To menu items. 
            //  
            SendTo =  Win32Native.CSIDL_SENDTO,
            //  
            //     Represents the file system directory that contains the Start menu items. 
            //  
            StartMenu =  Win32Native.CSIDL_STARTMENU,
            //  
            //     Represents the file system directory that corresponds to the user's Startup program group. The system
            //       starts these programs whenever any user logs on to Windows NT, or
            //       starts Windows 95 or Windows 98. 
            //  
            Startup =  Win32Native.CSIDL_STARTUP,
            //  
            //     System directory.
            //  
            System =  Win32Native.CSIDL_SYSTEM,
            //  
            //     Represents the file system directory that serves as a common repository for document
            //       templates. 
            //  
            Templates =  Win32Native.CSIDL_TEMPLATES,
            //  
            //     Represents the file system directory used to physically store file objects on the desktop.
            //       This should not be confused with the desktop folder itself, which is
            //       a virtual folder. 
            //  
            DesktopDirectory =  Win32Native.CSIDL_DESKTOPDIRECTORY,
            //  
            //     Represents the file system directory that serves as a common repository for documents. 
            //  
            Personal =  Win32Native.CSIDL_PERSONAL, 
            //          
            // "MyDocuments" is a better name than "Personal"
            //
            MyDocuments = Win32Native.CSIDL_PERSONAL,                         
            //  
            //     Represents the program files folder. 
            //  
            ProgramFiles =  Win32Native.CSIDL_PROGRAM_FILES,
            //  
            //     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
        }
 
        public static int CurrentManagedThreadId
        {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            get
            {
                return Thread.CurrentThread.ManagedThreadId;
            }
        }
 
    }
}