From c5db003e27e39522eeb7ccc4d8db8f7e4981cfcf Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Tue, 31 Dec 2019 17:24:23 -0800 Subject: [PATCH 01/15] Implement Environment.UserInteractive --- .../PinvokeAnalyzerExceptionList.analyzerdata | 4 ++ .../Windows/User32/Interop.Constants.cs | 2 + .../src/Microsoft.Win32.SystemEvents.csproj | 9 ---- .../src/Microsoft/Win32/SystemEvents.cs | 41 +------------------ .../Windows/User32/Interop.Constants.cs | 12 ------ .../System.Private.CoreLib.Shared.projitems | 5 ++- .../src/System/Environment.Unix.cs | 2 + .../src/System/Environment.Windows.cs | 22 ++++++++++ .../src/System/Environment.cs | 2 - .../tests/System/EnvironmentTests.cs | 17 +++++++- 10 files changed, 51 insertions(+), 65 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/Interop/Windows/User32/Interop.Constants.cs diff --git a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata index 4bbdccae19d803..5d45345491c369 100644 --- a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata +++ b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata @@ -1,3 +1,7 @@ normaliz.dll!IsNormalizedString normaliz.dll!NormalizeString + + +user32.dll!GetProcessWindowStation +user32.dll!GetUserObjectInformationW diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs index 45fce95f67a569..5566ba2b2802fd 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs @@ -225,5 +225,7 @@ internal partial class User32 public const int UOI_FLAGS = 1; + public const int HWND_BROADCAST = 0xffff; + } } diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 558e3f4cb9bc4e..d780917cc61d32 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -30,12 +30,6 @@ Common\Interop\Windows\User32\Interop.GetClassInfo.cs - - Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs - - - Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs - Common\Interop\Windows\User32\Interop.GetWindowThreadProcessId.cs @@ -87,9 +81,6 @@ Common\Interop\Windows\User32\Interop.UnregisterClass.cs - - Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs - Common\Interop\Windows\User32\Interop.WNDCLASS.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 6e24b137a806d6..e766c17d8c841a 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -68,45 +68,6 @@ private SystemEvents() // This class is intended to be static, but predates static classes (which were introduced in C# 2.0). } - // stole from SystemInformation... if we get SystemInformation moved - // to somewhere that we can use it... rip this! - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - private static volatile IntPtr s_processWinStation = IntPtr.Zero; - private static volatile bool s_isUserInteractive = false; - private static unsafe bool UserInteractive - { - get - { - if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) - { - IntPtr hwinsta = IntPtr.Zero; - - hwinsta = Interop.User32.GetProcessWindowStation(); - if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta) - { - s_isUserInteractive = true; - - int lengthNeeded = 0; - Interop.User32.USEROBJECTFLAGS flags = default; - - if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref lengthNeeded)) - { - if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) - { - s_isUserInteractive = false; - } - } - s_processWinStation = hwinsta; - } - } - else - { - s_isUserInteractive = true; - } - return s_isUserInteractive; - } - } - /// /// Occurs when the display settings are changing. /// @@ -476,7 +437,7 @@ private static void EnsureSystemEvents(bool requireHandle) { // If we are creating system events on a thread declared as STA, then // just share the thread. - if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) + if (!Environment.UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { SystemEvents systemEvents = new SystemEvents(); systemEvents.Initialize(); diff --git a/src/libraries/System.Private.CoreLib/src/Interop/Windows/User32/Interop.Constants.cs b/src/libraries/System.Private.CoreLib/src/Interop/Windows/User32/Interop.Constants.cs deleted file mode 100644 index a48329fb6b191a..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/Interop/Windows/User32/Interop.Constants.cs +++ /dev/null @@ -1,12 +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. - -internal static partial class Interop -{ - internal static partial class User32 - { - internal const int HWND_BROADCAST = 0xffff; - internal const int WM_SETTINGCHANGE = 0x001A; - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 3e9aacec26a2b4..3857115effe93c 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1173,9 +1173,12 @@ - + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs index d733feb5316221..3a51a58fc91a3a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs @@ -17,6 +17,8 @@ public static partial class Environment { private static Func? s_directoryCreateDirectory; + public static bool UserInteractive => true; + private static string CurrentDirectoryCore { get => Interop.Sys.GetCwd(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index 17a49080d661a3..b55960ef6669b1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -122,6 +122,28 @@ public static string SystemDirectory } } + public static bool UserInteractive + { + get + { + // Per documentation of GetProcessWindowStation, this handle should not be closed + IntPtr hwinsta = Interop.User32.GetProcessWindowStation(); + if (hwinsta == IntPtr.Zero) + { + return false; // eg., Windows Nano + } + + Interop.User32.USEROBJECTFLAGS flags = default; + if (!Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, Marshal.SizeOf(flags), ref _)) + { + return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); + } + + // If we can't determine, return true optimistically + return true; + } + } + public static unsafe long WorkingSet { get diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 1454f1d56e4040..194ae6099bb513 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -138,8 +138,6 @@ public static OperatingSystem OSVersion } } - public static bool UserInteractive => true; - public static Version Version { get diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index ea33c8e9eda47e..edd5e0e860109f 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -165,11 +165,26 @@ public void SystemPageSize_Valid() } [Fact] - public void UserInteractive_True() + [PlatformSpecific(TestPlatforms.AnyUnix)] + public void UserInteractive_Unix_True() { Assert.True(Environment.UserInteractive); } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void UserInteractive_Windows_DoesNotThrow() + { + var _ = Environment.UserInteractive; // Does not throw + } + + [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer)] + public void UserInteractive_Windows_DoesNotThrow() + { + Assert.False(Environment.UserInteractive); + } + [Fact] public void Version_Valid() { From 6bfe1f886078208a6d8566d5facdc369935b1b45 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Tue, 31 Dec 2019 17:37:57 -0800 Subject: [PATCH 02/15] typo --- .../tests/System/EnvironmentTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index edd5e0e860109f..a496467910afdd 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -178,9 +178,8 @@ public void UserInteractive_Windows_DoesNotThrow() var _ = Environment.UserInteractive; // Does not throw } - [Fact] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer)] - public void UserInteractive_Windows_DoesNotThrow() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer))] + public void UserInteractive_WindowsNano() { Assert.False(Environment.UserInteractive); } From d250a1fd17c7e0e1063a9d3065904c49710ba4f2 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Tue, 31 Dec 2019 17:42:41 -0800 Subject: [PATCH 03/15] rename --- .../src/System/Environment.Windows.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index b55960ef6669b1..9b8f1d8f214038 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -127,14 +127,14 @@ public static bool UserInteractive get { // Per documentation of GetProcessWindowStation, this handle should not be closed - IntPtr hwinsta = Interop.User32.GetProcessWindowStation(); - if (hwinsta == IntPtr.Zero) + IntPtr handle = Interop.User32.GetProcessWindowStation(); + if (handle == IntPtr.Zero) { return false; // eg., Windows Nano } Interop.User32.USEROBJECTFLAGS flags = default; - if (!Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, Marshal.SizeOf(flags), ref _)) + if (!Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, Marshal.SizeOf(flags), ref _)) { return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); } From 85b403bd74750cef120207db800771811a0c2980 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 10:02:15 -0800 Subject: [PATCH 04/15] Revert M.Win32.SE --- .../src/Microsoft.Win32.SystemEvents.csproj | 9 ++++ .../src/Microsoft/Win32/SystemEvents.cs | 41 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index d780917cc61d32..558e3f4cb9bc4e 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -30,6 +30,12 @@ Common\Interop\Windows\User32\Interop.GetClassInfo.cs + + Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs + + + Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs + Common\Interop\Windows\User32\Interop.GetWindowThreadProcessId.cs @@ -81,6 +87,9 @@ Common\Interop\Windows\User32\Interop.UnregisterClass.cs + + Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs + Common\Interop\Windows\User32\Interop.WNDCLASS.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index e766c17d8c841a..6e24b137a806d6 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -68,6 +68,45 @@ private SystemEvents() // This class is intended to be static, but predates static classes (which were introduced in C# 2.0). } + // stole from SystemInformation... if we get SystemInformation moved + // to somewhere that we can use it... rip this! + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + private static volatile IntPtr s_processWinStation = IntPtr.Zero; + private static volatile bool s_isUserInteractive = false; + private static unsafe bool UserInteractive + { + get + { + if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) + { + IntPtr hwinsta = IntPtr.Zero; + + hwinsta = Interop.User32.GetProcessWindowStation(); + if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta) + { + s_isUserInteractive = true; + + int lengthNeeded = 0; + Interop.User32.USEROBJECTFLAGS flags = default; + + if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref lengthNeeded)) + { + if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) + { + s_isUserInteractive = false; + } + } + s_processWinStation = hwinsta; + } + } + else + { + s_isUserInteractive = true; + } + return s_isUserInteractive; + } + } + /// /// Occurs when the display settings are changing. /// @@ -437,7 +476,7 @@ private static void EnsureSystemEvents(bool requireHandle) { // If we are creating system events on a thread declared as STA, then // just share the thread. - if (!Environment.UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) + if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { SystemEvents systemEvents = new SystemEvents(); systemEvents.Initialize(); From ebaf64c0848573d09fbec844da6cd65655c19a0b Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 11:07:10 -0800 Subject: [PATCH 05/15] CR feedback --- .../src/Microsoft/Win32/SystemEvents.cs | 32 ++++++++----------- .../src/System/Environment.Windows.cs | 15 ++++----- .../tests/ServiceBaseTests.cs | 1 + .../TestService.cs | 4 +++ 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 6e24b137a806d6..73861ae7e7b980 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -77,32 +77,26 @@ private static unsafe bool UserInteractive { get { - if (Environment.OSVersion.Platform == System.PlatformID.Win32NT) - { - IntPtr hwinsta = IntPtr.Zero; + IntPtr hwinsta = IntPtr.Zero; - hwinsta = Interop.User32.GetProcessWindowStation(); - if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta) - { - s_isUserInteractive = true; + hwinsta = Interop.User32.GetProcessWindowStation(); + if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta) + { + s_isUserInteractive = true; - int lengthNeeded = 0; - Interop.User32.USEROBJECTFLAGS flags = default; + int lengthNeeded = 0; + Interop.User32.USEROBJECTFLAGS flags = default; - if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref lengthNeeded)) + if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref lengthNeeded)) + { + if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) { - if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) - { - s_isUserInteractive = false; - } + s_isUserInteractive = false; } - s_processWinStation = hwinsta; } + s_processWinStation = hwinsta; } - else - { - s_isUserInteractive = true; - } + return s_isUserInteractive; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index 9b8f1d8f214038..906a346640ea84 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -128,18 +128,17 @@ public static bool UserInteractive { // Per documentation of GetProcessWindowStation, this handle should not be closed IntPtr handle = Interop.User32.GetProcessWindowStation(); - if (handle == IntPtr.Zero) + if (handle != IntPtr.Zero) { - return false; // eg., Windows Nano - } - - Interop.User32.USEROBJECTFLAGS flags = default; - if (!Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, Marshal.SizeOf(flags), ref _)) - { - return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); + Interop.User32.USEROBJECTFLAGS flags = default; + if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, sizeof(flags), ref _)) + { + return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); + } } // If we can't determine, return true optimistically + // This will include cases like Windows Nano which do not expose WindowStations return true; } } diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs index c6c43dce26b5dd..bcd93141cc976c 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs @@ -142,6 +142,7 @@ public void TestOnExecuteCustomCommand() ServiceController controller = ConnectToServer(); controller.ExecuteCommand(128); + // If we get 129, then Environment.UserInteractive was unexpectedly true Assert.Equal(128, _testService.GetByte()); controller.Stop(); diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs index c50f129e8ea0bf..daf6845b0f3ecf 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs @@ -43,6 +43,10 @@ protected override void OnContinue() protected override void OnCustomCommand(int command) { base.OnCustomCommand(command); + + if (Environment.UserInteractive) // verify this is false + command++; + WriteStreamAsync(PipeMessageByteCode.OnCustomCommand, command).Wait(); } From e6ea75b7925f1aa5cb49ace5c8878f5fc86ac768 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 12:26:52 -0800 Subject: [PATCH 06/15] CR feedback: --- .../System.Private.CoreLib/src/System/Environment.Windows.cs | 5 +++-- .../tests/System/EnvironmentTests.cs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index 906a346640ea84..7ccc31b68fa638 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -122,7 +122,7 @@ public static string SystemDirectory } } - public static bool UserInteractive + public static unsafe bool UserInteractive { get { @@ -131,7 +131,8 @@ public static bool UserInteractive if (handle != IntPtr.Zero) { Interop.User32.USEROBJECTFLAGS flags = default; - if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, sizeof(flags), ref _)) + int dummy = 0; + if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) { return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); } diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index a496467910afdd..b5856e9fa719ed 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -175,13 +175,14 @@ public void UserInteractive_Unix_True() [PlatformSpecific(TestPlatforms.Windows)] public void UserInteractive_Windows_DoesNotThrow() { - var _ = Environment.UserInteractive; // Does not throw + Environment.UserInteractive; // Does not throw } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer))] public void UserInteractive_WindowsNano() { - Assert.False(Environment.UserInteractive); + // Defaults to true on Nano, because it doesn't expose WindowStations + Assert.True(Environment.UserInteractive); } [Fact] From 6883f08f24ac068bac741ff56a21d9a721353f91 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 14:33:21 -0800 Subject: [PATCH 07/15] typo --- .../System.Runtime.Extensions/tests/System/EnvironmentTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index b5856e9fa719ed..26571f9697a5a8 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -175,7 +175,7 @@ public void UserInteractive_Unix_True() [PlatformSpecific(TestPlatforms.Windows)] public void UserInteractive_Windows_DoesNotThrow() { - Environment.UserInteractive; // Does not throw + var dummy = Environment.UserInteractive; // Does not throw } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer))] From 2b0e0f43c6f54aeba9f224e5039ef8ff4ed80adc Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 16:32:26 -0800 Subject: [PATCH 08/15] Fix test --- .../src/Microsoft/Win32/SystemEvents.cs | 4 +--- .../tests/ServiceBaseTests.cs | 12 ++++++++++-- .../TestService.cs | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 73861ae7e7b980..ae44a710cb270d 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -77,9 +77,7 @@ private static unsafe bool UserInteractive { get { - IntPtr hwinsta = IntPtr.Zero; - - hwinsta = Interop.User32.GetProcessWindowStation(); + IntPtr hwinsta = Interop.User32.GetProcessWindowStation(); if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta) { s_isUserInteractive = true; diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs index bcd93141cc976c..eaeafed3c1cc64 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs @@ -142,8 +142,16 @@ public void TestOnExecuteCustomCommand() ServiceController controller = ConnectToServer(); controller.ExecuteCommand(128); - // If we get 129, then Environment.UserInteractive was unexpectedly true - Assert.Equal(128, _testService.GetByte()); + // Response from test service: + // 128 => Environment.UserInteractive == false + // 129 => Environment.UserInteractive == true + // + // On Windows Nano and other SKU that do not expose Window Stations, Environment.UserInteractive + // will always return true, even within a service process. + // Otherwise, we expect it to be false. + // (This is the only place we verify Environment.UserInteractive can return false) + byte expected = PlatformDetection.HasWindowsShell ? 128 : 129; + Assert.Equal(expected, _testService.GetByte()); controller.Stop(); Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte()); diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs index daf6845b0f3ecf..604289322f9ce8 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs @@ -44,7 +44,7 @@ protected override void OnCustomCommand(int command) { base.OnCustomCommand(command); - if (Environment.UserInteractive) // verify this is false + if (Environment.UserInteractive) // see ServiceBaseTests.TestOnExecuteCustomCommand() command++; WriteStreamAsync(PipeMessageByteCode.OnCustomCommand, command).Wait(); From fcc553b0e254ad828580a1b62afaba97dea6fb7e Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 16:45:41 -0800 Subject: [PATCH 09/15] GUOI declaration --- .../Windows/User32/Interop.GetUserObjectInformation.cs | 2 +- .../System.Private.CoreLib/src/System/Environment.Windows.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetUserObjectInformation.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetUserObjectInformation.cs index 85205d3570a1ee..3144de671e3042 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.GetUserObjectInformation.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetUserObjectInformation.cs @@ -10,6 +10,6 @@ internal partial class Interop internal partial class User32 { [DllImport(Libraries.User32, SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - public static extern bool GetUserObjectInformationW(IntPtr hObj, int nIndex, ref USEROBJECTFLAGS pvBuffer, int nLength, ref int lpnLengthNeeded); + public static extern unsafe bool GetUserObjectInformationW(IntPtr hObj, int nIndex, void* pvBuffer, uint nLength, ref uint lpnLengthNeeded); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index 7ccc31b68fa638..caae0d88f2184f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -131,8 +131,8 @@ public static unsafe bool UserInteractive if (handle != IntPtr.Zero) { Interop.User32.USEROBJECTFLAGS flags = default; - int dummy = 0; - if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) + uint dummy = 0; + if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, (void*)&flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) { return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); } From b0e6f89bd151bb97227714f26b046253e43ba50c Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Thu, 2 Jan 2020 17:15:46 -0800 Subject: [PATCH 10/15] Another typo! --- .../tests/ServiceBaseTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs index eaeafed3c1cc64..8b62f638a9aff3 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs @@ -150,7 +150,7 @@ public void TestOnExecuteCustomCommand() // will always return true, even within a service process. // Otherwise, we expect it to be false. // (This is the only place we verify Environment.UserInteractive can return false) - byte expected = PlatformDetection.HasWindowsShell ? 128 : 129; + byte expected = PlatformDetection.HasWindowsShell ? (byte)128 : (byte)129; Assert.Equal(expected, _testService.GetByte()); controller.Stop(); From 7a7d8ffe7f4fbedc6cd7ccb48bed9d3648f693a8 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Fri, 3 Jan 2020 10:42:21 -0800 Subject: [PATCH 11/15] Fix build break --- .../System.Private.CoreLib.csproj | 2 +- .../src/Microsoft/Win32/SystemEvents.cs | 4 ++-- .../src/System.Private.CoreLib.Shared.projitems | 13 ++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index b0832f83c93537..aaaaaea6173a23 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -291,7 +291,7 @@ Common\Interop\Windows\Kernel32\Interop.HandleTypes.cs - Interop\Windows\Kernel32\Interop.LocalAlloc.cs + Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs Common\Interop\Windows\Ole32\Interop.CoTaskMemAlloc.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index ae44a710cb270d..661127845a966f 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -82,10 +82,10 @@ private static unsafe bool UserInteractive { s_isUserInteractive = true; - int lengthNeeded = 0; + uint dummy = 0; Interop.User32.USEROBJECTFLAGS flags = default; - if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, ref flags, sizeof(Interop.User32.USEROBJECTFLAGS), ref lengthNeeded)) + if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, (void*)&flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) { if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) { diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 41360b2000db4f..62b5d3583c5736 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1325,11 +1325,22 @@ Common\Interop\Windows\Shell32\Interop.SHGetKnownFolderPath.cs - + + Common\Interop\Windows\User32\Interop.Constants.cs + Common\Interop\Windows\User32\Interop.LoadString.cs + + Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs + + + Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs + + + Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs + From f52a075a23074f9f3ea89ade26033f4712f8789c Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 3 Jan 2020 14:26:19 -0800 Subject: [PATCH 12/15] Update src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Co-Authored-By: Jan Kotas --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 62b5d3583c5736..b5a1b5da117a0c 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1338,7 +1338,7 @@ Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs - + Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs From 65f5813c2ef9d89c16add60be73b8f6023b0a3db Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 3 Jan 2020 14:26:26 -0800 Subject: [PATCH 13/15] Update src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Co-Authored-By: Jan Kotas --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b5a1b5da117a0c..91cd71b9f49213 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1335,7 +1335,7 @@ Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs - + Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs From 960cbc7ade1f9938e5a08262b7920a3c784988db Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 3 Jan 2020 14:26:32 -0800 Subject: [PATCH 14/15] Update src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Co-Authored-By: Jan Kotas --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 91cd71b9f49213..cf8edf1de1e00a 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1332,7 +1332,7 @@ Common\Interop\Windows\User32\Interop.LoadString.cs - + Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs From 444554bc23a81077c4ad3b4acb3a69a9c47d9af3 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Fri, 3 Jan 2020 14:28:49 -0800 Subject: [PATCH 15/15] CR feedback --- .../System.Private.CoreLib/System.Private.CoreLib.csproj | 2 +- .../src/Microsoft/Win32/SystemEvents.cs | 2 +- .../src/System.Private.CoreLib.Shared.projitems | 6 +++--- .../src/System/Environment.Windows.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index aaaaaea6173a23..b0832f83c93537 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -291,7 +291,7 @@ Common\Interop\Windows\Kernel32\Interop.HandleTypes.cs - Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs + Interop\Windows\Kernel32\Interop.LocalAlloc.cs Common\Interop\Windows\Ole32\Interop.CoTaskMemAlloc.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 661127845a966f..ca6c3b5c38bd6e 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -85,7 +85,7 @@ private static unsafe bool UserInteractive uint dummy = 0; Interop.User32.USEROBJECTFLAGS flags = default; - if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, (void*)&flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) + if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, &flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) { if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0) { diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 62b5d3583c5736..8edce0c2f4c7d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1332,13 +1332,13 @@ Common\Interop\Windows\User32\Interop.LoadString.cs - + Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs - + Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs - + Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs index caae0d88f2184f..98c913a09804e1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Windows.cs @@ -132,7 +132,7 @@ public static unsafe bool UserInteractive { Interop.User32.USEROBJECTFLAGS flags = default; uint dummy = 0; - if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, (void*)&flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) + if (Interop.User32.GetUserObjectInformationW(handle, Interop.User32.UOI_FLAGS, &flags, (uint)sizeof(Interop.User32.USEROBJECTFLAGS), ref dummy)) { return ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0); }