The Labs \ Source Viewer \ SSCLI \ System \ ResourceHelper

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: Environment
  18. **
  19. **
  20. ** Purpose: Provides some basic access to some environment
  21. ** functionality.
  22. **
  23. **
  24. ============================================================*/
  25. namespace System
  26. {
  27.     using System.IO;
  28.     using System.Security;
  29.     using System.Resources;
  30.     using System.Globalization;
  31.     using System.Collections;
  32.     using System.Security.Permissions;
  33.     using System.Text;
  34.     using System.Configuration.Assemblies;
  35.     using System.Runtime.InteropServices;
  36.     using System.Reflection;
  37.     using System.Diagnostics;
  38.     using Microsoft.Win32;
  39.     using System.Runtime.CompilerServices;
  40.     using System.Threading;
  41.     using System.Runtime.ConstrainedExecution;
  42.     using System.Runtime.Versioning;
  43.    
  44.    
  45.     [ComVisible(true)]
  46.     public static class Environment
  47.     {
  48.        
  49.         const int MaximumLength = 32767;
  50.         // maximun length for environment vairable name and value
  51.         internal sealed class ResourceHelper
  52.         {
  53.             private ResourceManager SystemResMgr;
  54.            
  55.             // To avoid infinite loops when calling GetResourceString. See comments
  56.             // in GetResourceString for this field.
  57.             private Stack currentlyLoading;
  58.            
  59.             // process-wide state (since this is only used in one domain),
  60.             // used to avoid the TypeInitialization infinite recusion
  61.             // in GetResourceStringCode
  62.             internal bool resourceManagerInited = false;
  63.            
  64.             internal class GetResourceStringUserData
  65.             {
  66.                 public ResourceHelper m_resourceHelper;
  67.                 public string m_key;
  68.                 public string m_retVal;
  69.                 public bool m_lockWasTaken;
  70.                
  71.                 public GetResourceStringUserData(ResourceHelper resourceHelper, string key)
  72.                 {
  73.                     m_resourceHelper = resourceHelper;
  74.                     m_key = key;
  75.                 }
  76.             }
  77.            
  78.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  79.             internal string GetResourceString(string key)
  80.             {
  81.                 if (key == null || key.Length == 0) {
  82.                     BCLDebug.Assert(false, "Environment::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
  83.                     return "[Resource lookup failed - null or empty resource name]";
  84.                 }
  85.                
  86.                 // We have a somewhat common potential for infinite
  87.                 // loops with mscorlib's ResourceManager. If "potentially dangerous"
  88.                 // code throws an exception, we will get into an infinite loop
  89.                 // inside the ResourceManager and this "potentially dangerous" code.
  90.                 // Potentially dangerous code includes the IO package, CultureInfo,
  91.                 // parts of the loader, some parts of Reflection, Security (including
  92.                 // custom user-written permissions that may parse an XML file at
  93.                 // class load time), assembly load event handlers, etc. Essentially,
  94.                 // this is not a bounded set of code, and we need to fix the problem.
  95.                 // Fortunately, this is limited to mscorlib's error lookups and is NOT
  96.                 // a general problem for all user code using the ResourceManager.
  97.                
  98.                 // The solution is to make sure only one thread at a time can call
  99.                 // GetResourceString. Also, since resource lookups can be
  100.                 // reentrant, if the same thread comes into GetResourceString
  101.                 // twice looking for the exact same resource name before
  102.                 // returning, we're going into an infinite loop and we should
  103.                 // return a bogus string.
  104.                
  105.                 GetResourceStringUserData userData = new GetResourceStringUserData(this, key);
  106.                
  107.                 RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(GetResourceStringCode);
  108.                 RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(GetResourceStringBackoutCode);
  109.                
  110.                 RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, userData);
  111.                 return userData.m_retVal;
  112.                
  113.             }
  114.            
  115.             private void GetResourceStringCode(object userDataIn)
  116.             {
  117.                 GetResourceStringUserData userData = (GetResourceStringUserData)userDataIn;
  118.                 ResourceHelper rh = userData.m_resourceHelper;
  119.                 string key = userData.m_key;
  120.                
  121.                 Monitor.ReliableEnter(rh, ref userData.m_lockWasTaken);
  122.                
  123.                 // Are we recursively looking up the same resource?
  124.                 if (rh.currentlyLoading != null && rh.currentlyLoading.Count > 0 && rh.currentlyLoading.Contains(key)) {
  125.                     // This is often a bug in the BCL, security, NLS+ code,
  126.                     // or the loader somewhere. However, this could also
  127.                     // be a setup problem - check whether mscorlib &
  128.                     // mscorwks are both of the same build flavor.
  129.                     string stackTrace = "[Couldn't get a stack trace]";
  130.                     try {
  131.                         StackTrace st = new StackTrace(true);
  132.                         // Don't attempt to localize strings in this stack trace, otherwise it could cause
  133.                         // infinite recursion. This stack trace is used for an Assert message only, and
  134.                         // so the lack of localization should not be an issue.
  135.                         stackTrace = st.ToString(System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
  136.                     }
  137.                     catch (StackOverflowException) {
  138.                     }
  139.                     catch (NullReferenceException) {
  140.                     }
  141.                     catch (OutOfMemoryException) {
  142.                     }
  143.                    
  144.                     BCLDebug.Assert(false, "Infinite recursion during resource lookup. Resource name: " + key + "\r\n" + stackTrace);
  145.                    
  146.                     // Note: can't append the key name, since that may require
  147.                     // an extra allocation...
  148.                     userData.m_retVal = "[Resource lookup failed - infinite recursion or critical failure detected.]";
  149.                     return;
  150.                 }
  151.                 if (rh.currentlyLoading == null)
  152.                     rh.currentlyLoading = new Stack(4);
  153.                
  154.                 // Call class constructors preemptively, so that we cannot get into an infinite
  155.                 // loop constructing a TypeInitializationException. If this were omitted,
  156.                 // we could get the Infinite recursion assert above by failing type initialization
  157.                 // between the Push and Pop calls below.
  158.                
  159.                 if (!rh.resourceManagerInited) {
  160.                     // process-critical code here. No ThreadAbortExceptions
  161.                     // can be thrown here. Other exceptions percolate as normal.
  162.                     RuntimeHelpers.PrepareConstrainedRegions();
  163.                     try {
  164.                     }
  165.                     finally {
  166.                         RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
  167.                         RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
  168.                         RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
  169.                         RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
  170.                         rh.resourceManagerInited = true;
  171.                     }
  172.                    
  173.                 }
  174.                
  175.                 rh.currentlyLoading.Push(key);
  176.                 if (rh.SystemResMgr == null)
  177.                     rh.SystemResMgr = new ResourceManager("mscorlib", typeof(object).Assembly);
  178.                 string s = rh.SystemResMgr.GetString(key, null);
  179.                 rh.currentlyLoading.Pop();
  180.                
  181.                 BCLDebug.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 rhironment.GetResourceString. Resource name was: \"" + key + "\"");
  182.                
  183.                 userData.m_retVal = s;
  184.             }
  185.            
  186.             [PrePrepareMethod()]
  187.             private void GetResourceStringBackoutCode(object userDataIn, bool exceptionThrown)
  188.             {
  189.                 GetResourceStringUserData userData = (GetResourceStringUserData)userDataIn;
  190.                 ResourceHelper rh = userData.m_resourceHelper;
  191.                
  192.                 if (exceptionThrown) {
  193.                     if (userData.m_lockWasTaken) {
  194.                         // Backout code - throw away potentially corrupt state
  195.                         rh.SystemResMgr = null;
  196.                         rh.currentlyLoading = null;
  197.                     }
  198.                 }
  199.                 // Release the lock, if we took it.
  200.                 if (userData.m_lockWasTaken) {
  201.                     Monitor.Exit(rh);
  202.                 }
  203.             }
  204.            
  205.         }
  206.        
  207.        
  208.         private static ResourceHelper m_resHelper;
  209.         // Doesn't need to be initialized as they're zero-init.
  210.         private const int MaxMachineNameLength = 256;
  211.        
  212.         // Private object for locking instead of locking on a public type for SQL reliability work.
  213.         private static object s_InternalSyncObject;
  214.         private static object InternalSyncObject {
  215.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  216.             get {
  217.                 if (s_InternalSyncObject == null) {
  218.                     object o = new object();
  219.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  220.                 }
  221.                 return s_InternalSyncObject;
  222.             }
  223.         }
  224.        
  225.        
  226.        
  227. /*==================================TickCount===================================
  228.         **Action: Gets the number of ticks since the system was started.
  229.         **Returns: The number of ticks since the system was started.
  230.         **Arguments: None
  231.         **Exceptions: None
  232.         ==============================================================================*/       
  233.         public static int TickCount {
  234.             get { return nativeGetTickCount(); }
  235.         }
  236.        
  237.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  238.         private static extern int nativeGetTickCount();
  239.        
  240.         // Terminates this process with the given exit code.
  241.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  242.         private static extern void ExitNative(int exitCode);
  243.        
  244.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  245.         public static void Exit(int exitCode)
  246.         {
  247.             ExitNative(exitCode);
  248.         }
  249.        
  250.        
  251.         public static int ExitCode {
  252.             get { return nativeGetExitCode(); }
  253.            
  254.             set { nativeSetExitCode(value); }
  255.         }
  256.        
  257.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  258.         private static extern void nativeSetExitCode(int exitCode);
  259.        
  260.         // Gets the exit code of the process.
  261.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  262.         private static extern int nativeGetExitCode();
  263.        
  264.        
  265.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  266.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  267.         public static extern void FailFast(string message);
  268.        
  269.        
  270.         public static string CommandLine {
  271.             get {
  272.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
  273.                 return GetCommandLineNative();
  274.             }
  275.         }
  276.        
  277.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  278.         private static extern string GetCommandLineNative();
  279.        
  280. /*===============================CurrentDirectory===============================
  281.         **Action:  Provides a getter and setter for the current directory.  The original
  282.         **        current directory is the one from which the process was started. 
  283.         **Returns: The current directory (from the getter).  Void from the setter.
  284.         **Arguments: The current directory to which to switch to the setter.
  285.         **Exceptions:
  286.         ==============================================================================*/       
  287.         public static string CurrentDirectory {
  288.             [ResourceExposure(ResourceScope.Machine)]
  289.             [ResourceConsumption(ResourceScope.Machine)]
  290.             get { return Directory.GetCurrentDirectory(); }
  291.            
  292.             [ResourceExposure(ResourceScope.Machine)]
  293.             [ResourceConsumption(ResourceScope.Machine)]
  294.             set { Directory.SetCurrentDirectory(value); }
  295.         }
  296.        
  297.         // Returns the system directory (ie, C:\WinNT\System32).
  298.         public static string SystemDirectory {
  299.             [ResourceExposure(ResourceScope.Machine)]
  300.             [ResourceConsumption(ResourceScope.Machine)]
  301.             get {
  302.                 StringBuilder sb = new StringBuilder(Path.MAX_PATH);
  303.                 int r = Win32Native.GetSystemDirectory(sb, Path.MAX_PATH);
  304.                 BCLDebug.Assert(r < Path.MAX_PATH, "r < Path.MAX_PATH");
  305.                 if (r == 0)
  306.                     __Error.WinIOError();
  307.                 string path = sb.ToString();
  308.                
  309.                 // Do security check
  310.                 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
  311.                
  312.                 return path;
  313.             }
  314.         }
  315.        
  316.        
  317.         public static string MachineName {
  318.             get {
  319.                 // In future release of operating systems, you might be able to rename a machine without
  320.                 // rebooting. Therefore, don't cache this machine name.
  321.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "COMPUTERNAME").Demand();
  322.                 StringBuilder buf = new StringBuilder(MaxMachineNameLength);
  323.                 int len = MaxMachineNameLength;
  324.                 if (Win32Native.GetComputerName(buf, ref len) == 0)
  325.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ComputerName"));
  326.                 return buf.ToString();
  327.             }
  328.         }
  329.        
  330.         public static int ProcessorCount {
  331.             get {
  332.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "NUMBER_OF_PROCESSORS").Demand();
  333.                 Win32Native.SYSTEM_INFO info = new Win32Native.SYSTEM_INFO();
  334.                 Win32Native.GetSystemInfo(ref info);
  335.                 return info.dwNumberOfProcessors;
  336.             }
  337.         }
  338.        
  339. /*==============================GetCommandLineArgs==============================
  340.         **Action: Gets the command line and splits it appropriately to deal with whitespace,
  341.         **        quotes, and escape characters.
  342.         **Returns: A string array containing your command line arguments.
  343.         **Arguments: None
  344.         **Exceptions: None.
  345.         ==============================================================================*/       
  346.         public static string[] GetCommandLineArgs()
  347.         {
  348.             new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
  349.             return GetCommandLineArgsNative();
  350.         }
  351.        
  352.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  353.         private static extern string[] GetCommandLineArgsNative();
  354.        
  355.         // We need to keep this Fcall since it is used in AppDomain.cs.
  356.         // If we call GetEnvironmentVariable from AppDomain.cs, we will use StringBuilder class.
  357.         // That has side effect to change the ApartmentState of the calling Thread to MTA.
  358.         // So runtime can't change the ApartmentState of calling thread any more.
  359.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  360.         static internal extern string nativeGetEnvironmentVariable(string variable);
  361.        
  362. /*============================GetEnvironmentVariable============================
  363.         **Action:
  364.         **Returns:
  365.         **Arguments:
  366.         **Exceptions:
  367.         ==============================================================================*/       
  368.         [ResourceExposure(ResourceScope.Machine)]
  369.         [ResourceConsumption(ResourceScope.Machine)]
  370.         public static string GetEnvironmentVariable(string variable)
  371.         {
  372.             if (variable == null)
  373.                 throw new ArgumentNullException("variable");
  374.             (new EnvironmentPermission(EnvironmentPermissionAccess.Read, variable)).Demand();
  375.            
  376.             StringBuilder blob = new StringBuilder(128);
  377.             // A somewhat reasonable default size
  378.             int requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
  379.            
  380.             if (requiredSize == 0) {
  381.                 // GetEnvironmentVariable failed
  382.                 if (Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND)
  383.                     return null;
  384.             }
  385.            
  386.             while (requiredSize > blob.Capacity) {
  387.                 // need to retry since the environment variable might be changed
  388.                 blob.Capacity = requiredSize;
  389.                 blob.Length = 0;
  390.                 requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
  391.             }
  392.             return blob.ToString();
  393.         }
  394.        
  395.        
  396. /*===========================GetEnvironmentVariables============================
  397.         **Action: Returns an IDictionary containing all enviroment variables and their values.
  398.         **Returns: An IDictionary containing all environment variables and their values.
  399.         **Arguments: None.
  400.         **Exceptions: None.
  401.         ==============================================================================*/       
  402.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  403.         [ResourceExposure(ResourceScope.Machine)]
  404.         private static extern char[] nativeGetEnvironmentCharArray();
  405.        
  406.         [ResourceExposure(ResourceScope.Machine)]
  407.         [ResourceConsumption(ResourceScope.Machine)]
  408.         public static IDictionary GetEnvironmentVariables()
  409.         {
  410.             // Using an FCall is better than using PInvoke here since
  411.             // Interop Marshaler can't handle string which contains '\0', we need
  412.             // to allocate an unmanaged buffer, do the conversion and free the buffer
  413.             // if we do use PInvoke.
  414.             char[] block = nativeGetEnvironmentCharArray();
  415.             if (block == null) {
  416.                 throw new OutOfMemoryException();
  417.             }
  418.            
  419.             Hashtable table = new Hashtable(20);
  420.             StringBuilder vars = new StringBuilder();
  421.             // Copy strings out, parsing into pairs and inserting into the table.
  422.             // The first few environment variable entries start with an '='!
  423.             // The current working directory of every drive (except for those drives
  424.             // you haven't cd'ed into in your DOS window) are stored in the
  425.             // environment block (as =C:=pwd) and the program's exit code is
  426.             // as well (=ExitCode=00000000) Skip all that start with =.
  427.             // Read docs about Environment Blocks on MSDN's CreateProcess page.
  428.            
  429.             // Format for GetEnvironmentStrings is:
  430.             // (=HiddenVar=value\0 | Variable=value\0)* \0
  431.             // See the description of Environment Blocks in MSDN's
  432.             // CreateProcess page (null-terminated array of null-terminated strings).
  433.             // Note the =HiddenVar's aren't always at the beginning.
  434.            
  435.             // GetEnvironmentCharArray will not return the trailing 0 to terminate
  436.             // the array - we have the array length instead.
  437.             bool first = true;
  438.             for (int i = 0; i < block.Length; i++) {
  439.                 int startKey = i;
  440.                 // Skip to key
  441.                 // On some old OS, the environment block can be corrupted.
  442.                 // Someline will not have '=', so we need to check for '\0'.
  443.                 while (block[i] != '=' && block[i] != '\0') {
  444.                     i++;
  445.                 }
  446.                
  447.                 if (block[i] == '\0') {
  448.                     continue;
  449.                 }
  450.                
  451.                 // Skip over environment variables starting with '='
  452.                 if (i - startKey == 0) {
  453.                     while (block[i] != 0) {
  454.                         i++;
  455.                     }
  456.                     continue;
  457.                 }
  458.                 string key = new string(block, startKey, i - startKey);
  459.                 i++;
  460.                 // skip over '='
  461.                 int startValue = i;
  462.                 while (block[i] != 0) {
  463.                     // Read to end of this entry
  464.                     i++;
  465.                 }
  466.                
  467.                 string value = new string(block, startValue, i - startValue);
  468.                 // skip over 0 handled by for loop's i++
  469.                 table[key] = value;
  470.                
  471.                 if (first) {
  472.                     first = false;
  473.                 }
  474.                 else {
  475.                     vars.Append(';');
  476.                 }
  477.                
  478.                 vars.Append(key);
  479.             }
  480.            
  481.             new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand();
  482.             return table;
  483.         }
  484.        
  485.        
  486.         [ResourceExposure(ResourceScope.Machine)]
  487.         [ResourceConsumption(ResourceScope.Machine)]
  488.         public static void SetEnvironmentVariable(string variable, string value)
  489.         {
  490.             CheckEnvironmentVariableName(variable);
  491.            
  492.             new EnvironmentPermission(PermissionState.Unrestricted).Demand();
  493.             // explicitly null out value if is the empty string.
  494.             if (String.IsNullOrEmpty(value) || value[0] == '\0') {
  495.                 value = null;
  496.             }
  497.             else {
  498.                 if (value.Length >= MaximumLength) {
  499.                     throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
  500.                 }
  501.             }
  502.            
  503.             if (!Win32Native.SetEnvironmentVariable(variable, value)) {
  504.                 int errorCode = Marshal.GetLastWin32Error();
  505.                
  506.                 // Allow user to try to clear a environment variable
  507.                 if (errorCode == Win32Native.ERROR_ENVVAR_NOT_FOUND) {
  508.                     return;
  509.                 }
  510.                
  511.                 // The error message from Win32 is "The filename or extension is too long",
  512.                 // which is not accurate.
  513.                 if (errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE) {
  514.                     throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
  515.                 }
  516.                
  517.                 throw new ArgumentException(Win32Native.GetMessage(errorCode));
  518.             }
  519.         }
  520.        
  521.         private static void CheckEnvironmentVariableName(string variable)
  522.         {
  523.             if (variable == null) {
  524.                 throw new ArgumentNullException("variable");
  525.             }
  526.            
  527.             if (variable.Length == 0) {
  528.                 throw new ArgumentException(Environment.GetResourceString("Argument_StringZeroLength"), "variable");
  529.             }
  530.            
  531.             if (variable[0] == '\0') {
  532.                 throw new ArgumentException(Environment.GetResourceString("Argument_StringFirstCharIsZero"), "variable");
  533.             }
  534.            
  535.             if (variable.Length >= MaximumLength) {
  536.                 throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
  537.             }
  538.            
  539.             if (variable.IndexOf('=') != -1) {
  540.                 throw new ArgumentException(Environment.GetResourceString("Argument_IllegalEnvVarName"));
  541.             }
  542.         }
  543.        
  544.        
  545.        
  546. /*===============================GetLogicalDrives===============================
  547.         **Action: Retrieves the names of the logical drives on this machine in the  form "C:\".
  548.         **Arguments:  None.
  549.         **Exceptions:  IOException.
  550.         **Permissions: SystemInfo Permission.
  551.         ==============================================================================*/       
  552.         public static string[] GetLogicalDrives()
  553.         {
  554.             #if !PLATFORM_UNIX
  555.             new EnvironmentPermission(PermissionState.Unrestricted).Demand();
  556.            
  557.             int drives = Win32Native.GetLogicalDrives();
  558.             if (drives == 0)
  559.                 __Error.WinIOError();
  560.             uint d = (uint)drives;
  561.             int count = 0;
  562.             while (d != 0) {
  563.                 if (((int)d & 1) != 0)
  564.                     count++;
  565.                 d >>= 1;
  566.             }
  567.             string[] result = new string[count];
  568.             char[] root = new char[] {'A', ':', '\\'};
  569.             d = (uint)drives;
  570.             count = 0;
  571.             while (d != 0) {
  572.                 if (((int)d & 1) != 0) {
  573.                     result[count++] = new string(root);
  574.                 }
  575.                 d >>= 1;
  576.                 root[0]++;
  577.             }
  578.             return result;
  579.             #else
  580.             return new string[0];
  581.             #endif // !PLATFORM_UNIX
  582.         }
  583.        
  584. /*===================================NewLine====================================
  585.         **Action: A property which returns the appropriate newline string for the given
  586.         **        platform.
  587.         **Returns: \r\n on Win32.
  588.         **Arguments: None.
  589.         **Exceptions: None.
  590.         ==============================================================================*/       
  591.         public static string NewLine {
  592.             get {
  593.                 #if !PLATFORM_UNIX
  594.                 return "\r\n";
  595.                 #else
  596.                 return "\n";
  597.                 #endif // !PLATFORM_UNIX
  598.             }
  599.         }
  600.        
  601.        
  602. /*===================================Version====================================
  603.         **Action: Returns the COM+ version struct, describing the build number.
  604.         **Returns:
  605.         **Arguments:
  606.         **Exceptions:
  607.         ==============================================================================*/       
  608.         public static Version Version {
  609.             get { return new Version(ThisAssembly.InformationalVersion); }
  610.         }
  611.        
  612.        
  613. /*==================================WorkingSet==================================
  614.         **Action:
  615.         **Returns:
  616.         **Arguments:
  617.         **Exceptions:
  618.         ==============================================================================*/       
  619.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  620.         static internal extern long nativeGetWorkingSet();
  621.        
  622.         public static long WorkingSet {
  623.             get {
  624.                 new EnvironmentPermission(PermissionState.Unrestricted).Demand();
  625.                 return (long)nativeGetWorkingSet();
  626.             }
  627.         }
  628.        
  629.        
  630.         // This needs to be removed in a future release.
  631.         static internal bool IsWin9X()
  632.         {
  633.             return false;
  634.         }
  635.        
  636.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  637.         static internal extern bool nativeIsWin9x();
  638.        
  639.        
  640. /*==================================StackTrace==================================
  641.         **Action:
  642.         **Returns:
  643.         **Arguments:
  644.         **Exceptions:
  645.         ==============================================================================*/       
  646.         public static string StackTrace {
  647.             get {
  648.                 new EnvironmentPermission(PermissionState.Unrestricted).Demand();
  649.                 return GetStackTrace(null, true);
  650.             }
  651.         }
  652.        
  653.         static internal string GetStackTrace(Exception e, bool needFileInfo)
  654.         {
  655.             // Note: Setting needFileInfo to true will start up COM and set our
  656.             // apartment state. Try to not call this when passing "true"
  657.             // before the EE's ExecuteMainMethod has had a chance to set up the
  658.             // apartment state. --
  659.             StackTrace st;
  660.             if (e == null)
  661.                 st = new StackTrace(needFileInfo);
  662.             else
  663.                 st = new StackTrace(e, needFileInfo);
  664.            
  665.             // Do no include a trailing newline for backwards compatibility
  666.             return st.ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
  667.         }
  668.        
  669.         private static void InitResourceHelper()
  670.         {
  671.            
  672.             // Only the default AppDomain should have a ResourceHelper. All calls to
  673.             // GetResourceString from any AppDomain delegate to GetResourceStringLocal
  674.             // in the default AppDomain via the fcall GetResourceFromDefault.
  675.            
  676.             // Use Thread.BeginCriticalRegion to tell the CLR all managed
  677.             // allocations within this block are appdomain-critical.
  678.             // Use a CER to ensure we always exit this region.
  679.             bool enteredRegion = false;
  680.             bool tookLock = false;
  681.             RuntimeHelpers.PrepareConstrainedRegions();
  682.             try {
  683.                 RuntimeHelpers.PrepareConstrainedRegions();
  684.                 try {
  685.                 }
  686.                 finally {
  687.                     Thread.BeginCriticalRegion();
  688.                     enteredRegion = true;
  689.                     Monitor.Enter(Environment.InternalSyncObject);
  690.                     tookLock = true;
  691.                 }
  692.                
  693.                 if (m_resHelper == null) {
  694.                     ResourceHelper rh = new ResourceHelper();
  695.                     System.Threading.Thread.MemoryBarrier();
  696.                     m_resHelper = rh;
  697.                 }
  698.             }
  699.             finally {
  700.                 if (tookLock)
  701.                     Monitor.Exit(Environment.InternalSyncObject);
  702.                 if (enteredRegion)
  703.                     Thread.EndCriticalRegion();
  704.             }
  705.         }
  706.        
  707.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  708.         static internal extern string GetResourceFromDefault(string key);
  709.        
  710.         // Looks up the resource string value for key.
  711.         //
  712.         // if you change this method's signature then you must change the code that calls it
  713.         // in excep.cpp and probably you will have to visit mscorlib.h to add the new signature
  714.         // as well as metasig.h to create the new signature type
  715.         static internal string GetResourceStringLocal(string key)
  716.         {
  717.             if (m_resHelper == null)
  718.                 InitResourceHelper();
  719.            
  720.             return m_resHelper.GetResourceString(key);
  721.         }
  722.        
  723.         [ResourceExposure(ResourceScope.None)]
  724.         static internal string GetResourceString(string key)
  725.         {
  726.             return GetResourceFromDefault(key);
  727.         }
  728.        
  729.         [ResourceExposure(ResourceScope.None)]
  730.         static internal string GetResourceString(string key, params object[] values)
  731.         {
  732.             string s = GetResourceFromDefault(key);
  733.             return String.Format(CultureInfo.CurrentCulture, s, values);
  734.         }
  735.        
  736.         public static bool HasShutdownStarted {
  737.             get { return nativeHasShutdownStarted(); }
  738.         }
  739.        
  740.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  741.         private static extern bool nativeHasShutdownStarted();
  742.        
  743.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  744.         static internal extern bool GetCompatibilityFlag(CompatibilityFlag flag);
  745.        
  746.         public static string UserName {
  747.             get {
  748.                 new EnvironmentPermission(EnvironmentPermissionAccess.Read, "UserName").Demand();
  749.                
  750.                 StringBuilder sb = new StringBuilder(256);
  751.                 int size = sb.Capacity;
  752.                 Win32Native.GetUserName(sb, ref size);
  753.                 return sb.ToString();
  754.             }
  755.         }
  756.        
  757.     }
  758. }

Developer Fusion