diff --git a/src/Common/src/Interop/Unix/libc/Interop.Environment.cs b/src/Common/src/Interop/Unix/libc/Interop.Environment.cs
new file mode 100644
index 00000000000..f425906dcb4
--- /dev/null
+++ b/src/Common/src/Interop/Unix/libc/Interop.Environment.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal unsafe partial class libc
+ {
+
+ }
+}
diff --git a/src/Common/src/Interop/Windows/mincore/Interop.Environment.cs b/src/Common/src/Interop/Windows/mincore/Interop.Environment.cs
new file mode 100644
index 00000000000..c1e6276e8ee
--- /dev/null
+++ b/src/Common/src/Interop/Windows/mincore/Interop.Environment.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ private static class Libraries
+ {
+ internal const string Process = "api-ms-win-core-processenvironment-l1-1-0.dll";
+ }
+
+ internal static unsafe partial class mincore
+ {
+ // TODO: Once we have marshalling setup we probably want to revisit these PInvokes
+ [DllImport(Libraries.Process, EntryPoint = "GetEnvironmentVariableW")]
+ internal static unsafe extern int GetEnvironmentVariable(char* lpName, char* lpValue, int size);
+
+ [DllImport(Libraries.Process, EntryPoint = "ExpandEnvironmentStringsW")]
+ internal static unsafe extern int ExpandEnvironmentStrings(char* lpSrc, char* lpDst, int nSize);
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index 325ed5f79fa..cd36ab785aa 100644
--- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -219,7 +219,7 @@
-
+
@@ -477,6 +477,11 @@
+
+
+
+
+
@@ -485,6 +490,9 @@
+
+
+
diff --git a/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.UWP.cs b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.UWP.cs
new file mode 100644
index 00000000000..54c47ce8681
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.UWP.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*============================================================
+**
+**
+** Purpose: Provides some basic access to some environment
+** functionality.
+**
+**
+============================================================*/
+
+using System.Text;
+using System.Collections;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ public unsafe static String ExpandEnvironmentVariables(String name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ // Environment variable accessors are not approved modern API.
+ // Behave as if no variables are defined in this case.
+ return name;
+ }
+
+ public unsafe static String GetEnvironmentVariable(String variable)
+ {
+ if (variable == null)
+ throw new ArgumentNullException("variable");
+
+ // Environment variable accessors are not approved modern API.
+ // Behave as if the variable was not found in this case.
+ return null;
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Unix.cs b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Unix.cs
new file mode 100644
index 00000000000..19bb7032026
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Unix.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*============================================================
+**
+**
+** Purpose: Provides some basic access to some environment
+** functionality.
+**
+**
+============================================================*/
+
+using System.Text;
+using System.Collections;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ public unsafe static String ExpandEnvironmentVariables(String name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ //TODO: Unix implementations
+ return name;
+ }
+
+ public unsafe static String GetEnvironmentVariable(String variable)
+ {
+ if (variable == null)
+ throw new ArgumentNullException("variable");
+
+ //TODO: Unix implementations
+ return null;
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Win32.cs b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Win32.cs
new file mode 100644
index 00000000000..c713f912a5b
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.Win32.cs
@@ -0,0 +1,126 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+/*============================================================
+**
+**
+** Purpose: Provides some basic access to some environment
+** functionality.
+**
+**
+============================================================*/
+
+using System.Text;
+using System.Collections;
+
+namespace System
+{
+ public static partial class Environment
+ {
+ public unsafe static String ExpandEnvironmentVariables(String name)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ if (name.Length == 0)
+ {
+ return name;
+ }
+
+ int currentSize = 128;
+ char* blob = stackalloc char[currentSize]; // A somewhat reasonable default size
+ int requiredSize;
+ fixed (char* pName = name)
+ {
+ requiredSize = Interop.mincore.ExpandEnvironmentStrings(pName, blob, currentSize);
+ }
+
+ if (requiredSize == 0)
+ {
+ // TODO: This used to throw an exception:
+ // Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
+ throw new ArgumentException();
+ }
+
+ if (requiredSize <= currentSize)
+ {
+ return new string(blob);
+ }
+
+ // Fallback to using heap allocated buffers.
+ char[] newBlob = null;
+ while (requiredSize > currentSize)
+ {
+ currentSize = requiredSize;
+ newBlob = new char[currentSize];
+
+ fixed (char* pName = name, pBlob = newBlob)
+ {
+ requiredSize = Interop.mincore.ExpandEnvironmentStrings(pName, pBlob, currentSize);
+ }
+
+ if (requiredSize == 0)
+ {
+ // TODO: This used to throw an exception:
+ // Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
+ throw new ArgumentException();
+ }
+ }
+
+ return new string(newBlob);
+ }
+
+ public unsafe static String GetEnvironmentVariable(String variable)
+ {
+ if (variable == null)
+ throw new ArgumentNullException("variable");
+
+ // The convention of the API is as follows:
+ // You call the API with a buffer of a given size.
+ // If the size of the buffer is insufficient to hold the value,
+ // the API will return the required size for the buffer.
+ // In that case we resize the buffer and try again.
+
+ int currentSize = 128;
+ char* blob = stackalloc char[currentSize]; // A somewhat reasonable default size
+
+ int requiredSize;
+ fixed (char* pText = variable)
+ {
+ requiredSize = Interop.mincore.GetEnvironmentVariable(pText, blob, currentSize);
+ }
+
+ if (requiredSize == 0)
+ {
+ return null;
+ }
+
+ if (requiredSize <= currentSize)
+ {
+ return new string(blob);
+ }
+
+ // Fallback to using heap allocated buffers.
+ char[] newblob = null;
+ while (requiredSize > currentSize)
+ {
+ currentSize = requiredSize;
+ // need to retry since the environment variable might be changed
+ newblob = new char[currentSize];
+ fixed (char* pText = variable, pBlob = newblob)
+ {
+ requiredSize = Interop.mincore.GetEnvironmentVariable(pText, pBlob, currentSize);
+ }
+
+ if (requiredSize == 0)
+ {
+ return null;
+ }
+ }
+ // We should never end up with a null blob
+ Diagnostics.Debug.Assert(newblob != null);
+
+ return new string(newblob);
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.cs b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.cs
index 99e66c97208..7e0d9efad3e 100644
--- a/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.cs
+++ b/src/System.Private.CoreLib/src/System/Environment.EnvironmentVariables.cs
@@ -15,30 +15,11 @@
namespace System
{
+
public static partial class Environment
{
private const int MaxEnvVariableValueLength = 32767; // maximum length for environment variable name and value
- public static String ExpandEnvironmentVariables(String name)
- {
- if (name == null)
- throw new ArgumentNullException("name");
-
- // Environment variable accessors are not approved modern API.
- // Behave as if no variables are defined in this case.
- return name;
- }
-
- public static String GetEnvironmentVariable(String variable)
- {
- if (variable == null)
- throw new ArgumentNullException("variable");
-
- // Environment variable accessors are not approved modern API.
- // Behave as if the variable was not found in this case.
- return null;
- }
-
public static IDictionary GetEnvironmentVariables()
{
// Environment variable accessors are not approved modern API.