e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1812 lines
78 KiB
C#
1812 lines
78 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
/*============================================================
|
|
**
|
|
** Class: Environment
|
|
**
|
|
**
|
|
** Purpose: Provides some basic access to some environment
|
|
** functionality.
|
|
**
|
|
**
|
|
============================================================*/
|
|
namespace System {
|
|
using System.IO;
|
|
using System.Security;
|
|
using System.Resources;
|
|
using System.Globalization;
|
|
using System.Collections;
|
|
using System.Security.Permissions;
|
|
using System.Text;
|
|
using System.Configuration.Assemblies;
|
|
using System.Runtime.InteropServices;
|
|
using System.Reflection;
|
|
using System.Diagnostics;
|
|
using Microsoft.Win32;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Threading;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Runtime.Versioning;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
#if !FEATURE_PAL
|
|
[ComVisible(true)]
|
|
public enum EnvironmentVariableTarget {
|
|
Process = 0,
|
|
#if FEATURE_WIN32_REGISTRY
|
|
User = 1,
|
|
Machine = 2,
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
[ComVisible(true)]
|
|
public static class Environment {
|
|
|
|
// Assume the following constants include the terminating '\0' - use <, not <=
|
|
const int MaxEnvVariableValueLength = 32767; // maximum length for environment variable name and value
|
|
// System environment variables are stored in the registry, and have
|
|
// a size restriction that is separate from both normal environment
|
|
// variables and registry value name lengths, according to MSDN.
|
|
// MSDN doesn't detail whether the name is limited to 1024, or whether
|
|
// that includes the contents of the environment variable.
|
|
const int MaxSystemEnvVariableLength = 1024;
|
|
const int MaxUserEnvVariableLength = 255;
|
|
|
|
internal sealed class ResourceHelper
|
|
{
|
|
internal ResourceHelper(String name) {
|
|
m_name = name;
|
|
}
|
|
|
|
private String m_name;
|
|
private ResourceManager SystemResMgr;
|
|
|
|
// To avoid infinite loops when calling GetResourceString. See comments
|
|
// in GetResourceString for this field.
|
|
private Stack currentlyLoading;
|
|
|
|
// process-wide state (since this is only used in one domain),
|
|
// used to avoid the TypeInitialization infinite recusion
|
|
// in GetResourceStringCode
|
|
internal bool resourceManagerInited = false;
|
|
|
|
// Is this thread currently doing infinite resource lookups?
|
|
private int infinitelyRecursingCount;
|
|
|
|
// Data representing one individual resource lookup on a thread.
|
|
internal class GetResourceStringUserData
|
|
{
|
|
public ResourceHelper m_resourceHelper;
|
|
public String m_key;
|
|
public CultureInfo m_culture;
|
|
public String m_retVal;
|
|
public bool m_lockWasTaken;
|
|
|
|
public GetResourceStringUserData(ResourceHelper resourceHelper, String key, CultureInfo culture)
|
|
{
|
|
m_resourceHelper = resourceHelper;
|
|
m_key = key;
|
|
m_culture = culture;
|
|
}
|
|
}
|
|
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
internal String GetResourceString(String key) {
|
|
if (key == null || key.Length == 0) {
|
|
Contract.Assert(false, "Environment::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
|
|
return "[Resource lookup failed - null or empty resource name]";
|
|
}
|
|
return GetResourceString(key, null);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
internal String GetResourceString(String key, CultureInfo culture) {
|
|
if (key == null || key.Length == 0) {
|
|
Contract.Assert(false, "Environment::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
|
|
return "[Resource lookup failed - null or empty resource name]";
|
|
}
|
|
|
|
// We have a somewhat common potential for infinite
|
|
// loops with mscorlib's ResourceManager. If "potentially dangerous"
|
|
// code throws an exception, we will get into an infinite loop
|
|
// inside the ResourceManager and this "potentially dangerous" code.
|
|
// Potentially dangerous code includes the IO package, CultureInfo,
|
|
// parts of the loader, some parts of Reflection, Security (including
|
|
// custom user-written permissions that may parse an XML file at
|
|
// class load time), assembly load event handlers, etc. Essentially,
|
|
// this is not a bounded set of code, and we need to fix the problem.
|
|
// Fortunately, this is limited to mscorlib's error lookups and is NOT
|
|
// a general problem for all user code using the ResourceManager.
|
|
|
|
// The solution is to make sure only one thread at a time can call
|
|
// GetResourceString. Also, since resource lookups can be
|
|
// reentrant, if the same thread comes into GetResourceString
|
|
// twice looking for the exact same resource name before
|
|
// returning, we're going into an infinite loop and we should
|
|
// return a bogus string.
|
|
|
|
GetResourceStringUserData userData = new GetResourceStringUserData(this, key, culture);
|
|
|
|
RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(GetResourceStringCode);
|
|
RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(GetResourceStringBackoutCode);
|
|
|
|
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, userData);
|
|
return userData.m_retVal;
|
|
}
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#else
|
|
[System.Security.SecuritySafeCritical]
|
|
#endif
|
|
private void GetResourceStringCode(Object userDataIn)
|
|
{
|
|
GetResourceStringUserData userData = (GetResourceStringUserData) userDataIn;
|
|
ResourceHelper rh = userData.m_resourceHelper;
|
|
String key = userData.m_key;
|
|
CultureInfo culture = userData.m_culture;
|
|
|
|
Monitor.Enter(rh, ref userData.m_lockWasTaken);
|
|
|
|
// Are we recursively looking up the same resource? Note - our backout code will set
|
|
// the ResourceHelper's currentlyLoading stack to null if an exception occurs.
|
|
if (rh.currentlyLoading != null && rh.currentlyLoading.Count > 0 && rh.currentlyLoading.Contains(key)) {
|
|
// We can start infinitely recursing for one resource lookup,
|
|
// then during our failure reporting, start infinitely recursing again.
|
|
// avoid that.
|
|
if (rh.infinitelyRecursingCount > 0) {
|
|
userData.m_retVal = "[Resource lookup failed - infinite recursion or critical failure detected.]";
|
|
return;
|
|
}
|
|
rh.infinitelyRecursingCount++;
|
|
// This is often a bug in the BCL, security, NLS+ code,
|
|
// or the loader somewhere. However, this could also
|
|
// be a setup problem - check whether mscorlib &
|
|
// clr.dll are both of the same build flavor. Also, user
|
|
// code in the resource lookup process (like an assembly
|
|
// resolve event or custom CultureInfo) might potentially cause issues.
|
|
|
|
// Note: our infrastructure for reporting this exception will again cause resource lookup.
|
|
// This is the most direct way of dealing with that problem.
|
|
String message = "Infinite recursion during resource lookup within mscorlib. This may be a bug in mscorlib, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names. Resource name: " + key;
|
|
Assert.Fail("[mscorlib recursive resource lookup bug]", message, Assert.COR_E_FAILFAST, System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
|
|
Environment.FailFast(message);
|
|
}
|
|
if (rh.currentlyLoading == null)
|
|
rh.currentlyLoading = new Stack(4);
|
|
|
|
// Call class constructors preemptively, so that we cannot get into an infinite
|
|
// loop constructing a TypeInitializationException. If this were omitted,
|
|
// we could get the Infinite recursion assert above by failing type initialization
|
|
// between the Push and Pop calls below.
|
|
|
|
if (!rh.resourceManagerInited)
|
|
{
|
|
// process-critical code here. No ThreadAbortExceptions
|
|
// can be thrown here. Other exceptions percolate as normal.
|
|
RuntimeHelpers.PrepareConstrainedRegions();
|
|
try {
|
|
}
|
|
finally {
|
|
RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
|
|
RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
|
|
RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
|
|
RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
|
|
rh.resourceManagerInited = true;
|
|
}
|
|
|
|
}
|
|
|
|
rh.currentlyLoading.Push(key);
|
|
|
|
if (rh.SystemResMgr == null) {
|
|
rh.SystemResMgr = new ResourceManager(m_name, typeof(Object).Assembly);
|
|
}
|
|
String s = rh.SystemResMgr.GetString(key, null);
|
|
rh.currentlyLoading.Pop();
|
|
|
|
Contract.Assert(s!=null, "Managed resource string lookup failed. Was your resource name misspelled? Did you rebuild mscorlib after adding a resource to resources.txt? Debug this w/ cordbg and bug whoever owns the code that called Environment.GetResourceString. Resource name was: \""+key+"\"");
|
|
|
|
userData.m_retVal = s;
|
|
}
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#endif
|
|
[PrePrepareMethod]
|
|
private void GetResourceStringBackoutCode(Object userDataIn, bool exceptionThrown)
|
|
{
|
|
GetResourceStringUserData userData = (GetResourceStringUserData) userDataIn;
|
|
ResourceHelper rh = userData.m_resourceHelper;
|
|
|
|
if (exceptionThrown)
|
|
{
|
|
if (userData.m_lockWasTaken)
|
|
{
|
|
// Backout code - throw away potentially corrupt state
|
|
rh.SystemResMgr = null;
|
|
rh.currentlyLoading = null;
|
|
}
|
|
}
|
|
// Release the lock, if we took it.
|
|
if (userData.m_lockWasTaken)
|
|
{
|
|
Monitor.Exit(rh);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private static volatile ResourceHelper m_resHelper; // Doesn't need to be initialized as they're zero-init.
|
|
|
|
private const int MaxMachineNameLength = 256;
|
|
|
|
// Private object for locking instead of locking on a public type for SQL reliability work.
|
|
private static Object s_InternalSyncObject;
|
|
private static Object InternalSyncObject {
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
get {
|
|
if (s_InternalSyncObject == null) {
|
|
Object o = new Object();
|
|
Interlocked.CompareExchange<Object>(ref s_InternalSyncObject, o, null);
|
|
}
|
|
return s_InternalSyncObject;
|
|
}
|
|
}
|
|
|
|
|
|
private static volatile OperatingSystem m_os; // Cached OperatingSystem value
|
|
|
|
/*==================================TickCount===================================
|
|
**Action: Gets the number of ticks since the system was started.
|
|
**Returns: The number of ticks since the system was started.
|
|
**Arguments: None
|
|
**Exceptions: None
|
|
==============================================================================*/
|
|
public static extern int TickCount {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
// Terminates this process with the given exit code.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
internal static extern void _Exit(int exitCode);
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[ResourceConsumption(ResourceScope.Process)]
|
|
#pragma warning disable 618
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
|
|
#pragma warning restore 618
|
|
public static void Exit(int exitCode) {
|
|
_Exit(exitCode);
|
|
}
|
|
|
|
|
|
public static extern int ExitCode {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
get;
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
set;
|
|
}
|
|
|
|
// Note: The CLR's Watson bucketization code looks at the caller of the FCALL method
|
|
// to assign blame for crashes. Don't mess with this, such as by making it call
|
|
// another managed helper method, unless you consult with some CLR Watson experts.
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public static extern void FailFast(String message);
|
|
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern void FailFast(String message, uint exitCode);
|
|
|
|
// This overload of FailFast will allow you to specify the exception object
|
|
// whose bucket details *could* be used when undergoing the failfast process.
|
|
// To be specific:
|
|
//
|
|
// 1) When invoked from within a managed EH clause (fault/finally/catch),
|
|
// if the exception object is preallocated, the runtime will try to find its buckets
|
|
// and use them. If the exception object is not preallocated, it will use the bucket
|
|
// details contained in the object (if any).
|
|
//
|
|
// 2) When invoked from outside the managed EH clauses (fault/finally/catch),
|
|
// if the exception object is preallocated, the runtime will use the callsite's
|
|
// IP for bucketing. If the exception object is not preallocated, it will use the bucket
|
|
// details contained in the object (if any).
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
public static extern void FailFast(String message, Exception exception);
|
|
|
|
#if !FEATURE_CORECLR
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods.
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
|
internal static extern void TriggerCodeContractFailure(ContractFailureKind failureKind, String message, String condition, String exceptionAsString);
|
|
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SecurityCritical] // Our security team doesn't yet allow safe-critical P/Invoke methods.
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool GetIsCLRHosted();
|
|
|
|
internal static bool IsCLRHosted {
|
|
[SecuritySafeCritical]
|
|
get { return GetIsCLRHosted(); }
|
|
}
|
|
|
|
public static String CommandLine {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
|
|
|
|
String commandLine = null;
|
|
GetCommandLine(JitHelpers.GetStringHandleOnStack(ref commandLine));
|
|
return commandLine;
|
|
}
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
|
|
private static extern void GetCommandLine(StringHandleOnStack retString);
|
|
#endif // !FEATURE_CORECLR
|
|
|
|
/*===============================CurrentDirectory===============================
|
|
**Action: Provides a getter and setter for the current directory. The original
|
|
** current directory is the one from which the process was started.
|
|
**Returns: The current directory (from the getter). Void from the setter.
|
|
**Arguments: The current directory to which to switch to the setter.
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
public static String CurrentDirectory
|
|
{
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
get{
|
|
return Directory.GetCurrentDirectory();
|
|
}
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#endif
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
set {
|
|
Directory.SetCurrentDirectory(value);
|
|
}
|
|
}
|
|
|
|
// Returns the system directory (ie, C:\WinNT\System32).
|
|
public static String SystemDirectory {
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical]
|
|
#else
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#endif
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
get {
|
|
StringBuilder sb = new StringBuilder(Path.MAX_PATH);
|
|
int r = Win32Native.GetSystemDirectory(sb, Path.MAX_PATH);
|
|
Contract.Assert(r < Path.MAX_PATH, "r < Path.MAX_PATH");
|
|
if (r==0) __Error.WinIOError();
|
|
String path = sb.ToString();
|
|
|
|
#if !FEATURE_CORECLR
|
|
// Do security check
|
|
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
|
|
#endif
|
|
|
|
return path;
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
// Returns the windows directory (ie, C:\WinNT).
|
|
// Used by NLS+ custom culures only at the moment.
|
|
internal static String InternalWindowsDirectory {
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
get {
|
|
StringBuilder sb = new StringBuilder(Path.MAX_PATH);
|
|
int r = Win32Native.GetWindowsDirectory(sb, Path.MAX_PATH);
|
|
Contract.Assert(r < Path.MAX_PATH, "r < Path.MAX_PATH");
|
|
if (r==0) __Error.WinIOError();
|
|
String path = sb.ToString();
|
|
|
|
return path;
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public static String ExpandEnvironmentVariables(String name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException("name");
|
|
Contract.EndContractBlock();
|
|
|
|
if (name.Length == 0) {
|
|
return name;
|
|
}
|
|
|
|
if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
|
|
// Environment variable accessors are not approved modern API.
|
|
// Behave as if no variables are defined in this case.
|
|
return name;
|
|
}
|
|
|
|
int currentSize = 100;
|
|
StringBuilder blob = new StringBuilder(currentSize); // A somewhat reasonable default size
|
|
int size;
|
|
|
|
#if !FEATURE_CORECLR
|
|
bool isFullTrust = CodeAccessSecurityEngine.QuickCheckForAllDemands();
|
|
|
|
// Do a security check to guarantee we can read each of the
|
|
// individual environment variables requested here.
|
|
String[] varArray = name.Split(new char[] {'%'});
|
|
StringBuilder vars = isFullTrust ? null : new StringBuilder();
|
|
|
|
bool fJustExpanded = false; // to accommodate expansion alg.
|
|
|
|
for(int i=1; i<varArray.Length-1; i++) { // Skip first and last tokens
|
|
// ExpandEnvironmentStrings' greedy algorithm expands every
|
|
// non-boundary %-delimited substring, provided the previous
|
|
// has not been expanded.
|
|
// if "foo" is not expandable, and "PATH" is, then both
|
|
// %foo%PATH% and %foo%foo%PATH% will expand PATH, but
|
|
// %PATH%PATH% will expand only once.
|
|
// Therefore, if we've just expanded, skip this substring.
|
|
if (varArray[i].Length == 0 || fJustExpanded == true)
|
|
{
|
|
fJustExpanded = false;
|
|
continue; // Nothing to expand
|
|
}
|
|
// Guess a somewhat reasonable initial size, call the method, then if
|
|
// it fails (ie, the return value is larger than our buffer size),
|
|
// make a new buffer & try again.
|
|
blob.Length = 0;
|
|
String envVar = "%" + varArray[i] + "%";
|
|
size = Win32Native.ExpandEnvironmentStrings(envVar, blob, currentSize);
|
|
if (size == 0)
|
|
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
|
|
// some environment variable might be changed while this function is called
|
|
while (size > currentSize) {
|
|
currentSize = size;
|
|
blob.Capacity = currentSize;
|
|
blob.Length = 0;
|
|
size = Win32Native.ExpandEnvironmentStrings(envVar, blob, currentSize);
|
|
if (size == 0)
|
|
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
}
|
|
|
|
if (!isFullTrust) {
|
|
String temp = blob.ToString();
|
|
fJustExpanded = (temp != envVar);
|
|
if (fJustExpanded) { // We expanded successfully, we need to do String comparison here
|
|
// since %FOO% can become %FOOD
|
|
vars.Append(varArray[i]);
|
|
vars.Append(';');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isFullTrust)
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand();
|
|
#endif // !FEATURE_CORECLR
|
|
|
|
blob.Length = 0;
|
|
size = Win32Native.ExpandEnvironmentStrings(name, blob, currentSize);
|
|
if (size == 0)
|
|
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
|
|
while (size > currentSize) {
|
|
currentSize = size;
|
|
blob.Capacity = currentSize;
|
|
blob.Length = 0;
|
|
|
|
size = Win32Native.ExpandEnvironmentStrings(name, blob, currentSize);
|
|
if (size == 0)
|
|
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
}
|
|
|
|
return blob.ToString();
|
|
}
|
|
#endif // FEATURE_PAL
|
|
|
|
public static String MachineName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
// In future release of operating systems, you might be able to rename a machine without
|
|
// rebooting. Therefore, don't cache this machine name.
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read, "COMPUTERNAME").Demand();
|
|
StringBuilder buf = new StringBuilder(MaxMachineNameLength);
|
|
int len = MaxMachineNameLength;
|
|
if (Win32Native.GetComputerName(buf, ref len) == 0)
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ComputerName"));
|
|
return buf.ToString();
|
|
}
|
|
}
|
|
|
|
[SecurityCritical]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
private static extern Int32 GetProcessorCount();
|
|
|
|
public static int ProcessorCount {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
return GetProcessorCount();
|
|
}
|
|
}
|
|
|
|
public static int SystemPageSize {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
(new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
|
|
Win32Native.SYSTEM_INFO info = new Win32Native.SYSTEM_INFO();
|
|
Win32Native.GetSystemInfo(ref info);
|
|
return info.dwPageSize;
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
/*==============================GetCommandLineArgs==============================
|
|
**Action: Gets the command line and splits it appropriately to deal with whitespace,
|
|
** quotes, and escape characters.
|
|
**Returns: A string array containing your command line arguments.
|
|
**Arguments: None
|
|
**Exceptions: None.
|
|
==============================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public static String[] GetCommandLineArgs() {
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read, "Path").Demand();
|
|
return GetCommandLineArgsNative();
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern String[] GetCommandLineArgsNative();
|
|
|
|
// We need to keep this Fcall since it is used in AppDomain.cs.
|
|
// If we call GetEnvironmentVariable from AppDomain.cs, we will use StringBuilder class.
|
|
// That has side effect to change the ApartmentState of the calling Thread to MTA.
|
|
// So runtime can't change the ApartmentState of calling thread any more.
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Process)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern String nativeGetEnvironmentVariable(String variable);
|
|
#endif //!FEATURE_CORECLR
|
|
|
|
/*============================GetEnvironmentVariable============================
|
|
**Action:
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static String GetEnvironmentVariable(String variable)
|
|
{
|
|
if (variable == null)
|
|
throw new ArgumentNullException("variable");
|
|
Contract.EndContractBlock();
|
|
|
|
if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
|
|
// Environment variable accessors are not approved modern API.
|
|
// Behave as if the variable was not found in this case.
|
|
return null;
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
(new EnvironmentPermission(EnvironmentPermissionAccess.Read, variable)).Demand();
|
|
#endif //!FEATURE_CORECLR
|
|
|
|
StringBuilder blob = StringBuilderCache.Acquire(128); // A somewhat reasonable default size
|
|
int requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
|
|
|
|
if (requiredSize == 0) { // GetEnvironmentVariable failed
|
|
if (Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND) {
|
|
StringBuilderCache.Release(blob);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
while (requiredSize > blob.Capacity) { // need to retry since the environment variable might be changed
|
|
blob.Capacity = requiredSize;
|
|
blob.Length = 0;
|
|
requiredSize = Win32Native.GetEnvironmentVariable(variable, blob, blob.Capacity);
|
|
}
|
|
return StringBuilderCache.GetStringAndRelease(blob);
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static string GetEnvironmentVariable( string variable, EnvironmentVariableTarget target)
|
|
{
|
|
if (variable == null)
|
|
{
|
|
throw new ArgumentNullException("variable");
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
if (target == EnvironmentVariableTarget.Process)
|
|
{
|
|
return GetEnvironmentVariable(variable);
|
|
}
|
|
|
|
#if FEATURE_WIN32_REGISTRY
|
|
(new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
|
|
|
|
if( target == EnvironmentVariableTarget.Machine) {
|
|
using (RegistryKey environmentKey =
|
|
Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) {
|
|
|
|
Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!");
|
|
if (environmentKey == null) {
|
|
return null;
|
|
}
|
|
|
|
string value = environmentKey.GetValue(variable) as string;
|
|
return value;
|
|
}
|
|
}
|
|
else if( target == EnvironmentVariableTarget.User) {
|
|
using (RegistryKey environmentKey =
|
|
Registry.CurrentUser.OpenSubKey("Environment", false)) {
|
|
|
|
Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!");
|
|
if (environmentKey == null) {
|
|
return null;
|
|
}
|
|
|
|
string value = environmentKey.GetValue(variable) as string;
|
|
return value;
|
|
}
|
|
}
|
|
else
|
|
#endif // FEATURE_WIN32_REGISTRY
|
|
{
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*===========================GetEnvironmentVariables============================
|
|
**Action: Returns an IDictionary containing all enviroment variables and their values.
|
|
**Returns: An IDictionary containing all environment variables and their values.
|
|
**Arguments: None.
|
|
**Exceptions: None.
|
|
==============================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
private unsafe static char[] GetEnvironmentCharArray()
|
|
{
|
|
char[] block = null;
|
|
|
|
// Make sure pStrings is not leaked with async exceptions
|
|
RuntimeHelpers.PrepareConstrainedRegions();
|
|
try {
|
|
}
|
|
finally {
|
|
char * pStrings = null;
|
|
|
|
try
|
|
{
|
|
pStrings = Win32Native.GetEnvironmentStrings();
|
|
if (pStrings == null) {
|
|
throw new OutOfMemoryException();
|
|
}
|
|
|
|
// Format for GetEnvironmentStrings is:
|
|
// [=HiddenVar=value\0]* [Variable=value\0]* \0
|
|
// See the description of Environment Blocks in MSDN's
|
|
// CreateProcess page (null-terminated array of null-terminated strings).
|
|
|
|
// Search for terminating \0\0 (two unicode \0's).
|
|
char * p = pStrings;
|
|
while (!(*p == '\0' && *(p + 1) == '\0'))
|
|
p++;
|
|
|
|
int len = (int)(p - pStrings + 1);
|
|
block = new char[len];
|
|
|
|
fixed (char* pBlock = block)
|
|
String.wstrcpy(pBlock, pStrings, len);
|
|
}
|
|
finally
|
|
{
|
|
if (pStrings != null)
|
|
Win32Native.FreeEnvironmentStrings(pStrings);
|
|
}
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static IDictionary GetEnvironmentVariables()
|
|
{
|
|
if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
|
|
// Environment variable accessors are not approved modern API.
|
|
// Behave as if no environment variables are defined in this case.
|
|
return new Hashtable(0);
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
bool isFullTrust = CodeAccessSecurityEngine.QuickCheckForAllDemands();
|
|
StringBuilder vars = isFullTrust ? null : new StringBuilder();
|
|
bool first = true;
|
|
#endif
|
|
|
|
char[] block = GetEnvironmentCharArray();
|
|
|
|
Hashtable table = new Hashtable(20);
|
|
|
|
// Copy strings out, parsing into pairs and inserting into the table.
|
|
// The first few environment variable entries start with an '='!
|
|
// The current working directory of every drive (except for those drives
|
|
// you haven't cd'ed into in your DOS window) are stored in the
|
|
// environment block (as =C:=pwd) and the program's exit code is
|
|
// as well (=ExitCode=00000000) Skip all that start with =.
|
|
// Read docs about Environment Blocks on MSDN's CreateProcess page.
|
|
|
|
// Format for GetEnvironmentStrings is:
|
|
// (=HiddenVar=value\0 | Variable=value\0)* \0
|
|
// See the description of Environment Blocks in MSDN's
|
|
// CreateProcess page (null-terminated array of null-terminated strings).
|
|
// Note the =HiddenVar's aren't always at the beginning.
|
|
|
|
for(int i=0; i<block.Length; i++) {
|
|
int startKey = i;
|
|
// Skip to key
|
|
// On some old OS, the environment block can be corrupted.
|
|
// Someline will not have '=', so we need to check for '\0'.
|
|
while(block[i]!='=' && block[i] != '\0') {
|
|
i++;
|
|
}
|
|
|
|
if(block[i] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
// Skip over environment variables starting with '='
|
|
if (i-startKey==0) {
|
|
while(block[i]!=0) {
|
|
i++;
|
|
}
|
|
continue;
|
|
}
|
|
String key = new String(block, startKey, i-startKey);
|
|
i++; // skip over '='
|
|
int startValue = i;
|
|
while(block[i]!=0) {
|
|
// Read to end of this entry
|
|
i++;
|
|
}
|
|
|
|
String value = new String(block, startValue, i-startValue);
|
|
// skip over 0 handled by for loop's i++
|
|
table[key]=value;
|
|
|
|
#if !FEATURE_CORECLR
|
|
if (!isFullTrust) {
|
|
if( first) {
|
|
first = false;
|
|
}
|
|
else {
|
|
vars.Append(';');
|
|
}
|
|
vars.Append(key);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
if (!isFullTrust)
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read, vars.ToString()).Demand();
|
|
#endif
|
|
return table;
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
internal static IDictionary GetRegistryKeyNameValuePairs(RegistryKey registryKey) {
|
|
Hashtable table = new Hashtable(20);
|
|
|
|
if (registryKey != null) {
|
|
string[] names = registryKey.GetValueNames();
|
|
foreach( string name in names) {
|
|
string value = registryKey.GetValue(name, "").ToString();
|
|
table.Add(name, value);
|
|
}
|
|
}
|
|
return table;
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static IDictionary GetEnvironmentVariables( EnvironmentVariableTarget target) {
|
|
if( target == EnvironmentVariableTarget.Process) {
|
|
return GetEnvironmentVariables();
|
|
}
|
|
|
|
#if FEATURE_WIN32_REGISTRY
|
|
(new EnvironmentPermission(PermissionState.Unrestricted)).Demand();
|
|
|
|
if( target == EnvironmentVariableTarget.Machine) {
|
|
using (RegistryKey environmentKey =
|
|
Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false)) {
|
|
|
|
return GetRegistryKeyNameValuePairs(environmentKey);
|
|
}
|
|
}
|
|
else if( target == EnvironmentVariableTarget.User) {
|
|
using (RegistryKey environmentKey =
|
|
Registry.CurrentUser.OpenSubKey("Environment", false)) {
|
|
return GetRegistryKeyNameValuePairs(environmentKey);
|
|
}
|
|
}
|
|
else
|
|
#endif // FEATURE_WIN32_REGISTRY
|
|
{
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static void SetEnvironmentVariable(string variable, string value) {
|
|
CheckEnvironmentVariableName(variable);
|
|
|
|
#if !FEATURE_CORECLR
|
|
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
|
|
#endif
|
|
// explicitly null out value if is the empty string.
|
|
if (String.IsNullOrEmpty(value) || value[0] == '\0') {
|
|
value = null;
|
|
}
|
|
else {
|
|
if( value.Length >= MaxEnvVariableValueLength) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
|
|
}
|
|
}
|
|
|
|
if (AppDomain.IsAppXModel() && !AppDomain.IsAppXDesignMode()) {
|
|
// Environment variable accessors are not approved modern API.
|
|
// so we throw PlatformNotSupportedException.
|
|
throw new PlatformNotSupportedException();
|
|
}
|
|
|
|
if(!Win32Native.SetEnvironmentVariable(variable, value)) {
|
|
int errorCode = Marshal.GetLastWin32Error();
|
|
|
|
// Allow user to try to clear a environment variable
|
|
if( errorCode == Win32Native.ERROR_ENVVAR_NOT_FOUND) {
|
|
return;
|
|
}
|
|
|
|
// The error message from Win32 is "The filename or extension is too long",
|
|
// which is not accurate.
|
|
if( errorCode == Win32Native.ERROR_FILENAME_EXCED_RANGE) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
|
|
}
|
|
|
|
throw new ArgumentException(Win32Native.GetMessage(errorCode));
|
|
}
|
|
}
|
|
|
|
private static void CheckEnvironmentVariableName(string variable) {
|
|
if (variable == null) {
|
|
throw new ArgumentNullException("variable");
|
|
}
|
|
|
|
if( variable.Length == 0) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_StringZeroLength"), "variable");
|
|
}
|
|
|
|
if( variable[0] == '\0') {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_StringFirstCharIsZero"), "variable");
|
|
}
|
|
|
|
// Make sure the environment variable name isn't longer than the
|
|
// max limit on environment variable values. (MSDN is ambiguous
|
|
// on whether this check is necessary.)
|
|
if( variable.Length >= MaxEnvVariableValueLength ) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
|
|
}
|
|
|
|
if( variable.IndexOf('=') != -1) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_IllegalEnvVarName"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) {
|
|
if( target == EnvironmentVariableTarget.Process) {
|
|
SetEnvironmentVariable(variable, value);
|
|
return;
|
|
}
|
|
|
|
CheckEnvironmentVariableName(variable);
|
|
|
|
// System-wide environment variables stored in the registry are
|
|
// limited to 1024 chars for the environment variable name.
|
|
if (variable.Length >= MaxSystemEnvVariableLength) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarName"));
|
|
}
|
|
|
|
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
|
|
// explicitly null out value if is the empty string.
|
|
if (String.IsNullOrEmpty(value) || value[0] == '\0') {
|
|
value = null;
|
|
}
|
|
#if FEATURE_WIN32_REGISTRY
|
|
if( target == EnvironmentVariableTarget.Machine) {
|
|
using (RegistryKey environmentKey =
|
|
Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", true)) {
|
|
|
|
Contract.Assert(environmentKey != null, @"HKLM\System\CurrentControlSet\Control\Session Manager\Environment is missing!");
|
|
if (environmentKey != null) {
|
|
if (value == null)
|
|
environmentKey.DeleteValue(variable, false);
|
|
else
|
|
environmentKey.SetValue(variable, value);
|
|
}
|
|
}
|
|
}
|
|
else if( target == EnvironmentVariableTarget.User) {
|
|
// User-wide environment variables stored in the registry are
|
|
// limited to 255 chars for the environment variable name.
|
|
if (variable.Length >= MaxUserEnvVariableLength) {
|
|
throw new ArgumentException(Environment.GetResourceString("Argument_LongEnvVarValue"));
|
|
}
|
|
using (RegistryKey environmentKey =
|
|
Registry.CurrentUser.OpenSubKey("Environment", true)) {
|
|
Contract.Assert(environmentKey != null, @"HKCU\Environment is missing!");
|
|
if (environmentKey != null) {
|
|
if (value == null)
|
|
environmentKey.DeleteValue(variable, false);
|
|
else
|
|
environmentKey.SetValue(variable, value);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
|
|
}
|
|
// send a WM_SETTINGCHANGE message to all windows
|
|
IntPtr r = Win32Native.SendMessageTimeout(new IntPtr(Win32Native.HWND_BROADCAST), Win32Native.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
|
|
|
|
if (r == IntPtr.Zero) BCLDebug.Assert(false, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
|
|
|
|
#else // FEATURE_WIN32_REGISTRY
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)target));
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
/*===============================GetLogicalDrives===============================
|
|
**Action: Retrieves the names of the logical drives on this machine in the form "C:\".
|
|
**Arguments: None.
|
|
**Exceptions: IOException.
|
|
**Permissions: SystemInfo Permission.
|
|
==============================================================================*/
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
public static String[] GetLogicalDrives() {
|
|
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
|
|
|
|
int drives = Win32Native.GetLogicalDrives();
|
|
if (drives==0)
|
|
__Error.WinIOError();
|
|
uint d = (uint)drives;
|
|
int count = 0;
|
|
while (d != 0) {
|
|
if (((int)d & 1) != 0) count++;
|
|
d >>= 1;
|
|
}
|
|
String[] result = new String[count];
|
|
char[] root = new char[] {'A', ':', '\\'};
|
|
d = (uint)drives;
|
|
count = 0;
|
|
while (d != 0) {
|
|
if (((int)d & 1) != 0) {
|
|
result[count++] = new String(root);
|
|
}
|
|
d >>= 1;
|
|
root[0]++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*===================================NewLine====================================
|
|
**Action: A property which returns the appropriate newline string for the given
|
|
** platform.
|
|
**Returns: \r\n on Win32.
|
|
**Arguments: None.
|
|
**Exceptions: None.
|
|
==============================================================================*/
|
|
public static String NewLine {
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
return "\r\n";
|
|
}
|
|
}
|
|
|
|
|
|
/*===================================Version====================================
|
|
**Action: Returns the COM+ version struct, describing the build number.
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
public static Version Version {
|
|
get {
|
|
|
|
// Previously this represented the File version of mscorlib.dll. Many other libraries in the framework and outside took dependencies on the first three parts of this version
|
|
// remaining constant throughout 4.x. From 4.0 to 4.5.2 this was fine since the file version only incremented the last part.Starting with 4.6 we switched to a file versioning
|
|
// scheme that matched the product version. In order to preserve compatibility with existing libraries, this needs to be hard-coded.
|
|
|
|
return new Version(4,0,30319,42000);
|
|
}
|
|
}
|
|
|
|
|
|
/*==================================WorkingSet==================================
|
|
**Action:
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
|
|
private static extern long GetWorkingSet();
|
|
|
|
public static long WorkingSet {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
|
|
return GetWorkingSet();
|
|
}
|
|
}
|
|
|
|
|
|
/*==================================OSVersion===================================
|
|
**Action:
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
public static OperatingSystem OSVersion {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<OperatingSystem>() != null);
|
|
|
|
if (m_os==null) { // We avoid the lock since we don't care if two threads will set this at the same time.
|
|
|
|
Microsoft.Win32.Win32Native.OSVERSIONINFO osvi = new Microsoft.Win32.Win32Native.OSVERSIONINFO();
|
|
if (!GetVersion(osvi)) {
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_GetVersion"));
|
|
}
|
|
|
|
Microsoft.Win32.Win32Native.OSVERSIONINFOEX osviEx = new Microsoft.Win32.Win32Native.OSVERSIONINFOEX();
|
|
if (!GetVersionEx(osviEx))
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_GetVersion"));
|
|
|
|
PlatformID id = PlatformID.Win32NT;
|
|
|
|
#if FEATURE_LEGACYNETCF
|
|
// return platform as WinCE, to ensure apps earlier than WP8 works as expected.
|
|
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
{
|
|
id = PlatformID.WinCE;
|
|
}
|
|
#endif
|
|
|
|
Version v = new Version(osvi.MajorVersion, osvi.MinorVersion, osvi.BuildNumber, (osviEx.ServicePackMajor << 16) |osviEx.ServicePackMinor);
|
|
m_os = new OperatingSystem(id, v, osvi.CSDVersion);
|
|
}
|
|
Contract.Assert(m_os != null, "m_os != null");
|
|
return m_os;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_CORESYSTEM
|
|
|
|
internal static bool IsWindows8OrAbove {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_COMINTEROP
|
|
internal static bool IsWinRTSupported {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
#else // FEATURE_CORESYSTEM
|
|
|
|
private static volatile bool s_IsWindows8OrAbove;
|
|
private static volatile bool s_CheckedOSWin8OrAbove;
|
|
|
|
// Windows 8 version is 6.2
|
|
internal static bool IsWindows8OrAbove {
|
|
get {
|
|
if (!s_CheckedOSWin8OrAbove) {
|
|
OperatingSystem OS = Environment.OSVersion;
|
|
s_IsWindows8OrAbove = (OS.Platform == PlatformID.Win32NT &&
|
|
((OS.Version.Major == 6 && OS.Version.Minor >= 2) || (OS.Version.Major > 6)));
|
|
s_CheckedOSWin8OrAbove = true;
|
|
}
|
|
return s_IsWindows8OrAbove;
|
|
}
|
|
}
|
|
|
|
#if FEATURE_COMINTEROP
|
|
private static volatile bool s_WinRTSupported;
|
|
private static volatile bool s_CheckedWinRT;
|
|
|
|
// Does the current version of Windows have Windows Runtime suppport?
|
|
internal static bool IsWinRTSupported {
|
|
[SecuritySafeCritical]
|
|
get {
|
|
if (!s_CheckedWinRT) {
|
|
s_WinRTSupported = WinRTSupported();
|
|
s_CheckedWinRT = true;
|
|
}
|
|
|
|
return s_WinRTSupported;
|
|
}
|
|
}
|
|
|
|
[SecurityCritical]
|
|
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool WinRTSupported();
|
|
#endif // FEATURE_COMINTEROP
|
|
|
|
#endif // FEATURE_CORESYSTEM
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern bool GetVersion(Microsoft.Win32.Win32Native.OSVERSIONINFO osVer);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal static extern bool GetVersionEx(Microsoft.Win32.Win32Native.OSVERSIONINFOEX osVer);
|
|
|
|
|
|
/*==================================StackTrace==================================
|
|
**Action:
|
|
**Returns:
|
|
**Arguments:
|
|
**Exceptions:
|
|
==============================================================================*/
|
|
public static String StackTrace {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
Contract.Ensures(Contract.Result<String>() != null);
|
|
|
|
new EnvironmentPermission(PermissionState.Unrestricted).Demand();
|
|
return GetStackTrace(null, true);
|
|
}
|
|
}
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#endif
|
|
internal static String GetStackTrace(Exception e, bool needFileInfo)
|
|
{
|
|
// Note: Setting needFileInfo to true will start up COM and set our
|
|
// apartment state. Try to not call this when passing "true"
|
|
// before the EE's ExecuteMainMethod has had a chance to set up the
|
|
// apartment state. --
|
|
StackTrace st;
|
|
if (e == null)
|
|
st = new StackTrace(needFileInfo);
|
|
else
|
|
st = new StackTrace(e, needFileInfo);
|
|
|
|
// Do no include a trailing newline for backwards compatibility
|
|
return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
private static void InitResourceHelper() {
|
|
// Only the default AppDomain should have a ResourceHelper. All calls to
|
|
// GetResourceString from any AppDomain delegate to GetResourceStringLocal
|
|
// in the default AppDomain via the fcall GetResourceFromDefault.
|
|
|
|
bool tookLock = false;
|
|
RuntimeHelpers.PrepareConstrainedRegions();
|
|
try {
|
|
|
|
Monitor.Enter(Environment.InternalSyncObject, ref tookLock);
|
|
|
|
if (m_resHelper == null) {
|
|
ResourceHelper rh = new ResourceHelper("mscorlib");
|
|
|
|
System.Threading.Thread.MemoryBarrier();
|
|
m_resHelper =rh;
|
|
}
|
|
}
|
|
finally {
|
|
if (tookLock)
|
|
Monitor.Exit(Environment.InternalSyncObject);
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
internal extern static String GetResourceFromDefault(String key);
|
|
#endif
|
|
|
|
// Looks up the resource string value for key.
|
|
//
|
|
// if you change this method's signature then you must change the code that calls it
|
|
// in excep.cpp and probably you will have to visit mscorlib.h to add the new signature
|
|
// as well as metasig.h to create the new signature type
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#endif
|
|
internal static String GetResourceStringLocal(String key) {
|
|
if (m_resHelper == null)
|
|
InitResourceHelper();
|
|
|
|
return m_resHelper.GetResourceString(key);
|
|
}
|
|
|
|
// #threadCultureInfo
|
|
// Currently in silverlight, CurrentCulture and CurrentUICulture are isolated
|
|
// within an AppDomain. This is in contrast to the desktop, in which cultures
|
|
// leak across AppDomain boundaries with the thread.
|
|
//
|
|
// Note that mscorlib transitions to the default domain to perform resource
|
|
// lookup. This causes problems for the silverlight changes: since culture isn't
|
|
// passed, resource string lookup won't necessarily use the culture of the thread
|
|
// originating the request. To get around that problem, we pass the CultureInfo
|
|
// so that the ResourceManager GetString(x, cultureInfo) overload can be used.
|
|
// We first perform the same check as in CultureInfo to make sure it's safe to
|
|
// let the CultureInfo travel across AppDomains.
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
internal static String GetResourceString(String key) {
|
|
#if FEATURE_CORECLR
|
|
return GetResourceStringLocal(key);
|
|
#else
|
|
return GetResourceFromDefault(key);
|
|
#endif //FEATURE_CORECLR
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
internal static String GetResourceString(String key, params Object[] values) {
|
|
String s = GetResourceString(key);
|
|
return String.Format(CultureInfo.CurrentCulture, s, values);
|
|
}
|
|
|
|
//The following two internal methods are not used anywhere within the framework,
|
|
// but are being kept around as external platforms built on top of us have taken
|
|
// dependency by using private reflection on them for getting system resource strings
|
|
[ResourceExposure(ResourceScope.None)]
|
|
internal static String GetRuntimeResourceString(String key) {
|
|
return GetResourceString(key);
|
|
}
|
|
|
|
[ResourceExposure(ResourceScope.None)]
|
|
internal static String GetRuntimeResourceString(String key, params Object[] values) {
|
|
return GetResourceString(key,values);
|
|
}
|
|
|
|
public static bool Is64BitProcess {
|
|
get {
|
|
#if WIN32
|
|
return false;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
public static bool Is64BitOperatingSystem {
|
|
[System.Security.SecuritySafeCritical]
|
|
get {
|
|
#if WIN32
|
|
bool isWow64; // WinXP SP2+ and Win2k3 SP1+
|
|
return Win32Native.DoesWin32MethodExist(Win32Native.KERNEL32, "IsWow64Process")
|
|
&& Win32Native.IsWow64Process(Win32Native.GetCurrentProcess(), out isWow64)
|
|
&& isWow64;
|
|
#else
|
|
// 64-bit programs run only on 64-bit
|
|
//<
|
|
return true;
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
public static extern bool HasShutdownStarted {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
#if !FEATURE_CORECLR
|
|
// This is the temporary Whidbey stub for compatibility flags
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
[System.Security.SecurityCritical]
|
|
internal static extern bool GetCompatibilityFlag(CompatibilityFlag flag);
|
|
#endif //!FEATURE_CORECLR
|
|
|
|
public static string UserName {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserName").Demand();
|
|
|
|
StringBuilder sb = new StringBuilder(256);
|
|
int size = sb.Capacity;
|
|
if (Win32Native.GetUserName(sb, ref size))
|
|
{
|
|
return sb.ToString();
|
|
}
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
// Note that this is a handle to a process window station, but it does
|
|
// not need to be closed. CloseWindowStation would ignore this handle.
|
|
// We also do handle equality checking as well. This isn't a great fit
|
|
// for SafeHandle. We don't gain anything by using SafeHandle here.
|
|
#if !FEATURE_PAL && !FEATURE_CORESYSTEM
|
|
private static volatile IntPtr processWinStation; // Doesn't need to be initialized as they're zero-init.
|
|
private static volatile bool isUserNonInteractive;
|
|
#endif
|
|
|
|
public static bool UserInteractive {
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
|
|
get {
|
|
#if !FEATURE_PAL && !FEATURE_CORESYSTEM
|
|
IntPtr hwinsta = Win32Native.GetProcessWindowStation();
|
|
if (hwinsta != IntPtr.Zero && processWinStation != hwinsta) {
|
|
int lengthNeeded = 0;
|
|
Win32Native.USEROBJECTFLAGS flags = new Win32Native.USEROBJECTFLAGS();
|
|
if (Win32Native.GetUserObjectInformation(hwinsta, Win32Native.UOI_FLAGS, flags, Marshal.SizeOf(flags),ref lengthNeeded)) {
|
|
if ((flags.dwFlags & Win32Native.WSF_VISIBLE) == 0) {
|
|
isUserNonInteractive = true;
|
|
}
|
|
}
|
|
processWinStation = hwinsta;
|
|
}
|
|
|
|
// The logic is reversed to avoid static initialization to true
|
|
return !isUserNonInteractive;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static string GetFolderPath(SpecialFolder folder) {
|
|
if (!Enum.IsDefined(typeof(SpecialFolder), folder))
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
|
|
Contract.EndContractBlock();
|
|
|
|
return InternalGetFolderPath(folder, SpecialFolderOption.None);
|
|
}
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option) {
|
|
if (!Enum.IsDefined(typeof(SpecialFolder),folder))
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)folder));
|
|
if (!Enum.IsDefined(typeof(SpecialFolderOption),option))
|
|
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)option));
|
|
Contract.EndContractBlock();
|
|
|
|
return InternalGetFolderPath(folder, option);
|
|
}
|
|
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
internal static string UnsafeGetFolderPath(SpecialFolder folder)
|
|
{
|
|
return InternalGetFolderPath(folder, SpecialFolderOption.None, suppressSecurityChecks: true);
|
|
}
|
|
|
|
[System.Security.SecurityCritical]
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[ResourceConsumption(ResourceScope.Machine)]
|
|
private static string InternalGetFolderPath(SpecialFolder folder, SpecialFolderOption option, bool suppressSecurityChecks = false)
|
|
{
|
|
#if FEATURE_CORESYSTEM
|
|
// This is currently customized for Windows Phone since CoreSystem doesn't support
|
|
// SHGetFolderPath. The allowed folder values are based on the version of .NET CF WP7 was using.
|
|
switch (folder)
|
|
{
|
|
case SpecialFolder.System:
|
|
return SystemDirectory;
|
|
case SpecialFolder.ApplicationData:
|
|
case SpecialFolder.Favorites:
|
|
case SpecialFolder.Programs:
|
|
case SpecialFolder.StartMenu:
|
|
case SpecialFolder.Startup:
|
|
case SpecialFolder.Personal:
|
|
throw new PlatformNotSupportedException();
|
|
default:
|
|
throw new PlatformNotSupportedException();
|
|
}
|
|
#else // FEATURE_CORESYSTEM
|
|
#if !FEATURE_CORECLR
|
|
if (option == SpecialFolderOption.Create && !suppressSecurityChecks) {
|
|
FileIOPermission createPermission = new FileIOPermission(PermissionState.None);
|
|
createPermission.AllFiles = FileIOPermissionAccess.Write;
|
|
createPermission.Demand();
|
|
}
|
|
#endif
|
|
|
|
StringBuilder sb = new StringBuilder(Path.MAX_PATH);
|
|
int hresult = Win32Native.SHGetFolderPath(IntPtr.Zero, /* hwndOwner: [in] Reserved */
|
|
((int)folder | (int)option), /* nFolder: [in] CSIDL */
|
|
IntPtr.Zero, /* hToken: [in] access token */
|
|
Win32Native.SHGFP_TYPE_CURRENT, /* dwFlags: [in] retrieve current path */
|
|
sb); /* pszPath: [out]resultant path */
|
|
String s;
|
|
if (hresult < 0)
|
|
{
|
|
switch (hresult)
|
|
{
|
|
default:
|
|
// The previous incarnation threw away all errors. In order to limit
|
|
// breaking changes, we will be permissive about these errors
|
|
// instead of calling ThowExceptionForHR.
|
|
//Runtime.InteropServices.Marshal.ThrowExceptionForHR(hresult);
|
|
break;
|
|
case __HResults.COR_E_PLATFORMNOTSUPPORTED:
|
|
// This one error is the one we do want to throw.
|
|
// <
|
|
|
|
throw new PlatformNotSupportedException();
|
|
}
|
|
|
|
// SHGetFolderPath does not initialize the output buffer on error
|
|
s = String.Empty;
|
|
}
|
|
else
|
|
{
|
|
s = sb.ToString();
|
|
}
|
|
|
|
if (!suppressSecurityChecks)
|
|
{
|
|
// On CoreCLR we can check with the host if we're not trying to use any special options.
|
|
// Otherwise, we need to do a full demand since hosts aren't expecting to handle requests to
|
|
// create special folders.
|
|
#if FEATURE_CORECLR
|
|
if (option == SpecialFolderOption.None)
|
|
{
|
|
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, s);
|
|
state.EnsureState();
|
|
}
|
|
else
|
|
#endif // FEATURE_CORECLR
|
|
{
|
|
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, s).Demand();
|
|
}
|
|
}
|
|
return s;
|
|
#endif // FEATURE_CORESYSTEM
|
|
}
|
|
|
|
#if !FEATURE_PAL
|
|
public static string UserDomainName
|
|
{
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
get {
|
|
new EnvironmentPermission(EnvironmentPermissionAccess.Read,"UserDomain").Demand();
|
|
|
|
byte[] sid = new byte[1024];
|
|
int sidLen = sid.Length;
|
|
StringBuilder domainName = new StringBuilder(1024);
|
|
uint domainNameLen = (uint) domainName.Capacity;
|
|
int peUse;
|
|
|
|
byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen);
|
|
if (ret == 1) {
|
|
string samName = domainName.ToString();
|
|
int index = samName.IndexOf('\\');
|
|
if( index != -1) {
|
|
return samName.Substring(0, index);
|
|
}
|
|
}
|
|
domainNameLen = (uint) domainName.Capacity;
|
|
|
|
bool success = Win32Native.LookupAccountName(null, UserName, sid, ref sidLen, domainName, ref domainNameLen, out peUse);
|
|
if (!success) {
|
|
int errorCode = Marshal.GetLastWin32Error();
|
|
throw new InvalidOperationException(Win32Native.GetMessage(errorCode));
|
|
}
|
|
|
|
return domainName.ToString();
|
|
}
|
|
}
|
|
#endif // !FEATURE_PAL
|
|
public enum SpecialFolderOption {
|
|
None = 0,
|
|
Create = Win32Native.CSIDL_FLAG_CREATE,
|
|
DoNotVerify = Win32Native.CSIDL_FLAG_DONT_VERIFY,
|
|
}
|
|
|
|
//////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!////////
|
|
//////!!!!!! Keep the following locations synchronized !!!!!!////////
|
|
//////!!!!!! 1) ndp\clr\src\BCL\Microsoft\Win32\Win32Native.cs !!!!!!////////
|
|
//////!!!!!! 2) ndp\clr\src\BCL\System\Environment.cs !!!!!!////////
|
|
//////!!!!!! 3) rotor\pal\inc\rotor_pal.h !!!!!!////////
|
|
//////!!!!!! 4) rotor\pal\corunix\shfolder\shfolder.cpp !!!!!!////////
|
|
//////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!////////
|
|
[ComVisible(true)]
|
|
public enum SpecialFolder {
|
|
//
|
|
// Represents the file system directory that serves as a common repository for
|
|
// application-specific data for the current, roaming user.
|
|
// A roaming user works on more than one computer on a network. A roaming user's
|
|
// profile is kept on a server on the network and is loaded onto a system when the
|
|
// user logs on.
|
|
//
|
|
ApplicationData = Win32Native.CSIDL_APPDATA,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for application-specific data that
|
|
// is used by all users.
|
|
//
|
|
CommonApplicationData = Win32Native.CSIDL_COMMON_APPDATA,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for application specific data that
|
|
// is used by the current, non-roaming user.
|
|
//
|
|
LocalApplicationData = Win32Native.CSIDL_LOCAL_APPDATA,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for Internet
|
|
// cookies.
|
|
//
|
|
Cookies = Win32Native.CSIDL_COOKIES,
|
|
Desktop = Win32Native.CSIDL_DESKTOP,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for the user's
|
|
// favorite items.
|
|
//
|
|
Favorites = Win32Native.CSIDL_FAVORITES,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for Internet
|
|
// history items.
|
|
//
|
|
History = Win32Native.CSIDL_HISTORY,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for temporary
|
|
// Internet files.
|
|
//
|
|
InternetCache = Win32Native.CSIDL_INTERNET_CACHE,
|
|
//
|
|
// Represents the file system directory that contains
|
|
// the user's program groups.
|
|
//
|
|
Programs = Win32Native.CSIDL_PROGRAMS,
|
|
MyComputer = Win32Native.CSIDL_DRIVES,
|
|
MyMusic = Win32Native.CSIDL_MYMUSIC,
|
|
MyPictures = Win32Native.CSIDL_MYPICTURES,
|
|
// "My Videos" folder
|
|
MyVideos = Win32Native.CSIDL_MYVIDEO,
|
|
//
|
|
// Represents the file system directory that contains the user's most recently used
|
|
// documents.
|
|
//
|
|
Recent = Win32Native.CSIDL_RECENT,
|
|
//
|
|
// Represents the file system directory that contains Send To menu items.
|
|
//
|
|
SendTo = Win32Native.CSIDL_SENDTO,
|
|
//
|
|
// Represents the file system directory that contains the Start menu items.
|
|
//
|
|
StartMenu = Win32Native.CSIDL_STARTMENU,
|
|
//
|
|
// Represents the file system directory that corresponds to the user's Startup program group. The system
|
|
// starts these programs whenever any user logs on to Windows NT, or
|
|
// starts Windows 95 or Windows 98.
|
|
//
|
|
Startup = Win32Native.CSIDL_STARTUP,
|
|
//
|
|
// System directory.
|
|
//
|
|
System = Win32Native.CSIDL_SYSTEM,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for document
|
|
// templates.
|
|
//
|
|
Templates = Win32Native.CSIDL_TEMPLATES,
|
|
//
|
|
// Represents the file system directory used to physically store file objects on the desktop.
|
|
// This should not be confused with the desktop folder itself, which is
|
|
// a virtual folder.
|
|
//
|
|
DesktopDirectory = Win32Native.CSIDL_DESKTOPDIRECTORY,
|
|
//
|
|
// Represents the file system directory that serves as a common repository for documents.
|
|
//
|
|
Personal = Win32Native.CSIDL_PERSONAL,
|
|
//
|
|
// "MyDocuments" is a better name than "Personal"
|
|
//
|
|
MyDocuments = Win32Native.CSIDL_PERSONAL,
|
|
//
|
|
// Represents the program files folder.
|
|
//
|
|
ProgramFiles = Win32Native.CSIDL_PROGRAM_FILES,
|
|
//
|
|
// Represents the folder for components that are shared across applications.
|
|
//
|
|
CommonProgramFiles = Win32Native.CSIDL_PROGRAM_FILES_COMMON,
|
|
#if !FEATURE_CORECLR
|
|
//
|
|
// <user name>\Start Menu\Programs\Administrative Tools
|
|
//
|
|
AdminTools = Win32Native.CSIDL_ADMINTOOLS,
|
|
//
|
|
// USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning
|
|
//
|
|
CDBurning = Win32Native.CSIDL_CDBURN_AREA,
|
|
//
|
|
// All Users\Start Menu\Programs\Administrative Tools
|
|
//
|
|
CommonAdminTools = Win32Native.CSIDL_COMMON_ADMINTOOLS,
|
|
//
|
|
// All Users\Documents
|
|
//
|
|
CommonDocuments = Win32Native.CSIDL_COMMON_DOCUMENTS,
|
|
//
|
|
// All Users\My Music
|
|
//
|
|
CommonMusic = Win32Native.CSIDL_COMMON_MUSIC,
|
|
//
|
|
// Links to All Users OEM specific apps
|
|
//
|
|
CommonOemLinks = Win32Native.CSIDL_COMMON_OEM_LINKS,
|
|
//
|
|
// All Users\My Pictures
|
|
//
|
|
CommonPictures = Win32Native.CSIDL_COMMON_PICTURES,
|
|
//
|
|
// All Users\Start Menu
|
|
//
|
|
CommonStartMenu = Win32Native.CSIDL_COMMON_STARTMENU,
|
|
//
|
|
// All Users\Start Menu\Programs
|
|
//
|
|
CommonPrograms = Win32Native.CSIDL_COMMON_PROGRAMS,
|
|
//
|
|
// All Users\Startup
|
|
//
|
|
CommonStartup = Win32Native.CSIDL_COMMON_STARTUP,
|
|
//
|
|
// All Users\Desktop
|
|
//
|
|
CommonDesktopDirectory = Win32Native.CSIDL_COMMON_DESKTOPDIRECTORY,
|
|
//
|
|
// All Users\Templates
|
|
//
|
|
CommonTemplates = Win32Native.CSIDL_COMMON_TEMPLATES,
|
|
//
|
|
// All Users\My Video
|
|
//
|
|
CommonVideos = Win32Native.CSIDL_COMMON_VIDEO,
|
|
//
|
|
// windows\fonts
|
|
//
|
|
Fonts = Win32Native.CSIDL_FONTS,
|
|
//
|
|
// %APPDATA%\Microsoft\Windows\Network Shortcuts
|
|
//
|
|
NetworkShortcuts = Win32Native.CSIDL_NETHOOD,
|
|
//
|
|
// %APPDATA%\Microsoft\Windows\Printer Shortcuts
|
|
//
|
|
PrinterShortcuts = Win32Native.CSIDL_PRINTHOOD,
|
|
//
|
|
// USERPROFILE
|
|
//
|
|
UserProfile = Win32Native.CSIDL_PROFILE,
|
|
//
|
|
// x86 Program Files\Common on RISC
|
|
//
|
|
CommonProgramFilesX86 = Win32Native.CSIDL_PROGRAM_FILES_COMMONX86,
|
|
//
|
|
// x86 C:\Program Files on RISC
|
|
//
|
|
ProgramFilesX86 = Win32Native.CSIDL_PROGRAM_FILESX86,
|
|
//
|
|
// Resource Directory
|
|
//
|
|
Resources = Win32Native.CSIDL_RESOURCES,
|
|
//
|
|
// Localized Resource Directory
|
|
//
|
|
LocalizedResources = Win32Native.CSIDL_RESOURCES_LOCALIZED,
|
|
//
|
|
// %windir%\System32 or %windir%\syswow64
|
|
//
|
|
SystemX86 = Win32Native.CSIDL_SYSTEMX86,
|
|
//
|
|
// GetWindowsDirectory()
|
|
//
|
|
Windows = Win32Native.CSIDL_WINDOWS,
|
|
#endif // !FEATURE_CORECLR
|
|
}
|
|
|
|
public static int CurrentManagedThreadId
|
|
{
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
get
|
|
{
|
|
return Thread.CurrentThread.ManagedThreadId;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|