64ac736ec5
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
1059 lines
31 KiB
C#
1059 lines
31 KiB
C#
//------------------------------------------------------------------------------
|
|
//
|
|
// System.Environment.cs
|
|
//
|
|
// Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
|
|
//
|
|
// Author: Jim Richardson, develop@wtfo-guru.com
|
|
// Dan Lewis (dihlewis@yahoo.co.uk)
|
|
// Created: Saturday, August 11, 2001
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System.IO;
|
|
using System.Collections;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
namespace System {
|
|
|
|
[ComVisible (true)]
|
|
public static partial class Environment {
|
|
|
|
/*
|
|
* This is the version of the corlib-runtime interface.
|
|
* It is defined in configure.ac.
|
|
*/
|
|
#pragma warning disable 169
|
|
private const string mono_corlib_version = Consts.MonoCorlibVersion;
|
|
#pragma warning restore 169
|
|
|
|
[ComVisible (true)]
|
|
public enum SpecialFolder
|
|
{
|
|
MyDocuments = 0x05,
|
|
Desktop = 0x00,
|
|
MyComputer = 0x11,
|
|
Programs = 0x02,
|
|
Personal = 0x05,
|
|
Favorites = 0x06,
|
|
Startup = 0x07,
|
|
Recent = 0x08,
|
|
SendTo = 0x09,
|
|
StartMenu = 0x0b,
|
|
MyMusic = 0x0d,
|
|
DesktopDirectory = 0x10,
|
|
Templates = 0x15,
|
|
ApplicationData = 0x1a,
|
|
LocalApplicationData = 0x1c,
|
|
InternetCache = 0x20,
|
|
Cookies = 0x21,
|
|
History = 0x22,
|
|
CommonApplicationData = 0x23,
|
|
System = 0x25,
|
|
ProgramFiles = 0x26,
|
|
MyPictures = 0x27,
|
|
CommonProgramFiles = 0x2b,
|
|
MyVideos = 0x0e,
|
|
NetworkShortcuts = 0x13,
|
|
Fonts = 0x14,
|
|
CommonStartMenu = 0x16,
|
|
CommonPrograms = 0x17,
|
|
CommonStartup = 0x18,
|
|
CommonDesktopDirectory = 0x19,
|
|
PrinterShortcuts = 0x1b,
|
|
Windows = 0x24,
|
|
UserProfile = 0x28,
|
|
SystemX86 = 0x29,
|
|
ProgramFilesX86 = 0x2a,
|
|
CommonProgramFilesX86 = 0x2c,
|
|
CommonTemplates = 0x2d,
|
|
CommonDocuments = 0x2e,
|
|
CommonAdminTools = 0x2f,
|
|
AdminTools = 0x30,
|
|
CommonMusic = 0x35,
|
|
CommonPictures = 0x36,
|
|
CommonVideos = 0x37,
|
|
Resources = 0x38,
|
|
LocalizedResources = 0x39,
|
|
CommonOemLinks = 0x3a,
|
|
CDBurning = 0x3b,
|
|
}
|
|
|
|
public
|
|
enum SpecialFolderOption {
|
|
None = 0,
|
|
DoNotVerify = 0x4000,
|
|
Create = 0x8000
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the command line for this process
|
|
/// </summary>
|
|
public static string CommandLine {
|
|
// note: security demand inherited from calling GetCommandLineArgs
|
|
get {
|
|
StringBuilder sb = new StringBuilder ();
|
|
foreach (string str in GetCommandLineArgs ()) {
|
|
bool escape = false;
|
|
string quote = "";
|
|
string s = str;
|
|
for (int i = 0; i < s.Length; i++) {
|
|
if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
|
|
quote = "\"";
|
|
} else if (s [i] == '"') {
|
|
escape = true;
|
|
}
|
|
}
|
|
if (escape && quote.Length != 0) {
|
|
s = s.Replace ("\"", "\\\"");
|
|
}
|
|
sb.AppendFormat ("{0}{1}{0} ", quote, s);
|
|
}
|
|
if (sb.Length > 0)
|
|
sb.Length--;
|
|
return sb.ToString ();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the current directory. Actually this is supposed to get
|
|
/// and/or set the process start directory acording to the documentation
|
|
/// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
|
|
/// </summary>
|
|
public static string CurrentDirectory
|
|
{
|
|
get {
|
|
return Directory.InsecureGetCurrentDirectory ();
|
|
}
|
|
set {
|
|
Directory.InsecureSetCurrentDirectory (value);
|
|
}
|
|
}
|
|
|
|
public static int CurrentManagedThreadId {
|
|
get {
|
|
return Thread.CurrentThread.ManagedThreadId;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the exit code of this process
|
|
/// </summary>
|
|
public extern static int ExitCode
|
|
{
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
get;
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
set;
|
|
}
|
|
|
|
static public extern bool HasShutdownStarted
|
|
{
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the name of the local computer
|
|
/// </summary>
|
|
public extern static string MachineName {
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
[EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
|
|
[SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
|
|
get;
|
|
}
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
extern static string GetNewLine ();
|
|
|
|
static string nl;
|
|
/// <summary>
|
|
/// Gets the standard new line value
|
|
/// </summary>
|
|
public static string NewLine {
|
|
get {
|
|
if (nl != null)
|
|
return nl;
|
|
|
|
nl = GetNewLine ();
|
|
return nl;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Support methods and fields for OSVersion property
|
|
//
|
|
static OperatingSystem os;
|
|
|
|
static internal PlatformID Platform {
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal static extern string GetOSVersionString ();
|
|
|
|
/// <summary>
|
|
/// Gets the current OS version information
|
|
/// </summary>
|
|
public static OperatingSystem OSVersion {
|
|
get {
|
|
if (os == null) {
|
|
Version v = CreateVersionFromString (GetOSVersionString ());
|
|
PlatformID p = Platform;
|
|
if (p == PlatformID.MacOSX)
|
|
p = PlatformID.Unix;
|
|
os = new OperatingSystem (p, v);
|
|
}
|
|
return os;
|
|
}
|
|
}
|
|
|
|
|
|
// a very gentle way to construct a Version object which takes
|
|
// the first four numbers in a string as the version
|
|
internal static Version CreateVersionFromString (string info)
|
|
{
|
|
int major = 0;
|
|
int minor = 0;
|
|
int build = 0;
|
|
int revision = 0;
|
|
int state = 1;
|
|
int number = -1; // string may not begin with a digit
|
|
|
|
if (info == null)
|
|
return new Version (0, 0, 0, 0);
|
|
|
|
for (int i=0; i < info.Length; i++) {
|
|
char c = info [i];
|
|
if (Char.IsDigit (c)) {
|
|
if (number < 0) {
|
|
number = (c - '0');
|
|
}
|
|
else {
|
|
number = (number * 10) + (c - '0');
|
|
}
|
|
}
|
|
else if (number >= 0) {
|
|
// assign
|
|
switch (state) {
|
|
case 1:
|
|
major = number;
|
|
break;
|
|
case 2:
|
|
minor = number;
|
|
break;
|
|
case 3:
|
|
build = number;
|
|
break;
|
|
case 4:
|
|
revision = number;
|
|
break;
|
|
}
|
|
number = -1;
|
|
state ++;
|
|
}
|
|
// ignore end of string
|
|
if (state == 5)
|
|
break;
|
|
}
|
|
|
|
// Last number
|
|
if (number >= 0) {
|
|
switch (state) {
|
|
case 1:
|
|
major = number;
|
|
break;
|
|
case 2:
|
|
minor = number;
|
|
break;
|
|
case 3:
|
|
build = number;
|
|
break;
|
|
case 4:
|
|
revision = number;
|
|
break;
|
|
}
|
|
}
|
|
return new Version (major, minor, build, revision);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get StackTrace
|
|
/// </summary>
|
|
public static string StackTrace {
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
|
|
get {
|
|
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
|
|
return trace.ToString ();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a fully qualified path to the system directory
|
|
/// </summary>
|
|
public static string SystemDirectory {
|
|
get {
|
|
return GetFolderPath (SpecialFolder.System);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the number of milliseconds that have elapsed since the system was booted
|
|
/// </summary>
|
|
public extern static int TickCount {
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get UserDomainName
|
|
/// </summary>
|
|
public static string UserDomainName {
|
|
// FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
|
|
[EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
|
|
get {
|
|
return MachineName;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a flag indicating whether the process is in interactive mode
|
|
/// </summary>
|
|
[MonoTODO ("Currently always returns false, regardless of interactive state")]
|
|
public static bool UserInteractive {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the user name of current process is running under
|
|
/// </summary>
|
|
public extern static string UserName {
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
[EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
|
|
get;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the version of the common language runtime
|
|
/// </summary>
|
|
public static Version Version {
|
|
get {
|
|
return new Version (Consts.EnvironmentVersion);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the amount of physical memory mapped to process
|
|
/// </summary>
|
|
[MonoTODO ("Currently always returns zero")]
|
|
public static long WorkingSet {
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
|
|
get { return 0; }
|
|
}
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
[SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
|
|
public extern static void Exit (int exitCode);
|
|
|
|
internal static void _Exit (int exitCode)
|
|
{
|
|
Exit (exitCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Substitute environment variables in the argument "name"
|
|
/// </summary>
|
|
public static string ExpandEnvironmentVariables (string name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException ("name");
|
|
|
|
int off1 = name.IndexOf ('%');
|
|
if (off1 == -1)
|
|
return name;
|
|
|
|
int len = name.Length;
|
|
int off2 = 0;
|
|
if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
|
|
return name;
|
|
|
|
StringBuilder result = new StringBuilder ();
|
|
result.Append (name, 0, off1);
|
|
Hashtable tbl = null;
|
|
do {
|
|
string var = name.Substring (off1 + 1, off2 - off1 - 1);
|
|
string value = GetEnvironmentVariable (var);
|
|
if (value == null && Environment.IsRunningOnWindows) {
|
|
// On windows, env. vars. are case insensitive
|
|
if (tbl == null)
|
|
tbl = GetEnvironmentVariablesNoCase ();
|
|
|
|
value = tbl [var] as string;
|
|
}
|
|
|
|
// If value not found, add %FOO to stream,
|
|
// and use the closing % for the next iteration.
|
|
// If value found, expand it in place of %FOO%
|
|
int realOldOff2 = off2;
|
|
if (value == null) {
|
|
result.Append ('%');
|
|
result.Append (var);
|
|
off2--;
|
|
} else {
|
|
result.Append (value);
|
|
}
|
|
int oldOff2 = off2;
|
|
off1 = name.IndexOf ('%', off2 + 1);
|
|
// If no % found for off1, don't look for one for off2
|
|
off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
|
|
// textLen is the length of text between the closing % of current iteration
|
|
// and the starting % of the next iteration if any. This text is added to output
|
|
int textLen;
|
|
// If no new % found, use all the remaining text
|
|
if (off1 == -1 || off2 == -1)
|
|
textLen = len - oldOff2 - 1;
|
|
// If value found in current iteration, use text after current closing % and next %
|
|
else if(value != null)
|
|
textLen = off1 - oldOff2 - 1;
|
|
// If value not found in current iteration, but a % was found for next iteration,
|
|
// use text from current closing % to the next %.
|
|
else
|
|
textLen = off1 - realOldOff2;
|
|
if(off1 >= oldOff2 || off1 == -1)
|
|
result.Append (name, oldOff2+1, textLen);
|
|
} while (off2 > -1 && off2 < len);
|
|
|
|
return result.ToString ();
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return an array of the command line arguments of the current process
|
|
/// </summary>
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
[EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
|
|
public extern static string[] GetCommandLineArgs ();
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static string internalGetEnvironmentVariable_native (IntPtr variable);
|
|
|
|
internal static string internalGetEnvironmentVariable (string variable) {
|
|
if (variable == null)
|
|
return null;
|
|
using (var h = Mono.RuntimeMarshal.MarshalString (variable)) {
|
|
return internalGetEnvironmentVariable_native (h.Value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return a string containing the value of the environment
|
|
/// variable identifed by parameter "variable"
|
|
/// </summary>
|
|
public static string GetEnvironmentVariable (string variable)
|
|
{
|
|
#if MONO_FEATURE_CAS
|
|
if (SecurityManager.SecurityEnabled) {
|
|
new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
|
|
}
|
|
#endif
|
|
return internalGetEnvironmentVariable (variable);
|
|
}
|
|
|
|
static Hashtable GetEnvironmentVariablesNoCase ()
|
|
{
|
|
Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
|
|
CaseInsensitiveComparer.Default);
|
|
|
|
foreach (string name in GetEnvironmentVariableNames ()) {
|
|
vars [name] = internalGetEnvironmentVariable (name);
|
|
}
|
|
|
|
return vars;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return a set of all environment variables and their values
|
|
/// </summary>
|
|
#if !MOBILE
|
|
public static IDictionary GetEnvironmentVariables ()
|
|
{
|
|
StringBuilder sb = null;
|
|
if (SecurityManager.SecurityEnabled) {
|
|
// we must have access to each variable to get the lot
|
|
sb = new StringBuilder ();
|
|
// but (performance-wise) we do not want a stack-walk
|
|
// for each of them so we concatenate them
|
|
}
|
|
|
|
Hashtable vars = new Hashtable ();
|
|
foreach (string name in GetEnvironmentVariableNames ()) {
|
|
vars [name] = internalGetEnvironmentVariable (name);
|
|
if (sb != null) {
|
|
sb.Append (name);
|
|
sb.Append (";");
|
|
}
|
|
}
|
|
|
|
if (sb != null) {
|
|
new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
|
|
}
|
|
return vars;
|
|
}
|
|
#else
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
|
|
public static IDictionary GetEnvironmentVariables ()
|
|
{
|
|
Hashtable vars = new Hashtable ();
|
|
foreach (string name in GetEnvironmentVariableNames ()) {
|
|
vars [name] = internalGetEnvironmentVariable (name);
|
|
}
|
|
return vars;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Returns the fully qualified path of the
|
|
/// folder specified by the "folder" parameter
|
|
/// </summary>
|
|
public static string GetFolderPath (SpecialFolder folder)
|
|
{
|
|
return GetFolderPath (folder, SpecialFolderOption.None);
|
|
}
|
|
|
|
#if !MONOTOUCH
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
private extern static string GetWindowsFolderPath (int folder);
|
|
|
|
public
|
|
static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
|
|
{
|
|
SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
|
|
|
|
string dir = null;
|
|
|
|
if (Environment.IsRunningOnWindows)
|
|
dir = GetWindowsFolderPath ((int) folder);
|
|
else
|
|
dir = UnixGetFolderPath (folder, option);
|
|
|
|
#if MONO_FEATURE_CAS
|
|
if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
|
|
new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
|
|
}
|
|
#endif
|
|
return dir;
|
|
}
|
|
|
|
private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
|
|
{
|
|
string env_path = internalGetEnvironmentVariable (key);
|
|
if (env_path != null && env_path != String.Empty) {
|
|
return env_path;
|
|
}
|
|
|
|
string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
|
|
|
|
if (!File.Exists (user_dirs_path)) {
|
|
return Path.Combine (home_dir, fallback);
|
|
}
|
|
|
|
try {
|
|
using(StreamReader reader = new StreamReader (user_dirs_path)) {
|
|
string line;
|
|
while ((line = reader.ReadLine ()) != null) {
|
|
line = line.Trim ();
|
|
int delim_index = line.IndexOf ('=');
|
|
if(delim_index > 8 && line.Substring (0, delim_index) == key) {
|
|
string path = line.Substring (delim_index + 1).Trim ('"');
|
|
bool relative = false;
|
|
|
|
if (path.StartsWithOrdinalUnchecked ("$HOME/")) {
|
|
relative = true;
|
|
path = path.Substring (6);
|
|
} else if (!path.StartsWithOrdinalUnchecked ("/")) {
|
|
relative = true;
|
|
}
|
|
|
|
return relative ? Path.Combine (home_dir, path) : path;
|
|
}
|
|
}
|
|
}
|
|
} catch (FileNotFoundException) {
|
|
}
|
|
|
|
return Path.Combine (home_dir, fallback);
|
|
}
|
|
|
|
|
|
// the security runtime (and maybe other parts of corlib) needs the
|
|
// information to initialize themselves before permissions can be checked
|
|
internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
|
|
{
|
|
string home = internalGetHome ();
|
|
|
|
// http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
|
|
|
|
// note: skip security check for environment variables
|
|
string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
|
|
if ((data == null) || (data == String.Empty)) {
|
|
data = Path.Combine (home, ".local");
|
|
data = Path.Combine (data, "share");
|
|
}
|
|
|
|
// note: skip security check for environment variables
|
|
string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
|
|
if ((config == null) || (config == String.Empty)) {
|
|
config = Path.Combine (home, ".config");
|
|
}
|
|
|
|
switch (folder) {
|
|
// MyComputer is a virtual directory
|
|
case SpecialFolder.MyComputer:
|
|
return String.Empty;
|
|
|
|
// personal == ~
|
|
case SpecialFolder.Personal:
|
|
return home;
|
|
|
|
// use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
|
|
case SpecialFolder.ApplicationData:
|
|
return config;
|
|
|
|
//use FDO's DATA_HOME. This is *NOT* synced
|
|
case SpecialFolder.LocalApplicationData:
|
|
return data;
|
|
|
|
case SpecialFolder.Desktop:
|
|
case SpecialFolder.DesktopDirectory:
|
|
return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
|
|
|
|
case SpecialFolder.MyMusic:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return Path.Combine (home, "Music");
|
|
else
|
|
return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
|
|
|
|
case SpecialFolder.MyPictures:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return Path.Combine (home, "Pictures");
|
|
else
|
|
return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
|
|
|
|
case SpecialFolder.Templates:
|
|
return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
|
|
case SpecialFolder.MyVideos:
|
|
return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
|
|
case SpecialFolder.CommonTemplates:
|
|
return "/usr/share/templates";
|
|
case SpecialFolder.Fonts:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return Path.Combine (home, "Library", "Fonts");
|
|
|
|
return Path.Combine (home, ".fonts");
|
|
// these simply dont exist on Linux
|
|
// The spec says if a folder doesnt exist, we
|
|
// should return ""
|
|
case SpecialFolder.Favorites:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return Path.Combine (home, "Library", "Favorites");
|
|
else
|
|
return String.Empty;
|
|
|
|
case SpecialFolder.ProgramFiles:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return "/Applications";
|
|
else
|
|
return String.Empty;
|
|
|
|
case SpecialFolder.InternetCache:
|
|
if (Platform == PlatformID.MacOSX)
|
|
return Path.Combine (home, "Library", "Caches");
|
|
else
|
|
return String.Empty;
|
|
|
|
// #2873
|
|
case SpecialFolder.UserProfile:
|
|
return home;
|
|
|
|
case SpecialFolder.Programs:
|
|
case SpecialFolder.SendTo:
|
|
case SpecialFolder.StartMenu:
|
|
case SpecialFolder.Startup:
|
|
case SpecialFolder.Cookies:
|
|
case SpecialFolder.History:
|
|
case SpecialFolder.Recent:
|
|
case SpecialFolder.CommonProgramFiles:
|
|
case SpecialFolder.System:
|
|
case SpecialFolder.NetworkShortcuts:
|
|
case SpecialFolder.CommonStartMenu:
|
|
case SpecialFolder.CommonPrograms:
|
|
case SpecialFolder.CommonStartup:
|
|
case SpecialFolder.CommonDesktopDirectory:
|
|
case SpecialFolder.PrinterShortcuts:
|
|
case SpecialFolder.Windows:
|
|
case SpecialFolder.SystemX86:
|
|
case SpecialFolder.ProgramFilesX86:
|
|
case SpecialFolder.CommonProgramFilesX86:
|
|
case SpecialFolder.CommonDocuments:
|
|
case SpecialFolder.CommonAdminTools:
|
|
case SpecialFolder.AdminTools:
|
|
case SpecialFolder.CommonMusic:
|
|
case SpecialFolder.CommonPictures:
|
|
case SpecialFolder.CommonVideos:
|
|
case SpecialFolder.Resources:
|
|
case SpecialFolder.LocalizedResources:
|
|
case SpecialFolder.CommonOemLinks:
|
|
case SpecialFolder.CDBurning:
|
|
return String.Empty;
|
|
// This is where data common to all users goes
|
|
case SpecialFolder.CommonApplicationData:
|
|
return "/usr/share";
|
|
default:
|
|
throw new ArgumentException ("Invalid SpecialFolder");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
|
|
public static string[] GetLogicalDrives ()
|
|
{
|
|
return GetLogicalDrivesInternal ();
|
|
}
|
|
|
|
#if !MOBILE
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
private static extern void internalBroadcastSettingChange ();
|
|
|
|
public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
|
|
{
|
|
switch (target) {
|
|
case EnvironmentVariableTarget.Process:
|
|
return GetEnvironmentVariable (variable);
|
|
case EnvironmentVariableTarget.Machine:
|
|
new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
|
|
if (!IsRunningOnWindows)
|
|
return null;
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
|
|
object regvalue = env.GetValue (variable);
|
|
return (regvalue == null) ? null : regvalue.ToString ();
|
|
}
|
|
case EnvironmentVariableTarget.User:
|
|
new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
|
|
if (!IsRunningOnWindows)
|
|
return null;
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
|
|
object regvalue = env.GetValue (variable);
|
|
return (regvalue == null) ? null : regvalue.ToString ();
|
|
}
|
|
default:
|
|
throw new ArgumentException ("target");
|
|
}
|
|
}
|
|
|
|
public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
|
|
{
|
|
IDictionary variables = (IDictionary)new Hashtable ();
|
|
switch (target) {
|
|
case EnvironmentVariableTarget.Process:
|
|
variables = GetEnvironmentVariables ();
|
|
break;
|
|
case EnvironmentVariableTarget.Machine:
|
|
new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
|
|
if (IsRunningOnWindows) {
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
|
|
string[] value_names = env.GetValueNames ();
|
|
foreach (string value_name in value_names)
|
|
variables.Add (value_name, env.GetValue (value_name));
|
|
}
|
|
}
|
|
break;
|
|
case EnvironmentVariableTarget.User:
|
|
new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
|
|
if (IsRunningOnWindows) {
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
|
|
string[] value_names = env.GetValueNames ();
|
|
foreach (string value_name in value_names)
|
|
variables.Add (value_name, env.GetValue (value_name));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
throw new ArgumentException ("target");
|
|
}
|
|
return variables;
|
|
}
|
|
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
|
|
public static void SetEnvironmentVariable (string variable, string value)
|
|
{
|
|
SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
|
|
}
|
|
|
|
[EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
|
|
public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
|
|
{
|
|
if (variable == null)
|
|
throw new ArgumentNullException ("variable");
|
|
if (variable == String.Empty)
|
|
throw new ArgumentException ("String cannot be of zero length.", "variable");
|
|
if (variable.IndexOf ('=') != -1)
|
|
throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
|
|
if (variable[0] == '\0')
|
|
throw new ArgumentException ("The first char in the string is the null character.", "variable");
|
|
|
|
switch (target) {
|
|
case EnvironmentVariableTarget.Process:
|
|
InternalSetEnvironmentVariable (variable, value);
|
|
break;
|
|
case EnvironmentVariableTarget.Machine:
|
|
if (!IsRunningOnWindows)
|
|
return;
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
|
|
if (String.IsNullOrEmpty (value))
|
|
env.DeleteValue (variable, false);
|
|
else
|
|
env.SetValue (variable, value);
|
|
internalBroadcastSettingChange ();
|
|
}
|
|
break;
|
|
case EnvironmentVariableTarget.User:
|
|
if (!IsRunningOnWindows)
|
|
return;
|
|
using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
|
|
if (String.IsNullOrEmpty (value))
|
|
env.DeleteValue (variable, false);
|
|
else
|
|
env.SetValue (variable, value);
|
|
internalBroadcastSettingChange ();
|
|
}
|
|
break;
|
|
default:
|
|
throw new ArgumentException ("target");
|
|
}
|
|
}
|
|
#else
|
|
public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
|
|
{
|
|
if (target == EnvironmentVariableTarget.Process)
|
|
return GetEnvironmentVariable (variable);
|
|
|
|
return null;
|
|
}
|
|
|
|
public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
|
|
{
|
|
if (target == EnvironmentVariableTarget.Process)
|
|
return GetEnvironmentVariables ();
|
|
|
|
return (IDictionary)new Hashtable ();
|
|
}
|
|
|
|
public static void SetEnvironmentVariable (string variable, string value)
|
|
{
|
|
if (variable == null)
|
|
throw new ArgumentNullException ("variable");
|
|
if (variable == String.Empty)
|
|
throw new ArgumentException ("String cannot be of zero length.", "variable");
|
|
if (variable.IndexOf ('=') != -1)
|
|
throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
|
|
if (variable[0] == '\0')
|
|
throw new ArgumentException ("The first char in the string is the null character.", "variable");
|
|
|
|
InternalSetEnvironmentVariable (variable, value);
|
|
}
|
|
|
|
public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
|
|
{
|
|
if (target == EnvironmentVariableTarget.Process)
|
|
SetEnvironmentVariable (variable, value);
|
|
|
|
// other targets ignored
|
|
}
|
|
#endif
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal unsafe static extern void InternalSetEnvironmentVariable (char *variable, int variable_length,
|
|
char *value, int value_length);
|
|
|
|
internal unsafe static void InternalSetEnvironmentVariable (string variable, string value)
|
|
{
|
|
fixed (char *fixed_variable = variable)
|
|
fixed (char *fixed_value = value)
|
|
InternalSetEnvironmentVariable (fixed_variable, variable?.Length ?? 0,
|
|
fixed_value, value?.Length ?? 0);
|
|
}
|
|
|
|
[SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
|
|
public static void FailFast (string message)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
internal static void FailFast (String message, uint exitCode)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[SecurityCritical]
|
|
public static void FailFast (string message, Exception exception)
|
|
{
|
|
#pragma warning disable 618
|
|
throw new ExecutionEngineException (message, exception);
|
|
#pragma warning restore
|
|
}
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
extern static bool GetIs64BitOperatingSystem ();
|
|
|
|
public static bool Is64BitOperatingSystem {
|
|
get { return GetIs64BitOperatingSystem (); }
|
|
}
|
|
|
|
public static int SystemPageSize {
|
|
get { return GetPageSize (); }
|
|
}
|
|
|
|
public
|
|
static bool Is64BitProcess {
|
|
get { return IntPtr.Size == 8; }
|
|
}
|
|
|
|
public static extern int ProcessorCount {
|
|
[EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
get;
|
|
}
|
|
|
|
// private methods
|
|
#if (MONOTOUCH || MONODROID || XAMMAC)
|
|
internal const bool IsRunningOnWindows = false;
|
|
#else
|
|
internal static bool IsRunningOnWindows {
|
|
get { return ((int) Platform < 4); }
|
|
}
|
|
#endif
|
|
|
|
#if !MOBILE
|
|
//
|
|
// Used by gacutil.exe
|
|
//
|
|
#pragma warning disable 169
|
|
private static string GacPath {
|
|
get {
|
|
if (Environment.IsRunningOnWindows) {
|
|
/* On windows, we don't know the path where mscorlib.dll will be installed */
|
|
string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
|
|
return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
|
|
}
|
|
|
|
return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
|
|
}
|
|
}
|
|
#pragma warning restore 169
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static string internalGetGacPath ();
|
|
#endif
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static string [] GetLogicalDrivesInternal ();
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
private extern static string [] GetEnvironmentVariableNames ();
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static string GetMachineConfigPath ();
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static string internalGetHome ();
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
internal extern static int GetPageSize ();
|
|
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
extern private static string get_bundled_machine_config ();
|
|
|
|
internal static string GetBundledMachineConfig ()
|
|
{
|
|
return get_bundled_machine_config ();
|
|
}
|
|
|
|
static internal bool IsUnix {
|
|
get {
|
|
int platform = (int) Environment.Platform;
|
|
|
|
return (platform == 4 || platform == 128 || platform == 6);
|
|
}
|
|
}
|
|
static internal bool IsMacOS {
|
|
get {
|
|
return Environment.Platform == PlatformID.MacOSX;
|
|
}
|
|
}
|
|
|
|
internal static bool IsCLRHosted {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal static void TriggerCodeContractFailure(ContractFailureKind failureKind, String message, String condition, String exceptionAsString)
|
|
{
|
|
|
|
}
|
|
|
|
// Copied from referencesource Environment
|
|
internal static String GetStackTrace(Exception e, bool needFileInfo)
|
|
{
|
|
System.Diagnostics.StackTrace st;
|
|
if (e == null)
|
|
st = new System.Diagnostics.StackTrace(needFileInfo);
|
|
else
|
|
st = new System.Diagnostics.StackTrace(e, needFileInfo);
|
|
|
|
// Do not include a trailing newline for backwards compatibility
|
|
return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
|
|
}
|
|
|
|
// Copied from referencesource Environment
|
|
internal static bool IsWinRTSupported
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|