diff options
Diffstat (limited to 'src/mscorlib/src/System/Environment.cs')
-rw-r--r-- | src/mscorlib/src/System/Environment.cs | 1735 |
1 files changed, 1735 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs new file mode 100644 index 0000000000..dc052ac726 --- /dev/null +++ b/src/mscorlib/src/System/Environment.cs @@ -0,0 +1,1735 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================ +** +** +** +** 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; + + [ComVisible(true)] + public enum EnvironmentVariableTarget { + Process = 0, +#if FEATURE_WIN32_REGISTRY + User = 1, + Machine = 2, +#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++; + + // 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 + [MethodImplAttribute(MethodImplOptions.InternalCall)] + get; + } + + // Terminates this process with the given exit code. + [System.Security.SecurityCritical] // auto-generated + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + internal static extern void _Exit(int exitCode); + + [System.Security.SecuritySafeCritical] // auto-generated +#pragma warning disable 618 + [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)] +#pragma warning restore 618 + public static void Exit(int exitCode) { + _Exit(exitCode); + } + + + public static extern int ExitCode { + [System.Security.SecuritySafeCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + get; + + [System.Security.SecuritySafeCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + set; + } + + // Note: The CLR's Watson bucketization code looks at the caller of the FCALL method + // to assign blame for crashes. Don't mess with this, such as by making it call + // another managed helper method, unless you consult with some CLR Watson experts. + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void FailFast(String message); + + [System.Security.SecurityCritical] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void FailFast(String message, uint exitCode); + + // 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] + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern void FailFast(String message, Exception exception); + +#if !FEATURE_CORECLR + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods. + [SuppressUnmanagedCodeSecurity] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + internal static extern void TriggerCodeContractFailure(ContractFailureKind failureKind, String message, String condition, String exceptionAsString); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods. + [SuppressUnmanagedCodeSecurity] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetIsCLRHosted(); + + internal static bool IsCLRHosted { + [SecuritySafeCritical] + get { return GetIsCLRHosted(); } + } + + public static String CommandLine { + [System.Security.SecuritySafeCritical] // auto-generated + get { + new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand(); + + String commandLine = null; + GetCommandLine(JitHelpers.GetStringHandleOnStack(ref commandLine)); + return commandLine; + } + } + + [System.Security.SecurityCritical] // auto-generated + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private static extern void GetCommandLine(StringHandleOnStack retString); +#endif // !FEATURE_CORECLR + + /*===============================CurrentDirectory=============================== + **Action: Provides a getter and setter for the current directory. The original + ** current directory is the one from which the process was started. + **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 + { + get{ + return Directory.GetCurrentDirectory(); + } + + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + 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 + 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 + new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand(); +#endif + + return path; + } + } + + // Returns the windows directory (ie, C:\WinNT). + // Used by NLS+ custom culures only at the moment. + internal static String InternalWindowsDirectory { + [System.Security.SecurityCritical] // auto-generated + get { + StringBuilder sb = new StringBuilder(Path.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(); + } + + 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 + [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 + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern String nativeGetEnvironmentVariable(String variable); +#endif //!FEATURE_CORECLR + + /*============================GetEnvironmentVariable============================ + **Action: + **Returns: + **Arguments: + **Exceptions: + ==============================================================================*/ + [System.Security.SecuritySafeCritical] // auto-generated + public static String GetEnvironmentVariable(String variable) + { + if (variable == null) + throw new ArgumentNullException("variable"); + Contract.EndContractBlock(); + + if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) { + // Environment variable accessors are not approved modern API. + // Behave as if the variable was not found in this case. + return null; + } + +#if !FEATURE_CORECLR + (new EnvironmentPermission(EnvironmentPermissionAccess.Read, variable)).Demand(); +#endif //!FEATURE_CORECLR + + StringBuilder blob = StringBuilderCache.Acquire(128); // A somewhat reasonable default size + int requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity); + + if (requiredSize == 0) { // GetEnvironmentVariable failed + if (Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND) { + StringBuilderCache.Release(blob); + return null; + } + } + + while (requiredSize > blob.Capacity) { // need to retry since the environment variable might be changed + blob.Capacity = requiredSize; + blob.Length = 0; + requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity); + } + return StringBuilderCache.GetStringAndRelease(blob); + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static string GetEnvironmentVariable( string variable, EnvironmentVariableTarget target) + { + if (variable == null) + { + throw new ArgumentNullException("variable"); + } + Contract.EndContractBlock(); + + if (target == EnvironmentVariableTarget.Process) + { + return GetEnvironmentVariable(variable); + } + +#if FEATURE_WIN32_REGISTRY + (new EnvironmentPermission(PermissionState.Unrestricted)).Demand(); + + if( target == EnvironmentVariableTarget.Machine) { + using (RegistryKey environmentKey = + Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) { + + Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!"); + if (environmentKey == null) { + return null; + } + + string value = environmentKey.GetValue(variable) as string; + return value; + } + } + else if( target == EnvironmentVariableTarget.User) { + using (RegistryKey environmentKey = + Registry.CurrentUser.OpenSubKey("Environment", false)) { + + Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!"); + if (environmentKey == null) { + return null; + } + + string value = environmentKey.GetValue(variable) as string; + return value; + } + } + else +#endif // FEATURE_WIN32_REGISTRY + { + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target)); + } + } + + /*===========================GetEnvironmentVariables============================ + **Action: Returns an IDictionary containing all enviroment variables and their values. + **Returns: An IDictionary containing all environment variables and their values. + **Arguments: None. + **Exceptions: None. + ==============================================================================*/ + [System.Security.SecurityCritical] // auto-generated + private unsafe static char[] GetEnvironmentCharArray() + { + char[] block = null; + + // Make sure pStrings is not leaked with async exceptions + RuntimeHelpers.PrepareConstrainedRegions(); + try { + } + 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 + public static IDictionary GetEnvironmentVariables() + { + if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) { + // Environment variable accessors are not approved modern API. + // Behave as if no environment variables are defined in this case. + return new Hashtable(0); + } + +#if !FEATURE_CORECLR + bool isFullTrust = CodeAccessSecurityEngine.QuickCheckForAllDemands(); + StringBuilder vars = isFullTrust ? null : new StringBuilder(); + bool first = true; +#endif + + char[] block = GetEnvironmentCharArray(); + + Hashtable table = new Hashtable(20); + + // Copy strings out, parsing into pairs and inserting into the table. + // The first few environment variable entries start with an '='! + // The current working directory of every drive (except for those drives + // you haven't cd'ed into in your DOS window) are stored in the + // environment block (as =C:=pwd) and the program's exit code is + // as well (=ExitCode=00000000) Skip all that start with =. + // Read docs about Environment Blocks on MSDN's CreateProcess page. + + // Format for GetEnvironmentStrings is: + // (=HiddenVar=value\0 | Variable=value\0)* \0 + // See the description of Environment Blocks in MSDN's + // CreateProcess page (null-terminated array of null-terminated strings). + // Note the =HiddenVar's aren't always at the beginning. + + for(int i=0; i<block.Length; i++) { + int startKey = i; + // Skip to key + // On some old OS, the environment block can be corrupted. + // Someline will not have '=', so we need to check for '\0'. + while(block[i]!='=' && block[i] != '\0') { + i++; + } + + if(block[i] == '\0') { + continue; + } + + // Skip over environment variables starting with '=' + if (i-startKey==0) { + while(block[i]!=0) { + i++; + } + continue; + } + String key = new String(block, startKey, i-startKey); + i++; // skip over '=' + int startValue = i; + while(block[i]!=0) { + // Read to end of this entry + i++; + } + + String value = new String(block, startValue, i-startValue); + // skip over 0 handled by for loop's i++ + table[key]=value; + +#if !FEATURE_CORECLR + if (!isFullTrust) { + if( first) { + first = false; + } + else { + vars.Append(';'); + } + vars.Append(key); + } +#endif + } + +#if !FEATURE_CORECLR + if (!isFullTrust) + new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand(); +#endif + return table; + } + +#if FEATURE_WIN32_REGISTRY + internal static IDictionary GetRegistryKeyNameValuePairs(RegistryKey registryKey) { + Hashtable table = new Hashtable(20); + + if (registryKey != null) { + string[] names = registryKey.GetValueNames(); + foreach( string name in names) { + string value = registryKey.GetValue(name, "").ToString(); + table.Add(name, value); + } + } + return table; + } +#endif + + [System.Security.SecuritySafeCritical] // auto-generated + public static IDictionary GetEnvironmentVariables( EnvironmentVariableTarget target) { + if( target == EnvironmentVariableTarget.Process) { + return GetEnvironmentVariables(); + } + +#if FEATURE_WIN32_REGISTRY + (new EnvironmentPermission(PermissionState.Unrestricted)).Demand(); + + if( target == EnvironmentVariableTarget.Machine) { + using (RegistryKey environmentKey = + Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) { + + return GetRegistryKeyNameValuePairs(environmentKey); + } + } + else if( target == EnvironmentVariableTarget.User) { + using (RegistryKey environmentKey = + Registry.CurrentUser.OpenSubKey("Environment", false)) { + return GetRegistryKeyNameValuePairs(environmentKey); + } + } + else +#endif // FEATURE_WIN32_REGISTRY + { + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target)); + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static void SetEnvironmentVariable(string variable, string value) { + CheckEnvironmentVariableName(variable); + +#if !FEATURE_CORECLR + new EnvironmentPermission(PermissionState.Unrestricted).Demand(); +#endif + // explicitly null out value if is the empty string. + if (String.IsNullOrEmpty(value) || value[0] == '\0') { + value = null; + } + else { + if( value.Length >= MaxEnvVariableValueLength) { + throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue")); + } + } + + if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) { + // Environment variable accessors are not approved modern API. + // so we throw PlatformNotSupportedException. + throw new PlatformNotSupportedException(); + } + + if(!Win32Native.SetEnvironmentVariable(variable, value)) { + int errorCode = Marshal.GetLastWin32Error(); + + // Allow user to try to clear a environment variable + if( errorCode == Win32Native.ERROR_ENVVAR_NOT_FOUND) { + return; + } + + // The error message from Win32 is "The filename or extension is too long", + // which is not accurate. + if( errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE) { + throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue")); + } + + throw new ArgumentException(Win32Native.GetMessage(errorCode)); + } + } + + private static void CheckEnvironmentVariableName(string variable) { + if (variable == null) { + throw new ArgumentNullException("variable"); + } + + if( variable.Length == 0) { + throw new ArgumentException(Environment.GetResourceString("Argument_StringZeroLength"), "variable"); + } + + if( variable[0] == '\0') { + throw new ArgumentException(Environment.GetResourceString("Argument_StringFirstCharIsZero"), "variable"); + } + + // Make sure the environment variable name isn't longer than the + // max limit on environment variable values. (MSDN is ambiguous + // on whether this check is necessary.) + if( variable.Length >= MaxEnvVariableValueLength ) { + throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue")); + } + + if( variable.IndexOf('=') != -1) { + throw new ArgumentException(Environment.GetResourceString("Argument_IllegalEnvVarName")); + } + Contract.EndContractBlock(); + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) { + if( target == EnvironmentVariableTarget.Process) { + SetEnvironmentVariable(variable, value); + return; + } + + CheckEnvironmentVariableName(variable); + + // System-wide environment variables stored in the registry are + // limited to 1024 chars for the environment variable name. + if (variable.Length >= MaxSystemEnvVariableLength) { + throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarName")); + } + + new EnvironmentPermission(PermissionState.Unrestricted).Demand(); + // explicitly null out value if is the empty string. + if (String.IsNullOrEmpty(value) || value[0] == '\0') { + value = null; + } +#if FEATURE_WIN32_REGISTRY + if( target == EnvironmentVariableTarget.Machine) { + using (RegistryKey environmentKey = + Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", true)) { + + Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!"); + if (environmentKey != null) { + if (value == null) + environmentKey.DeleteValue(variable, false); + else + environmentKey.SetValue(variable, value); + } + } + } + else if( target == EnvironmentVariableTarget.User) { + // User-wide environment variables stored in the registry are + // limited to 255 chars for the environment variable name. + if (variable.Length >= MaxUserEnvVariableLength) { + throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue")); + } + using (RegistryKey environmentKey = + Registry.CurrentUser.OpenSubKey("Environment", true)) { + Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!"); + if (environmentKey != null) { + if (value == null) + environmentKey.DeleteValue(variable, false); + else + environmentKey.SetValue(variable, value); + } + } + } + else + { + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target)); + } + // send a WM_SETTINGCHANGE message to all windows + IntPtr r = Win32Native.SendMessageTimeout(new IntPtr(Win32Native.HWND_BROADCAST), Win32Native.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero); + + if (r == IntPtr.Zero) BCLDebug.Assert(false, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error()); + +#else // FEATURE_WIN32_REGISTRY + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target)); +#endif + } + + + /*===============================GetLogicalDrives=============================== + **Action: Retrieves the names of the logical drives on this machine in the form "C:\". + **Arguments: None. + **Exceptions: IOException. + **Permissions: SystemInfo Permission. + ==============================================================================*/ + [System.Security.SecuritySafeCritical] // auto-generated + public static String[] GetLogicalDrives() { + new EnvironmentPermission(PermissionState.Unrestricted).Demand(); + + 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); +#if !PLATFORM_UNIX + return "\r\n"; +#else + return "\n"; +#endif // !PLATFORM_UNIX + } + } + + + /*===================================Version==================================== + **Action: Returns the COM+ version struct, describing the build number. + **Returns: + **Arguments: + **Exceptions: + ==============================================================================*/ + public static Version Version { + get { + return new Version(ThisAssembly.InformationalVersion); + } + } + + + /*==================================WorkingSet================================== + **Action: + **Returns: + **Arguments: + **Exceptions: + ==============================================================================*/ + [System.Security.SecurityCritical] // auto-generated + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] + private static extern long GetWorkingSet(); + + public static long WorkingSet { + [System.Security.SecuritySafeCritical] // auto-generated + get { + new EnvironmentPermission(PermissionState.Unrestricted).Demand(); + return GetWorkingSet(); + } + } + + + /*==================================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")); + +#if PLATFORM_UNIX + PlatformID id = PlatformID.Unix; +#else + 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 +#endif // PLATFORM_UNIX + + Version v = new Version(osvi.MajorVersion, osvi.MinorVersion, osvi.BuildNumber, (osviEx.ServicePackMajor << 16) |osviEx.ServicePackMinor); + m_os = new OperatingSystem(id, v, osvi.CSDVersion); + } + 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 + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern bool GetVersion(Microsoft.Win32.Win32Native.OSVERSIONINFO osVer); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern bool GetVersionEx(Microsoft.Win32.Win32Native.OSVERSIONINFOEX osVer); + + + /*==================================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 + [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 + internal static String GetResourceString(String key) { +#if FEATURE_CORECLR + return GetResourceStringLocal(key); +#else + return GetResourceFromDefault(key); +#endif //FEATURE_CORECLR + } + + [System.Security.SecuritySafeCritical] // auto-generated + internal static String GetResourceString(String key, params Object[] values) { + String s = GetResourceString(key); + return String.Format(CultureInfo.CurrentCulture, s, values); + } + + //The following two internal methods are not used anywhere within the framework, + // but are being kept around as external platforms built on top of us have taken + // dependency by using private reflection on them for getting system resource strings + internal static String GetRuntimeResourceString(String key) { + return GetResourceString(key); + } + + 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 + } + } + + 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 + } + } + + public static extern bool HasShutdownStarted { + [System.Security.SecuritySafeCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + get; + } + +#if !FEATURE_CORECLR + // This is the temporary Whidbey stub for compatibility flags + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [System.Security.SecurityCritical] + internal static extern bool GetCompatibilityFlag(CompatibilityFlag flag); +#endif //!FEATURE_CORECLR + + public static string UserName { + [System.Security.SecuritySafeCritical] // auto-generated + get { + new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserName").Demand(); + + 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_CORECLR + private static volatile IntPtr processWinStation; // Doesn't need to be initialized as they're zero-init. + private static volatile bool isUserNonInteractive; +#endif + + public static bool UserInteractive { + [System.Security.SecuritySafeCritical] // auto-generated + get { +#if !FEATURE_CORECLR + IntPtr hwinsta = Win32Native.GetProcessWindowStation(); + if (hwinsta != IntPtr.Zero && processWinStation != hwinsta) { + int lengthNeeded = 0; + Win32Native.USEROBJECTFLAGS flags = new Win32Native.USEROBJECTFLAGS(); + if (Win32Native.GetUserObjectInformation(hwinsta, Win32Native.UOI_FLAGS, flags, Marshal.SizeOf(flags),ref lengthNeeded)) { + if ((flags.dwFlags & Win32Native.WSF_VISIBLE) == 0) { + isUserNonInteractive = true; + } + } + processWinStation = hwinsta; + } + + // The logic is reversed to avoid static initialization to true + return !isUserNonInteractive; +#else + return true; +#endif + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static string GetFolderPath(SpecialFolder folder) { + if (!Enum.IsDefined(typeof(SpecialFolder), folder)) + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder)); + Contract.EndContractBlock(); + + return InternalGetFolderPath(folder, SpecialFolderOption.None); + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) { + if (!Enum.IsDefined(typeof(SpecialFolder),folder)) + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder)); + if (!Enum.IsDefined(typeof(SpecialFolderOption),option)) + throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)option)); + Contract.EndContractBlock(); + + return InternalGetFolderPath(folder, option); + } + + [System.Security.SecurityCritical] + internal static string UnsafeGetFolderPath(SpecialFolder folder) + { + return InternalGetFolderPath(folder, SpecialFolderOption.None, suppressSecurityChecks: true); + } + + [System.Security.SecurityCritical] + private static string InternalGetFolderPath(SpecialFolder folder, SpecialFolderOption option, bool suppressSecurityChecks = false) + { +#if FEATURE_CORESYSTEM + // 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 + } + + 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(); + } + } + + 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 !!!!!!//////// +//////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//////// + [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; + } + } + + } +} |