summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Toub <stoub@microsoft.com>2019-01-30 16:22:27 -0500
committerGitHub <noreply@github.com>2019-01-30 16:22:27 -0500
commit91e1ffccc38fc87f6f496eb056396a1b775f08af (patch)
tree827d79048645d76128154f67d2e571766ae39893
parent6a43dd765ea6341310fde3f83bb41ff88d94b435 (diff)
downloadcoreclr-91e1ffccc38fc87f6f496eb056396a1b775f08af.tar.gz
coreclr-91e1ffccc38fc87f6f496eb056396a1b775f08af.tar.bz2
coreclr-91e1ffccc38fc87f6f496eb056396a1b775f08af.zip
Switch CoreLib over to using shared Environment from corefx (#22106)
This requires merging/adapting the implementation with EnvironmentAugments (which goes away completely), the shared files, what corert has, etc.
-rw-r--r--src/System.Private.CoreLib/Resources/Strings.resx9
-rw-r--r--src/System.Private.CoreLib/System.Private.CoreLib.csproj5
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs4
-rw-r--r--src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs23
-rw-r--r--src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems48
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs21
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.Unix.cs20
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs168
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.Win32.cs140
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.Windows.cs26
-rw-r--r--src/System.Private.CoreLib/shared/System/Environment.cs157
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs36
-rw-r--r--src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs23
-rw-r--r--src/System.Private.CoreLib/src/System/CLRConfig.cs3
-rw-r--r--src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs158
-rw-r--r--src/System.Private.CoreLib/src/System/Environment.Windows.cs34
-rw-r--r--src/System.Private.CoreLib/src/System/Environment.cs708
-rw-r--r--src/System.Private.CoreLib/src/System/Exception.cs19
18 files changed, 692 insertions, 910 deletions
diff --git a/src/System.Private.CoreLib/Resources/Strings.resx b/src/System.Private.CoreLib/Resources/Strings.resx
index 98a3d9ebdb..6800d8ed33 100644
--- a/src/System.Private.CoreLib/Resources/Strings.resx
+++ b/src/System.Private.CoreLib/Resources/Strings.resx
@@ -496,6 +496,9 @@
<data name="Arg_MustBeDouble" xml:space="preserve">
<value>Object must be of type Double.</value>
</data>
+ <data name="Arg_MustBeDriveLetterOrRootDir" xml:space="preserve">
+ <value>Drive name must be a root directory (i.e. 'C:\') or a drive letter ('C').</value>
+ </data>
<data name="Arg_MustBeEnum" xml:space="preserve">
<value>Type provided must be an Enum.</value>
</data>
@@ -2464,6 +2467,9 @@
<data name="InvalidOperation_CollectionCorrupted" xml:space="preserve">
<value>A prior operation on this collection was interrupted by an exception. Collection's state is no longer trusted.</value>
</data>
+ <data name="InvalidOperation_ComputerName" xml:space="preserve">
+ <value>Computer name could not be obtained.</value>
+ </data>
<data name="InvalidOperation_ConcurrentOperationsNotSupported" xml:space="preserve">
<value>Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.</value>
</data>
@@ -3190,6 +3196,9 @@
<data name="PreconditionFailed_Cnd" xml:space="preserve">
<value>Precondition failed: {0}</value>
</data>
+ <data name="PersistedFiles_NoHomeDirectory" xml:space="preserve">
+ <value>The home directory of the current user could not be determined.</value>
+ </data>
<data name="Rank_MultiDimNotSupported" xml:space="preserve">
<value>Only single dimension arrays are supported here.</value>
</data>
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index db83064834..d8bde72ee4 100644
--- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -160,7 +160,7 @@
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\SymbolStore\SymAddressKind.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\SymbolStore\Token.cs" />
<Compile Include="$(BclSourcesRoot)\System\Enum.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Environment.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Environment.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Exception.cs" />
<Compile Include="$(BclSourcesRoot)\System\GC.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.cs" />
@@ -371,7 +371,6 @@
<Compile Include="$(BclSourcesRoot)\System\ApplicationModel.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Environment.Windows.cs" />
</ItemGroup>
<ItemGroup>
<!--
@@ -444,4 +443,4 @@
</ItemGroup>
<Import Project="ILLink.targets" />
<Import Project="GenerateCompilerResponseFile.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs
index ba942ba6ff..ce3db6f2b4 100644
--- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs
@@ -8,7 +8,7 @@ internal partial class Interop
{
internal partial class Kernel32
{
- [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern uint ExpandEnvironmentStringsW(string lpSrc, ref char lpDst, uint nSize);
+ [DllImport(Libraries.Kernel32, EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, SetLastError = true)]
+ internal static extern uint ExpandEnvironmentStrings(string lpSrc, ref char lpDst, uint nSize);
}
}
diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs
new file mode 100644
index 0000000000..13adefc216
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ internal static unsafe int GetEnvironmentVariable(string lpName, Span<char> buffer)
+ {
+ fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer))
+ {
+ return GetEnvironmentVariable(lpName, bufferPtr, buffer.Length);
+ }
+ }
+
+ [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentVariableW", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern unsafe int GetEnvironmentVariable(string lpName, char* lpBuffer, int nSize);
+ }
+}
diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
index a10e0c247b..e0a7aa594c 100644
--- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems
@@ -211,6 +211,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\DuplicateWaitObjectException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Empty.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\EntryPointNotFoundException.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.SpecialFolder.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.SpecialFolderOption.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\EnvironmentVariableTarget.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\EventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\EventHandler.cs" />
@@ -370,12 +373,15 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Object.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ObjectDisposedException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ObsoleteAttribute.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\OperatingSystem.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\OperationCanceledException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\OutOfMemoryException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\OverflowException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ParamArrayAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ParamsArray.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ParseNumbers.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\PlatformID.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\PlatformNotSupportedException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Progress.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Random.cs" />
@@ -915,32 +921,40 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Vector_Operations.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows)">
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Advapi32\Interop.LookupAccountNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\BCrypt\Interop.BCryptGenRandom.GetRandomBytes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\BCrypt\Interop.NTSTATUS.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Interop.BOOL.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Interop.BOOLEAN.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Interop.Libraries.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CancelIoEx.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ExpandEnvironmentStrings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileAttributes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FILE_INFO_BY_HANDLE_CLASS.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FileTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindClose.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FindFirstFileEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FlushFileBuffers.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeEnvironmentStrings.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetComputerName.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetCPInfo.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetEnvironmentStrings.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetCurrentProcess_IntPtr.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetCurrentDirectory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFileAttributesEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFileInformationByHandleEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFileType_SafeHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFullPathNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetLogicalDrives.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemDirectoryW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetVersionExW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.IsWow64Process_IntPtr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LockFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MAX_PATH.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MEMORY_BASIC_INFORMATION.cs" />
@@ -952,8 +966,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SecurityOptions.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetCurrentDirectory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEndOfFile.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEnvironmentVariable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SYSTEM_INFO.cs" />
@@ -971,9 +985,12 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Secur32\Interop.GetUserNameExW.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Shell32\Interop.SHGetKnownFolderPath.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Windows.cs" />
@@ -987,12 +1004,14 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamCompletionSource.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathHelper.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DisableMediaInsertionPrompt.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.Windows.cs" Condition="'$(TargetsCoreRT)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SafeBSTRHandle.cs" />
@@ -1030,6 +1049,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.LoadString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.SendMessageTimeout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" />
</ItemGroup>
@@ -1043,10 +1063,15 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CloseHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Constants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Interop.Errors.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetEnvironmentVariable.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetEnvironmentStrings.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeEnvironmentStrings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FormatMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Mutex.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Semaphore.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEnvironmentVariable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.EventWaitHandle.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Variables.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Win32Marshal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Mutex.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Semaphore.Windows.cs" />
@@ -1066,15 +1091,23 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Utils.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Access.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.ChDir.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Close.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.FLock.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.FSync.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.FTruncate.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetCwd.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetEUid.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetHostName.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetPwUid.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetRandomBytes.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetUnixName.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.GetUnixRelease.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.LockFileRegion.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.LSeek.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.MksTemps.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.MountPoints.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Open.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.OpenFlags.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.PathConf.cs" />
@@ -1084,12 +1117,14 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.ReadDir.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.ReadLink.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Stat.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.SysConf.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.SysLog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Unlink.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Write.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" />
@@ -1101,16 +1136,23 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\PersistedFiles.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\IO\PersistedFiles.Names.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\PasteArguments.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.Unix.cs" Condition="'$(TargetsCoreRT)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Unix.cs" />
</ItemGroup>
+ <ItemGroup Condition="$(TargetsUnix) or '$(EnableWinRT)'=='true'">
+ <Compile Include="$(MSBuildThisFileDirectory)System\Environment.NoRegistry.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(FeatureHardwareIntrinsics)' == 'true' AND ('$(Platform)' == 'x64' OR ('$(Platform)' == 'x86' AND '$(TargetsUnix)' != 'true'))">
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Aes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Avx.cs" />
diff --git a/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs
new file mode 100644
index 0000000000..427d29d818
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Collections;
+using Microsoft.Win32;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ // Systems without the Windows registry pretend that it's always empty.
+
+ private static string GetEnvironmentVariableFromRegistry(string variable, bool fromMachine) => null;
+
+ private static void SetEnvironmentVariableFromRegistry(string variable, string value, bool fromMachine) { }
+
+ private static IDictionary GetEnvironmentVariablesFromRegistry(bool fromMachine) => new Hashtable();
+ }
+}
diff --git a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs
index e18b5951ea..a69aa63a72 100644
--- a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs
+++ b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs
@@ -16,17 +16,15 @@ namespace System
{
public static partial class Environment
{
- internal static readonly bool IsMac = Interop.Sys.GetUnixName() == "OSX";
+ private static readonly bool s_isMac = Interop.Sys.GetUnixName() == "OSX";
private static Func<string, object> s_directoryCreateDirectory;
private static string CurrentDirectoryCore
{
- get { return Interop.Sys.GetCwd(); }
- set { Interop.CheckIo(Interop.Sys.ChDir(value), value, isDirectory: true); }
+ get => Interop.Sys.GetCwd();
+ set => Interop.CheckIo(Interop.Sys.ChDir(value), value, isDirectory: true);
}
- public static int ExitCode { get { return EnvironmentAugments.ExitCode; } set { EnvironmentAugments.ExitCode = value; } }
-
private static string ExpandEnvironmentVariablesCore(string name)
{
Span<char> initialBuffer = stackalloc char[128];
@@ -101,7 +99,7 @@ namespace System
case SpecialFolder.CommonApplicationData: return "/usr/share";
case SpecialFolder.CommonTemplates: return "/usr/share/templates";
}
- if (IsMac)
+ if (s_isMac)
{
switch (folder)
{
@@ -161,17 +159,17 @@ namespace System
return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos");
case SpecialFolder.MyMusic:
- return IsMac ? Path.Combine(home, "Music") : ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music");
+ return s_isMac ? Path.Combine(home, "Music") : ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music");
case SpecialFolder.MyPictures:
- return IsMac ? Path.Combine(home, "Pictures") : ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures");
+ return s_isMac ? Path.Combine(home, "Pictures") : ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures");
case SpecialFolder.Fonts:
- return IsMac ? Path.Combine(home, "Library", "Fonts") : Path.Combine(home, ".fonts");
+ return s_isMac ? Path.Combine(home, "Library", "Fonts") : Path.Combine(home, ".fonts");
case SpecialFolder.Favorites:
- if (IsMac) return Path.Combine(home, "Library", "Favorites");
+ if (s_isMac) return Path.Combine(home, "Library", "Favorites");
break;
case SpecialFolder.InternetCache:
- if (IsMac) return Path.Combine(home, "Library", "Caches");
+ if (s_isMac) return Path.Combine(home, "Library", "Caches");
break;
}
diff --git a/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs b/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs
new file mode 100644
index 0000000000..7e8bcce6ad
--- /dev/null
+++ b/src/System.Private.CoreLib/shared/System/Environment.Variables.Windows.cs
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ private static string GetEnvironmentVariableCore(string variable)
+ {
+ Span<char> buffer = stackalloc char[128]; // a somewhat reasonable default size
+ int requiredSize = Interop.Kernel32.GetEnvironmentVariable(variable, buffer);
+
+ if (requiredSize == 0 && Marshal.GetLastWin32Error() == Interop.Errors.ERROR_ENVVAR_NOT_FOUND)
+ {
+ return null;
+ }
+
+ if (requiredSize <= buffer.Length)
+ {
+ return new string(buffer.Slice(0, requiredSize));
+ }
+
+ char[] chars = ArrayPool<char>.Shared.Rent(requiredSize);
+ try
+ {
+ buffer = chars;
+ requiredSize = Interop.Kernel32.GetEnvironmentVariable(variable, buffer);
+ if ((requiredSize == 0 && Marshal.GetLastWin32Error() == Interop.Errors.ERROR_ENVVAR_NOT_FOUND) ||
+ requiredSize > buffer.Length)
+ {
+ return null;
+ }
+
+ return new string(buffer.Slice(0, requiredSize));
+ }
+ finally
+ {
+ ArrayPool<char>.Shared.Return(chars);
+ }
+ }
+
+ private static void SetEnvironmentVariableCore(string variable, string value)
+ {
+ if (!Interop.Kernel32.SetEnvironmentVariable(variable, value))
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ switch (errorCode)
+ {
+ case Interop.Errors.ERROR_ENVVAR_NOT_FOUND:
+ // Allow user to try to clear a environment variable
+ return;
+
+ case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
+ // The error message from Win32 is "The filename or extension is too long",
+ // which is not accurate.
+ throw new ArgumentException(SR.Format(SR.Argument_LongEnvVarValue));
+
+ case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY:
+ case Interop.Errors.ERROR_NO_SYSTEM_RESOURCES:
+ throw new OutOfMemoryException(Interop.Kernel32.GetMessage(errorCode));
+
+ default:
+ throw new ArgumentException(Interop.Kernel32.GetMessage(errorCode));
+ }
+ }
+ }
+
+ public static unsafe IDictionary GetEnvironmentVariables()
+ {
+ char* pStrings = Interop.Kernel32.GetEnvironmentStrings();
+ if (pStrings == null)
+ {
+ throw new OutOfMemoryException();
+ }
+
+ try
+ {
+ // 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++;
+ }
+ Span<char> block = new Span<char>(pStrings, (int)(p - pStrings + 1));
+
+ // 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.
+
+ // 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).
+
+ var results = new Hashtable();
+ for (int i = 0; i < block.Length; i++)
+ {
+ int startKey = i;
+
+ // Skip to key. On some old OS, the environment block can be corrupted.
+ // Some 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.Slice(startKey, i - startKey));
+ i++; // skip over '='
+
+ int startValue = i;
+ while (block[i] != 0)
+ {
+ i++; // Read to end of this entry
+ }
+
+ string value = new string(block.Slice(startValue, i - startValue)); // skip over 0 handled by for loop's i++
+ try
+ {
+ results.Add(key, value);
+ }
+ catch (ArgumentException)
+ {
+ // Throw and catch intentionally to provide non-fatal notification about corrupted environment block
+ }
+ }
+ return results;
+ }
+ finally
+ {
+ bool success = Interop.Kernel32.FreeEnvironmentStrings(pStrings);
+ Debug.Assert(success);
+ }
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs
index 3ac7663b50..f7b87ff786 100644
--- a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs
+++ b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs
@@ -2,18 +2,126 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections;
+using System.Diagnostics;
using System.IO;
-using System.Text;
+using System.Reflection;
using System.Runtime.InteropServices;
+using System.Text;
+using Internal.Win32;
namespace System
{
public static partial class Environment
{
+ private static string GetEnvironmentVariableFromRegistry(string variable, bool fromMachine)
+ {
+ Debug.Assert(variable != null);
+
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap)
+ return null; // Systems without the Windows registry pretend that it's always empty.
+#endif
+
+ using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false))
+ {
+ return environmentKey?.GetValue(variable) as string;
+ }
+ }
+
+ private static void SetEnvironmentVariableFromRegistry(string variable, string value, bool fromMachine)
+ {
+ Debug.Assert(variable != null);
+
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap)
+ return; // Systems without the Windows registry pretend that it's always empty.
+#endif
+
+ const int MaxUserEnvVariableLength = 255; // User-wide env vars stored in the registry have names limited to 255 chars
+ if (!fromMachine && variable.Length >= MaxUserEnvVariableLength)
+ {
+ throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable));
+ }
+
+ using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: true))
+ {
+ if (environmentKey != null)
+ {
+ if (value == null)
+ {
+ environmentKey.DeleteValue(variable, throwOnMissingValue: false);
+ }
+ else
+ {
+ environmentKey.SetValue(variable, value);
+ }
+ }
+ }
+
+ // send a WM_SETTINGCHANGE message to all windows
+ IntPtr r = Interop.User32.SendMessageTimeout(new IntPtr(Interop.User32.HWND_BROADCAST), Interop.User32.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
+ Debug.Assert(r != IntPtr.Zero, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
+ }
+
+ private static IDictionary GetEnvironmentVariablesFromRegistry(bool fromMachine)
+ {
+ var results = new Hashtable();
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap) // Systems without the Windows registry pretend that it's always empty.
+ return results;
+#endif
+
+ using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false))
+ {
+ if (environmentKey != null)
+ {
+ foreach (string name in environmentKey.GetValueNames())
+ {
+ string value = environmentKey.GetValue(name, "").ToString();
+ try
+ {
+ results.Add(name, value);
+ }
+ catch (ArgumentException)
+ {
+ // Throw and catch intentionally to provide non-fatal notification about corrupted environment block
+ }
+ }
+ }
+ }
+
+ return results;
+ }
+
+ private static RegistryKey OpenEnvironmentKeyIfExists(bool fromMachine, bool writable)
+ {
+ RegistryKey baseKey;
+ string keyName;
+
+ if (fromMachine)
+ {
+ baseKey = Registry.LocalMachine;
+ keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
+ }
+ else
+ {
+ baseKey = Registry.CurrentUser;
+ keyName = "Environment";
+ }
+
+ return baseKey.OpenSubKey(keyName, writable: writable);
+ }
+
public static string UserName
{
get
{
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap)
+ return "Windows User";
+#endif
+
// 40 should be enough as we're asking for the SAM compatible name (DOMAIN\User).
// The max length should be 15 (domain) + 1 (separator) + 20 (name) + null. If for
// some reason it isn't, we'll grow the buffer.
@@ -60,6 +168,11 @@ namespace System
{
get
{
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap)
+ return "Windows Domain";
+#endif
+
// See the comment in UserName
Span<char> initialBuffer = stackalloc char[40];
var builder = new ValueStringBuilder(initialBuffer);
@@ -108,6 +221,11 @@ namespace System
private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
{
+#if FEATURE_APPX
+ if (ApplicationModel.IsUap)
+ return WinRTFolderPaths.GetFolderPath(folder, option);
+#endif
+
// We're using SHGetKnownFolderPath instead of SHGetFolderPath as SHGetFolderPath is
// capped at MAX_PATH.
//
@@ -280,5 +398,25 @@ namespace System
return path;
}
+
+#if FEATURE_APPX
+ private static class WinRTFolderPaths
+ {
+ private static Func<SpecialFolder, SpecialFolderOption, string> s_winRTFolderPathsGetFolderPath;
+
+ public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
+ {
+ if (s_winRTFolderPathsGetFolderPath == null)
+ {
+ Type winRtFolderPathsType = Type.GetType("System.WinRTFolderPaths, System.Runtime.WindowsRuntime, Version=4.0.14.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: false);
+ MethodInfo getFolderPathsMethod = winRtFolderPathsType?.GetMethod("GetFolderPath", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(SpecialFolder), typeof(SpecialFolderOption) }, null);
+ var d = (Func<SpecialFolder, SpecialFolderOption, string>)getFolderPathsMethod?.CreateDelegate(typeof(Func<SpecialFolder, SpecialFolderOption, string>));
+ s_winRTFolderPathsGetFolderPath = d ?? delegate { return null; };
+ }
+
+ return s_winRTFolderPathsGetFolderPath(folder, option);
+ }
+ }
+#endif
}
}
diff --git a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs
index 991c69c023..db56ea1a7a 100644
--- a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs
@@ -3,9 +3,10 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
-using Internal.Runtime.Augments;
+using Microsoft.Win32;
namespace System
{
@@ -59,15 +60,13 @@ namespace System
}
}
- public static int ExitCode { get { return EnvironmentAugments.ExitCode; } set { EnvironmentAugments.ExitCode = value; } }
-
private static string ExpandEnvironmentVariablesCore(string name)
{
Span<char> initialBuffer = stackalloc char[128];
var builder = new ValueStringBuilder(initialBuffer);
uint length;
- while ((length = Interop.Kernel32.ExpandEnvironmentStringsW(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
+ while ((length = Interop.Kernel32.ExpandEnvironmentStrings(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
{
builder.EnsureCapacity((int)length);
}
@@ -80,21 +79,12 @@ namespace System
return builder.ToString();
}
- private static bool Is64BitOperatingSystemWhen32BitProcess
- => Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool isWow64) && isWow64;
+ private static bool Is64BitOperatingSystemWhen32BitProcess =>
+ Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool isWow64) && isWow64;
- public static string MachineName
- {
- get
- {
- string name = Interop.Kernel32.GetComputerName();
- if (name == null)
- {
- throw new InvalidOperationException(SR.InvalidOperation_ComputerName);
- }
- return name;
- }
- }
+ public static string MachineName =>
+ Interop.Kernel32.GetComputerName() ??
+ throw new InvalidOperationException(SR.InvalidOperation_ComputerName);
private static readonly unsafe Lazy<OperatingSystem> s_osVersion = new Lazy<OperatingSystem>(() =>
{
diff --git a/src/System.Private.CoreLib/shared/System/Environment.cs b/src/System.Private.CoreLib/shared/System/Environment.cs
index 6daccb8da9..870f22d49a 100644
--- a/src/System.Private.CoreLib/shared/System/Environment.cs
+++ b/src/System.Private.CoreLib/shared/System/Environment.cs
@@ -6,8 +6,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
-using System.Runtime.CompilerServices;
-using Internal.Runtime.Augments;
namespace System
{
@@ -15,157 +13,113 @@ namespace System
{
public static string GetEnvironmentVariable(string variable)
{
- return EnvironmentAugments.GetEnvironmentVariable(variable);
+ if (variable == null)
+ throw new ArgumentNullException(nameof(variable));
+
+ return GetEnvironmentVariableCore(variable);
}
public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
{
- return EnvironmentAugments.GetEnvironmentVariable(variable, target);
- }
+ if (target == EnvironmentVariableTarget.Process)
+ return GetEnvironmentVariable(variable);
- public static IDictionary GetEnvironmentVariables()
- {
- // To maintain complete compatibility with prior versions we need to return a Hashtable.
- // We did ship a prior version of Core with LowLevelDictionary, which does iterate the
- // same (e.g. yields DictionaryEntry), but it is not a public type.
- //
- // While we could pass Hashtable back from CoreCLR the type is also defined here. We only
- // want to surface the local Hashtable.
- return EnvironmentAugments.EnumerateEnvironmentVariables().ToHashtable();
+ if (variable == null)
+ throw new ArgumentNullException(nameof(variable));
+
+ bool fromMachine = ValidateAndConvertRegistryTarget(target);
+ return GetEnvironmentVariableFromRegistry(variable, fromMachine);
}
public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
{
- // See comments in GetEnvironmentVariables()
- return EnvironmentAugments.EnumerateEnvironmentVariables(target).ToHashtable();
- }
+ if (target == EnvironmentVariableTarget.Process)
+ return GetEnvironmentVariables();
- private static Hashtable ToHashtable(this IEnumerable<KeyValuePair<string, string>> pairs)
- {
- Hashtable hashTable = new Hashtable();
- foreach (KeyValuePair<string, string> pair in pairs)
- {
- try
- {
- hashTable.Add(pair.Key, pair.Value);
- }
- catch (ArgumentException)
- {
- // Throw and catch intentionally to provide non-fatal notification about corrupted environment block
- }
- }
- return hashTable;
+ bool fromMachine = ValidateAndConvertRegistryTarget(target);
+ return GetEnvironmentVariablesFromRegistry(fromMachine);
}
public static void SetEnvironmentVariable(string variable, string value)
{
- EnvironmentAugments.SetEnvironmentVariable(variable, value);
+ ValidateVariableAndValue(variable, ref value);
+ SetEnvironmentVariableCore(variable, value);
}
public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
{
- EnvironmentAugments.SetEnvironmentVariable(variable, value, target);
- }
-
- public static string CommandLine
- {
- get
+ if (target == EnvironmentVariableTarget.Process)
{
- return PasteArguments.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules: true);
+ SetEnvironmentVariable(variable, value);
+ return;
}
+
+ ValidateVariableAndValue(variable, ref value);
+
+ bool fromMachine = ValidateAndConvertRegistryTarget(target);
+ SetEnvironmentVariableFromRegistry(variable, value, fromMachine: fromMachine);
}
+ public static string CommandLine => PasteArguments.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules: true);
+
public static string CurrentDirectory
{
- get { return CurrentDirectoryCore; }
+ get => CurrentDirectoryCore;
set
{
if (value == null)
- {
throw new ArgumentNullException(nameof(value));
- }
if (value.Length == 0)
- {
throw new ArgumentException(SR.Argument_PathEmpty, nameof(value));
- }
CurrentDirectoryCore = value;
}
}
- public static int CurrentManagedThreadId => EnvironmentAugments.CurrentManagedThreadId;
-
- public static void Exit(int exitCode) => EnvironmentAugments.Exit(exitCode);
-
- public static void FailFast(string message) => FailFast(message, exception: null);
-
- public static void FailFast(string message, Exception exception) => EnvironmentAugments.FailFast(message, exception);
-
public static string ExpandEnvironmentVariables(string name)
{
if (name == null)
- {
throw new ArgumentNullException(nameof(name));
- }
if (name.Length == 0)
- {
return name;
- }
return ExpandEnvironmentVariablesCore(name);
}
- public static string[] GetCommandLineArgs() => EnvironmentAugments.GetCommandLineArgs();
+ private static string[] s_commandLineArgs;
+
+ internal static void SetCommandLineArgs(string[] cmdLineArgs) // invoked from VM
+ {
+ s_commandLineArgs = cmdLineArgs;
+ }
public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None);
public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
{
if (!Enum.IsDefined(typeof(SpecialFolder), folder))
- {
throw new ArgumentOutOfRangeException(nameof(folder), folder, SR.Format(SR.Arg_EnumIllegalVal, folder));
- }
if (option != SpecialFolderOption.None && !Enum.IsDefined(typeof(SpecialFolderOption), option))
- {
throw new ArgumentOutOfRangeException(nameof(option), option, SR.Format(SR.Arg_EnumIllegalVal, option));
- }
return GetFolderPathCore(folder, option);
}
- public static bool HasShutdownStarted => EnvironmentAugments.HasShutdownStarted;
-
public static bool Is64BitProcess => IntPtr.Size == 8;
public static bool Is64BitOperatingSystem => Is64BitProcess || Is64BitOperatingSystemWhen32BitProcess;
public static OperatingSystem OSVersion => s_osVersion.Value;
- public static int ProcessorCount => EnvironmentAugments.ProcessorCount;
-
- public static string StackTrace
- {
- [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
- get
- {
- return EnvironmentAugments.StackTrace;
- }
- }
-
- public static int TickCount => EnvironmentAugments.TickCount;
-
public static bool UserInteractive => true;
- public static Version Version
- {
- // 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.
- get { return new Version(4, 0, 30319, 42000); }
- }
+ // 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.
+ public static Version Version => new Version(4, 0, 30319, 42000);
public static long WorkingSet
{
@@ -185,9 +139,44 @@ namespace System
if (result is long) return (long)result;
}
}
+
// Could not get the current working set.
return 0;
}
}
+
+ private static bool ValidateAndConvertRegistryTarget(EnvironmentVariableTarget target)
+ {
+ Debug.Assert(target != EnvironmentVariableTarget.Process);
+
+ if (target == EnvironmentVariableTarget.Machine)
+ return true;
+
+ if (target == EnvironmentVariableTarget.User)
+ return false;
+
+ throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target));
+ }
+
+ private static void ValidateVariableAndValue(string variable, ref string value)
+ {
+ if (variable == null)
+ throw new ArgumentNullException(nameof(variable));
+
+ if (variable.Length == 0)
+ throw new ArgumentException(SR.Argument_StringZeroLength, nameof(variable));
+
+ if (variable[0] == '\0')
+ throw new ArgumentException(SR.Argument_StringFirstCharIsZero, nameof(variable));
+
+ if (variable.Contains('='))
+ throw new ArgumentException(SR.Argument_IllegalEnvVarName, nameof(variable));
+
+ if (string.IsNullOrEmpty(value) || value[0] == '\0')
+ {
+ // Explicitly null out value if it's empty
+ value = null;
+ }
+ }
}
}
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
index 8bed354ac1..a501f87a56 100644
--- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
@@ -3,13 +3,16 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections;
using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
namespace Internal.Runtime.Augments
{
- /// <summary>For internal use only. Exposes runtime functionality to the Environments implementation in corefx.</summary>
+ // TODO: Delete this file once corefx has consumed https://github.com/dotnet/coreclr/pull/22106
+ // and its corresponding mirrored build from corert, and then the resulting corefx builds
+ // have been consumed back here, such that the CI tests which currently expect to find
+ // EnvironmentAugments have been updated to no longer need it.
+
public static class EnvironmentAugments
{
public static int CurrentManagedThreadId => Environment.CurrentManagedThreadId;
@@ -21,20 +24,25 @@ namespace Internal.Runtime.Augments
public static int TickCount => Environment.TickCount;
public static string GetEnvironmentVariable(string variable) => Environment.GetEnvironmentVariable(variable);
public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) => Environment.GetEnvironmentVariable(variable, target);
- public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables() => Environment.EnumerateEnvironmentVariables();
- public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables(EnvironmentVariableTarget target) => Environment.EnumerateEnvironmentVariables(target);
- public static int ProcessorCount => Environment.ProcessorCount;
-
- public static void SetEnvironmentVariable(string variable, string value) => Environment.SetEnvironmentVariable(variable, value);
- public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) => Environment.SetEnvironmentVariable(variable, value, target);
-
- public static string StackTrace
+ public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables()
{
- [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
- get
+ IDictionaryEnumerator de = Environment.GetEnvironmentVariables().GetEnumerator();
+ while (de.MoveNext())
{
- return new StackTrace(1 /* skip this one frame */, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
+ yield return new KeyValuePair<string, string>((string)de.Key, (string)de.Value);
}
}
+ public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables(EnvironmentVariableTarget target)
+ {
+ IDictionaryEnumerator de = Environment.GetEnvironmentVariables(target).GetEnumerator();
+ while (de.MoveNext())
+ {
+ yield return new KeyValuePair<string, string>((string)de.Key, (string)de.Value);
+ }
+ }
+ public static int ProcessorCount => Environment.ProcessorCount;
+ public static void SetEnvironmentVariable(string variable, string value) => Environment.SetEnvironmentVariable(variable, value);
+ public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target) => Environment.SetEnvironmentVariable(variable, value, target);
+ public static string StackTrace => Environment.StackTrace; // this will temporarily result in an extra frame in Environment.StackTrace calls
}
}
diff --git a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs
index 4374c735cd..9d2cc9a4e6 100644
--- a/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs
+++ b/src/System.Private.CoreLib/src/Microsoft/Win32/Win32Native.cs
@@ -154,26 +154,6 @@ namespace Microsoft.Win32
[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
internal static extern IntPtr GetStdHandle(int nStdHandle); // param is NOT a handle, but it returns one!
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
- internal static extern bool SetEnvironmentVariable(string lpName, string lpValue);
-
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
- private static extern unsafe int GetEnvironmentVariable(string lpName, char* lpValue, int size);
-
- internal static unsafe int GetEnvironmentVariable(string lpName, Span<char> lpValue)
- {
- fixed (char* lpValuePtr = &MemoryMarshal.GetReference(lpValue))
- {
- return GetEnvironmentVariable(lpName, lpValuePtr, lpValue.Length);
- }
- }
-
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Unicode)]
- internal static extern unsafe char* GetEnvironmentStrings();
-
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Unicode)]
- internal static extern unsafe bool FreeEnvironmentStrings(char* pStrings);
-
[DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Auto)]
internal static extern int GetCurrentThreadId();
@@ -189,9 +169,6 @@ namespace Microsoft.Win32
[DllImport(Interop.Libraries.Ole32)]
internal static extern IntPtr CoTaskMemRealloc(IntPtr pv, UIntPtr cb);
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
- internal static extern uint ExpandEnvironmentStringsW(string lpSrc, ref char lpDst, uint nSize);
-
[DllImport(Interop.Libraries.Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool QueryUnbiasedInterruptTime(out ulong UnbiasedTime);
diff --git a/src/System.Private.CoreLib/src/System/CLRConfig.cs b/src/System.Private.CoreLib/src/System/CLRConfig.cs
index 1885c57e9f..5b14f282ed 100644
--- a/src/System.Private.CoreLib/src/System/CLRConfig.cs
+++ b/src/System.Private.CoreLib/src/System/CLRConfig.cs
@@ -30,8 +30,7 @@ namespace System
// abstractions where reasonably possible.
Span<char> buffer = stackalloc char[32];
-
- int length = Win32Native.GetEnvironmentVariable(environmentName, buffer);
+ int length = Interop.Kernel32.GetEnvironmentVariable(environmentName, buffer);
switch (length)
{
case 1:
diff --git a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
new file mode 100644
index 0000000000..8d92a7e4a8
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
@@ -0,0 +1,158 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Microsoft.Win32;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ public static int CurrentManagedThreadId => Thread.CurrentThread.ManagedThreadId;
+
+ // Terminates this process with the given exit code.
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ private static extern void _Exit(int exitCode);
+
+ public static void Exit(int exitCode) => _Exit(exitCode);
+
+ public static extern int ExitCode
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ [MethodImpl(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.
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern void FailFast(string message);
+
+ // 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).
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern void FailFast(string message, Exception exception);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public static extern void FailFast(string message, Exception exception, string errorMessage);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string[] GetCommandLineArgsNative();
+
+ public static string[] GetCommandLineArgs()
+ {
+ // There are multiple entry points to a hosted app. The host could
+ // use ::ExecuteAssembly() or ::CreateDelegate option:
+ //
+ // ::ExecuteAssembly() -> In this particular case, the runtime invokes the main
+ // method based on the arguments set by the host, and we return those arguments
+ //
+ // ::CreateDelegate() -> In this particular case, the host is asked to create a
+ // delegate based on the appDomain, assembly and methodDesc passed to it.
+ // which the caller uses to invoke the method. In this particular case we do not have
+ // any information on what arguments would be passed to the delegate.
+ // So our best bet is to simply use the commandLine that was used to invoke the process.
+ // in case it is present.
+
+ return s_commandLineArgs != null ?
+ (string[])s_commandLineArgs.Clone() :
+ GetCommandLineArgsNative();
+ }
+
+ public static extern bool HasShutdownStarted
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
+
+ public static int ProcessorCount => GetProcessorCount();
+
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ private static extern int GetProcessorCount();
+
+ // 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
+ internal static string GetResourceStringLocal(string key) => SR.GetResourceString(key);
+
+ public static string StackTrace
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
+ get => new StackTrace(true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
+ }
+
+ public static extern int TickCount
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
+
+#if !FEATURE_PAL
+ internal static bool IsWindows8OrAbove => WindowsVersion.IsWindows8OrAbove;
+
+ // Seperate type so a .cctor is not created for Enviroment which then would be triggered during startup
+ private static class WindowsVersion
+ {
+ // Cache the value in readonly static that can be optimized out by the JIT
+ internal readonly static bool IsWindows8OrAbove = GetIsWindows8OrAbove();
+
+ private static bool GetIsWindows8OrAbove()
+ {
+ ulong conditionMask = Win32Native.VerSetConditionMask(0, Win32Native.VER_MAJORVERSION, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_MINORVERSION, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMAJOR, Win32Native.VER_GREATER_EQUAL);
+ conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMINOR, Win32Native.VER_GREATER_EQUAL);
+
+ // Windows 8 version is 6.2
+ var version = new Win32Native.OSVERSIONINFOEX();
+ unsafe
+ {
+ version.dwOSVersionInfoSize = sizeof(Win32Native.OSVERSIONINFOEX);
+ }
+ version.dwMajorVersion = 6;
+ version.dwMinorVersion = 2;
+ version.wServicePackMajor = 0;
+ version.wServicePackMinor = 0;
+
+ return Win32Native.VerifyVersionInfoW(ref version,
+ Win32Native.VER_MAJORVERSION | Win32Native.VER_MINORVERSION | Win32Native.VER_SERVICEPACKMAJOR | Win32Native.VER_SERVICEPACKMINOR,
+ conditionMask);
+ }
+ }
+#endif
+
+#if FEATURE_COMINTEROP
+ // Seperate type so a .cctor is not created for Enviroment which then would be triggered during startup
+ private static class WinRT
+ {
+ // Cache the value in readonly static that can be optimized out by the JIT
+ public readonly static bool IsSupported = WinRTSupported();
+ }
+
+ // Does the current version of Windows have Windows Runtime suppport?
+ internal static bool IsWinRTSupported => WinRT.IsSupported;
+
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool WinRTSupported();
+#endif // FEATURE_COMINTEROP
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/System.Private.CoreLib/src/System/Environment.Windows.cs
deleted file mode 100644
index 5bf7bea158..0000000000
--- a/src/System.Private.CoreLib/src/System/Environment.Windows.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-
-namespace System
-{
- internal static partial class Environment
- {
- internal static string SystemDirectory
- {
- get
- {
- // The path will likely be under 32 characters, e.g. C:\Windows\system32
- Span<char> buffer = stackalloc char[32];
- int requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
-
- if (requiredSize > buffer.Length)
- {
- buffer = new char[requiredSize];
- requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
- }
-
- if (requiredSize == 0)
- {
- throw Win32Marshal.GetExceptionForLastWin32Error();
- }
-
- return new string(buffer.Slice(0, requiredSize));
- }
- }
- }
-}
diff --git a/src/System.Private.CoreLib/src/System/Environment.cs b/src/System.Private.CoreLib/src/System/Environment.cs
deleted file mode 100644
index 04bd7d0ce7..0000000000
--- a/src/System.Private.CoreLib/src/System/Environment.cs
+++ /dev/null
@@ -1,708 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*============================================================
-**
-**
-**
-** Purpose: Provides some basic access to some environment
-** functionality.
-**
-**
-============================================================*/
-
-using Microsoft.Win32;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Text;
-using System.Runtime.InteropServices;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Threading;
-
-#if FEATURE_WIN32_REGISTRY
-using Internal.Win32;
-#endif
-
-namespace System
-{
- internal static partial class Environment
- {
- // Assume the following constants include the terminating '\0' - use <, not <=
-
- // 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.
- private const int MaxSystemEnvVariableLength = 1024;
- private const int MaxUserEnvVariableLength = 255;
- private const int MaxMachineNameLength = 256;
-
- // 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
- internal static string GetResourceStringLocal(string key)
- {
- return SR.GetResourceString(key);
- }
-
- /*==================================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
- {
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- get;
- }
-
- // Terminates this process with the given exit code.
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- internal static extern void _Exit(int exitCode);
-
- public static void Exit(int exitCode)
- {
- _Exit(exitCode);
- }
-
-
- public static extern int ExitCode
- {
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- get;
-
- [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.
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern void FailFast(string message);
-
- // 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).
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern void FailFast(string message, Exception exception);
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern void FailFast(string message, Exception exception, string errorMessage);
-
-#if FEATURE_WIN32_REGISTRY
- // This is only used by RegistryKey on Windows.
- internal static string ExpandEnvironmentVariables(string name)
- {
- Debug.Assert(name != null);
-
- if (name.Length == 0)
- {
- return name;
- }
-
- Span<char> initialBuffer = stackalloc char[128];
- var builder = new ValueStringBuilder(initialBuffer);
-
- uint length;
- while ((length = Win32Native.ExpandEnvironmentStringsW(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
- {
- builder.EnsureCapacity((int)length);
- }
-
- if (length == 0)
- {
- Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
- }
-
- // length includes the null terminator
- builder.Length = (int)length - 1;
- return builder.ToString();
- }
-#endif // FEATURE_WIN32_REGISTRY
-
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- private static extern int GetProcessorCount();
-
- public static int ProcessorCount
- {
- get
- {
- return GetProcessorCount();
- }
- }
-
- /*==============================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.
- ==============================================================================*/
- public static string[] GetCommandLineArgs()
- {
- /*
- * There are multiple entry points to a hosted app.
- * The host could use ::ExecuteAssembly() or ::CreateDelegate option
- * ::ExecuteAssembly() -> In this particular case, the runtime invokes the main
- method based on the arguments set by the host, and we return those arguments
- *
- * ::CreateDelegate() -> In this particular case, the host is asked to create a
- * delegate based on the appDomain, assembly and methodDesc passed to it.
- * which the caller uses to invoke the method. In this particular case we do not have
- * any information on what arguments would be passed to the delegate.
- * So our best bet is to simply use the commandLine that was used to invoke the process.
- * in case it is present.
- */
- if (s_CommandLineArgs != null)
- return (string[])s_CommandLineArgs.Clone();
-
- return GetCommandLineArgsNative();
- }
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private static extern string[] GetCommandLineArgsNative();
-
- private static string[] s_CommandLineArgs;
- private static void SetCommandLineArgs(string[] cmdLineArgs)
- {
- s_CommandLineArgs = cmdLineArgs;
- }
-
- private static unsafe char[] GetEnvironmentCharArray()
- {
- char[] block = null;
-
- RuntimeHelpers.PrepareConstrainedRegions();
-
- 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;
- }
-
- /*===================================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
- {
-#if PLATFORM_WINDOWS
- return "\r\n";
-#else
- return "\n";
-#endif // PLATFORM_WINDOWS
- }
- }
-
-
- /*===================================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);
- }
- }
-
-#if !FEATURE_PAL
- internal static bool IsWindows8OrAbove => WindowsVersion.IsWindows8OrAbove;
-
- // Seperate type so a .cctor is not created for Enviroment which then would be triggered during startup
- private static class WindowsVersion
- {
- // Cache the value in readonly static that can be optimized out by the JIT
- internal readonly static bool IsWindows8OrAbove = GetIsWindows8OrAbove();
-
- private static bool GetIsWindows8OrAbove()
- {
- bool isWindows8OrAbove;
- unsafe
- {
- ulong conditionMask = Win32Native.VerSetConditionMask(0, Win32Native.VER_MAJORVERSION, Win32Native.VER_GREATER_EQUAL);
- conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_MINORVERSION, Win32Native.VER_GREATER_EQUAL);
- conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMAJOR, Win32Native.VER_GREATER_EQUAL);
- conditionMask = Win32Native.VerSetConditionMask(conditionMask, Win32Native.VER_SERVICEPACKMINOR, Win32Native.VER_GREATER_EQUAL);
-
- // Windows 8 version is 6.2
- var version = new Win32Native.OSVERSIONINFOEX();
- version.dwOSVersionInfoSize = sizeof(Win32Native.OSVERSIONINFOEX);
- version.dwMajorVersion = 6;
- version.dwMinorVersion = 2;
- version.wServicePackMajor = 0;
- version.wServicePackMinor = 0;
-
- isWindows8OrAbove = Win32Native.VerifyVersionInfoW(ref version,
- Win32Native.VER_MAJORVERSION | Win32Native.VER_MINORVERSION | Win32Native.VER_SERVICEPACKMAJOR | Win32Native.VER_SERVICEPACKMINOR,
- conditionMask);
- }
-
- return isWindows8OrAbove;
- }
- }
-#endif
-
-#if FEATURE_COMINTEROP
- // Seperate type so a .cctor is not created for Enviroment which then would be triggered during startup
- private static class WinRT
- {
- // Cache the value in readonly static that can be optimized out by the JIT
- public readonly static bool IsSupported = WinRTSupported();
- }
-
- // Does the current version of Windows have Windows Runtime suppport?
- internal static bool IsWinRTSupported => WinRT.IsSupported;
-
- [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool WinRTSupported();
-#endif // FEATURE_COMINTEROP
-
-
- /*==================================StackTrace==================================
- **Action:
- **Returns:
- **Arguments:
- **Exceptions:
- ==============================================================================*/
- public static string StackTrace
- {
- [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
- get
- {
- return Internal.Runtime.Augments.EnvironmentAugments.StackTrace;
- }
- }
-
- 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);
- }
-
- public static extern bool HasShutdownStarted
- {
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- get;
- }
-
- internal static bool UserInteractive
- {
- get
- {
- return true;
- }
- }
- public static int CurrentManagedThreadId
- {
- get
- {
- return Thread.CurrentThread.ManagedThreadId;
- }
- }
-
- public static string GetEnvironmentVariable(string variable)
- {
- if (variable == null)
- {
- throw new ArgumentNullException(nameof(variable));
- }
-
- // separated from the EnvironmentVariableTarget overload to help with tree shaking in common case
- return GetEnvironmentVariableCore(variable);
- }
-
- internal static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
- {
- if (variable == null)
- {
- throw new ArgumentNullException(nameof(variable));
- }
-
- ValidateTarget(target);
-
- return GetEnvironmentVariableCore(variable, target);
- }
-
- public static void SetEnvironmentVariable(string variable, string value)
- {
- ValidateVariableAndValue(variable, ref value);
-
- // separated from the EnvironmentVariableTarget overload to help with tree shaking in common case
- SetEnvironmentVariableCore(variable, value);
- }
-
- internal static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
- {
- ValidateVariableAndValue(variable, ref value);
- ValidateTarget(target);
-
- SetEnvironmentVariableCore(variable, value, target);
- }
-
- private static void ValidateVariableAndValue(string variable, ref string value)
- {
- if (variable == null)
- {
- throw new ArgumentNullException(nameof(variable));
- }
- if (variable.Length == 0)
- {
- throw new ArgumentException(SR.Argument_StringZeroLength, nameof(variable));
- }
- if (variable[0] == '\0')
- {
- throw new ArgumentException(SR.Argument_StringFirstCharIsZero, nameof(variable));
- }
- if (variable.Contains('='))
- {
- throw new ArgumentException(SR.Argument_IllegalEnvVarName, nameof(variable));
- }
-
- if (string.IsNullOrEmpty(value) || value[0] == '\0')
- {
- // Explicitly null out value if it's empty
- value = null;
- }
- }
-
- private static void ValidateTarget(EnvironmentVariableTarget target)
- {
- if (target != EnvironmentVariableTarget.Process &&
- target != EnvironmentVariableTarget.Machine &&
- target != EnvironmentVariableTarget.User)
- {
- throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target));
- }
- }
-
- private static string GetEnvironmentVariableCore(string variable)
- {
- Span<char> buffer = stackalloc char[128]; // A somewhat reasonable default size
- return GetEnvironmentVariableCoreHelper(variable, buffer);
- }
-
- private static string GetEnvironmentVariableCoreHelper(string variable, Span<char> buffer)
- {
- int requiredSize = Win32Native.GetEnvironmentVariable(variable, buffer);
-
- if (requiredSize == 0 && Marshal.GetLastWin32Error() == Interop.Errors.ERROR_ENVVAR_NOT_FOUND)
- {
- return null;
- }
-
- if (requiredSize > buffer.Length)
- {
- char[] chars = ArrayPool<char>.Shared.Rent(requiredSize);
- try
- {
- return GetEnvironmentVariableCoreHelper(variable, chars);
- }
- finally
- {
- ArrayPool<char>.Shared.Return(chars);
- }
- }
-
- return new string(buffer.Slice(0, requiredSize));
- }
-
- private static string GetEnvironmentVariableCore(string variable, EnvironmentVariableTarget target)
- {
- if (target == EnvironmentVariableTarget.Process)
- return GetEnvironmentVariableCore(variable);
-
-#if FEATURE_WIN32_REGISTRY
- if (ApplicationModel.IsUap)
-#endif
- {
- return null;
- }
-#if FEATURE_WIN32_REGISTRY
- RegistryKey baseKey;
- string keyName;
-
- if (target == EnvironmentVariableTarget.Machine)
- {
- baseKey = Registry.LocalMachine;
- keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
- }
- else if (target == EnvironmentVariableTarget.User)
- {
- baseKey = Registry.CurrentUser;
- keyName = "Environment";
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)target));
- }
-
- using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
- {
- return environmentKey?.GetValue(variable) as string;
- }
-#endif
- }
-
- internal static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables()
- {
- // 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.
-
- // 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).
-
- char[] block = GetEnvironmentCharArray();
- for (int i = 0; i < block.Length; i++)
- {
- int startKey = i;
-
- // Skip to key. On some old OS, the environment block can be corrupted.
- // Some 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)
- i++; // Read to end of this entry
- string value = new string(block, startValue, i - startValue); // skip over 0 handled by for loop's i++
-
- yield return new KeyValuePair<string, string>(key, value);
- }
- }
-
- internal static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables(EnvironmentVariableTarget target)
- {
- if (target == EnvironmentVariableTarget.Process)
- return EnumerateEnvironmentVariables();
- return EnumerateEnvironmentVariablesFromRegistry(target);
- }
-
- internal static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariablesFromRegistry(EnvironmentVariableTarget target)
- {
-#if FEATURE_WIN32_REGISTRY
- if (ApplicationModel.IsUap)
-#endif
- {
- // Without registry support we have nothing to return
- ValidateTarget(target);
- yield break;
- }
-#if FEATURE_WIN32_REGISTRY
- RegistryKey baseKey;
- string keyName;
- if (target == EnvironmentVariableTarget.Machine)
- {
- baseKey = Registry.LocalMachine;
- keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
- }
- else if (target == EnvironmentVariableTarget.User)
- {
- baseKey = Registry.CurrentUser;
- keyName = @"Environment";
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target));
- }
-
- using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: false))
- {
- if (environmentKey != null)
- {
- foreach (string name in environmentKey.GetValueNames())
- {
- string value = environmentKey.GetValue(name, "").ToString();
- yield return new KeyValuePair<string, string>(name, value);
- }
- }
- }
-#endif // FEATURE_WIN32_REGISTRY
- }
-
- private static void SetEnvironmentVariableCore(string variable, string value)
- {
- // explicitly null out value if is the empty string.
- if (string.IsNullOrEmpty(value) || value[0] == '\0')
- value = null;
-
- if (!Win32Native.SetEnvironmentVariable(variable, value))
- {
- int errorCode = Marshal.GetLastWin32Error();
-
- switch (errorCode)
- {
- case Interop.Errors.ERROR_ENVVAR_NOT_FOUND:
- // Allow user to try to clear a environment variable
- return;
- case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
- // The error message from Win32 is "The filename or extension is too long",
- // which is not accurate.
- throw new ArgumentException(SR.Format(SR.Argument_LongEnvVarValue));
- case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY:
- case Interop.Errors.ERROR_NO_SYSTEM_RESOURCES:
- throw new OutOfMemoryException(Interop.Kernel32.GetMessage(errorCode));
- default:
- throw new ArgumentException(Interop.Kernel32.GetMessage(errorCode));
- }
- }
- }
-
- private static void SetEnvironmentVariableCore(string variable, string value, EnvironmentVariableTarget target)
- {
- if (target == EnvironmentVariableTarget.Process)
- {
- SetEnvironmentVariableCore(variable, value);
- return;
- }
-
-#if FEATURE_WIN32_REGISTRY
- if (ApplicationModel.IsUap)
-#endif
- {
- // other targets ignored
- return;
- }
-#if FEATURE_WIN32_REGISTRY
- // explicitly null out value if is the empty string.
- if (string.IsNullOrEmpty(value) || value[0] == '\0')
- value = null;
-
- RegistryKey baseKey;
- string keyName;
-
- if (target == EnvironmentVariableTarget.Machine)
- {
- baseKey = Registry.LocalMachine;
- keyName = @"System\CurrentControlSet\Control\Session Manager\Environment";
- }
- else if (target == EnvironmentVariableTarget.User)
- {
- // User-wide environment variables stored in the registry are limited to 255 chars for the environment variable name.
- const int MaxUserEnvVariableLength = 255;
- if (variable.Length >= MaxUserEnvVariableLength)
- {
- throw new ArgumentException(SR.Argument_LongEnvVarValue, nameof(variable));
- }
-
- baseKey = Registry.CurrentUser;
- keyName = "Environment";
- }
- else
- {
- throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)target));
- }
-
- using (RegistryKey environmentKey = baseKey.OpenSubKey(keyName, writable: true))
- {
- if (environmentKey != null)
- {
- if (value == null)
- {
- environmentKey.DeleteValue(variable, throwOnMissingValue: false);
- }
- else
- {
- environmentKey.SetValue(variable, value);
- }
- }
- }
-
- // send a WM_SETTINGCHANGE message to all windows
- IntPtr r = Interop.User32.SendMessageTimeout(new IntPtr(Interop.User32.HWND_BROADCAST),
- Interop.User32.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
-
- Debug.Assert(r != IntPtr.Zero, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
-#endif // FEATURE_WIN32_REGISTRY
- }
- }
-}
diff --git a/src/System.Private.CoreLib/src/System/Exception.cs b/src/System.Private.CoreLib/src/System/Exception.cs
index bfdd601802..de5e786b1c 100644
--- a/src/System.Private.CoreLib/src/System/Exception.cs
+++ b/src/System.Private.CoreLib/src/System/Exception.cs
@@ -307,12 +307,17 @@ namespace System
return remoteStackTraceString;
}
- // Obtain the stack trace string. Note that since Environment.GetStackTrace
- // will add the path to the source file if the PDB is present and a demand
- // for FileIOPermission(PathDiscovery) succeeds, we need to make sure we
- // don't store the stack trace string in the _stackTraceString member variable.
- string tempStackTraceString = Environment.GetStackTrace(this, needFileInfo);
- return remoteStackTraceString + tempStackTraceString;
+ // Obtain the stack trace string. Note that since GetStackTrace
+ // will add the path to the source file if the PDB is present:
+ // we need to make sure we don't store the stack trace string in
+ // the _stackTraceString member variable.
+ return remoteStackTraceString + GetStackTrace(needFileInfo, this);
+ }
+
+ private static string GetStackTrace(bool needFileInfo, Exception e)
+ {
+ // Do not include a trailing newline for backwards compatibility
+ return new StackTrace(e, needFileInfo).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
}
// Sets the help link for this exception.
@@ -418,7 +423,7 @@ namespace System
{
if (tempStackTraceString == null)
{
- tempStackTraceString = Environment.GetStackTrace(this, true);
+ tempStackTraceString = GetStackTrace(true, this);
}
if (_exceptionMethod == null)
{