Permalink
| // ==++== | |
| // | |
| // 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 bug in the BCL, security, NLS+ code, | |
| // or the loader somewhere. However, this could also | |
| // be a setup problem - check whether mscorlib & | |
| // clr.dll are both of the same build flavor. Also, user | |
| // code in the resource lookup process (like an assembly | |
| // resolve event or custom CultureInfo) might potentially cause issues. | |
| // 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; | |
| } | |
| } | |
| } | |
| } |