don't fail LongModuleFileNamesAreSupported test if we can't load assembly on x86...
authorAdam Sitnik <adam.sitnik@gmail.com>
Tue, 17 Aug 2021 07:49:41 +0000 (09:49 +0200)
committerGitHub <noreply@github.com>
Tue, 17 Aug 2021 07:49:41 +0000 (09:49 +0200)
src/libraries/System.Diagnostics.Process/tests/Interop.Unix.cs
src/libraries/System.Diagnostics.Process/tests/Interop.cs
src/libraries/System.Diagnostics.Process/tests/ProcessModuleTests.Windows.cs [new file with mode: 0644]
src/libraries/System.Diagnostics.Process/tests/ProcessModuleTests.cs
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj

index ddab95f..f6cb0ce 100644 (file)
@@ -1,16 +1,10 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using Microsoft.Win32.SafeHandles;
-using System.ComponentModel;
 using System.Runtime.InteropServices;
-using System.Security.Principal;
 
-namespace System.Diagnostics.Tests
+internal static partial class Interop
 {
-    internal static partial class Interop
-    {
-        [DllImport("libc")]
-        internal static extern int getsid(int pid);
-    }
+    [DllImport("libc")]
+    internal static extern int getsid(int pid);
 }
index 0bcbb62..949034c 100644 (file)
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using Microsoft.Win32.SafeHandles;
 using System.ComponentModel;
 using System.Runtime.InteropServices;
 using System.Security.Principal;
 
-namespace System.Diagnostics.Tests
+internal static partial class Interop
 {
-    internal static partial class Interop
+    [StructLayout(LayoutKind.Sequential, Size = 40)]
+    public struct PROCESS_MEMORY_COUNTERS
     {
-        [StructLayout(LayoutKind.Sequential, Size = 40)]
-        public struct PROCESS_MEMORY_COUNTERS
-        {
-            public uint cb;
-            public uint PageFaultCount;
-            public uint PeakWorkingSetSize;
-            public uint WorkingSetSize;
-            public uint QuotaPeakPagedPoolUsage;
-            public uint QuotaPagedPoolUsage;
-            public uint QuotaPeakNonPagedPoolUsage;
-            public uint QuotaNonPagedPoolUsage;
-            public uint PagefileUsage;
-            public uint PeakPagefileUsage;
-        }
+        public uint cb;
+        public uint PageFaultCount;
+        public uint PeakWorkingSetSize;
+        public uint WorkingSetSize;
+        public uint QuotaPeakPagedPoolUsage;
+        public uint QuotaPagedPoolUsage;
+        public uint QuotaPeakNonPagedPoolUsage;
+        public uint QuotaNonPagedPoolUsage;
+        public uint PagefileUsage;
+        public uint PeakPagefileUsage;
+    }
 
-        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
-        internal struct USER_INFO_1
-        {
-            public string usri1_name;
-            public string usri1_password;
-            public uint usri1_password_age;
-            public uint usri1_priv;
-            public string usri1_home_dir;
-            public string usri1_comment;
-            public uint usri1_flags;
-            public string usri1_script_path;
-        }
+    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+    internal struct USER_INFO_1
+    {
+        public string usri1_name;
+        public string usri1_password;
+        public uint usri1_password_age;
+        public uint usri1_priv;
+        public string usri1_home_dir;
+        public string usri1_comment;
+        public uint usri1_flags;
+        public string usri1_script_path;
+    }
 
-        [StructLayout(LayoutKind.Sequential)]
-        public struct TOKEN_USER
-        {
-            public SID_AND_ATTRIBUTES User;
-        }
+    [StructLayout(LayoutKind.Sequential)]
+    public struct TOKEN_USER
+    {
+        public SID_AND_ATTRIBUTES User;
+    }
 
-        [StructLayout(LayoutKind.Sequential)]
-        public struct SID_AND_ATTRIBUTES
-        {
-            public IntPtr Sid;
-            public int Attributes;
-        }
+    [StructLayout(LayoutKind.Sequential)]
+    public struct SID_AND_ATTRIBUTES
+    {
+        public IntPtr Sid;
+        public int Attributes;
+    }
 
-        [DllImport("kernel32.dll")]
-        public static extern bool GetProcessWorkingSetSizeEx(SafeProcessHandle hProcess, out IntPtr lpMinimumWorkingSetSize, out IntPtr lpMaximumWorkingSetSize, out uint flags);
+    [DllImport("kernel32.dll")]
+    public static extern bool GetProcessWorkingSetSizeEx(SafeProcessHandle hProcess, out IntPtr lpMinimumWorkingSetSize, out IntPtr lpMaximumWorkingSetSize, out uint flags);
 
-        [DllImport("kernel32.dll")]
-        internal static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);
+    [DllImport("kernel32.dll")]
+    internal static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);
 
-        [DllImport("kernel32.dll")]
-        public static extern int GetProcessId(SafeProcessHandle nativeHandle);
+    [DllImport("kernel32.dll")]
+    public static extern int GetProcessId(SafeProcessHandle nativeHandle);
 
-        [DllImport("kernel32.dll")]
-        internal static extern int GetConsoleCP();
+    [DllImport("kernel32.dll")]
+    internal static extern int GetConsoleCP();
 
-        [DllImport("kernel32.dll")]
-        internal static extern int GetConsoleOutputCP();
+    [DllImport("kernel32.dll")]
+    internal static extern int GetConsoleOutputCP();
 
-        [DllImport("kernel32.dll")]
-        internal static extern int SetConsoleCP(int codePage);
+    [DllImport("kernel32.dll")]
+    internal static extern int SetConsoleCP(int codePage);
 
-        [DllImport("kernel32.dll")]
-        internal static extern int SetConsoleOutputCP(int codePage);
+    [DllImport("kernel32.dll")]
+    internal static extern int SetConsoleOutputCP(int codePage);
 
-        [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
-        internal static extern uint NetUserAdd(string servername, uint level, ref USER_INFO_1 buf, out uint parm_err);
+    [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern uint NetUserAdd(string servername, uint level, ref USER_INFO_1 buf, out uint parm_err);
 
-        [DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
-        internal static extern uint NetUserDel(string servername, string username);
+    [DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
+    internal static extern uint NetUserDel(string servername, string username);
 
-        [DllImport("advapi32.dll")]
-        internal static extern bool OpenProcessToken(SafeProcessHandle ProcessHandle, uint DesiredAccess, out SafeProcessHandle TokenHandle);
+    [DllImport("advapi32.dll")]
+    internal static extern bool OpenProcessToken(SafeProcessHandle ProcessHandle, uint DesiredAccess, out SafeProcessHandle TokenHandle);
 
-        [DllImport("advapi32.dll")]
-        internal static extern bool GetTokenInformation(SafeProcessHandle TokenHandle, uint TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);
+    [DllImport("advapi32.dll")]
+    internal static extern bool GetTokenInformation(SafeProcessHandle TokenHandle, uint TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);
 
-        [DllImport("shell32.dll")]
-        internal static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
+    [DllImport("shell32.dll")]
+    internal static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
 
-        internal static void NetUserAdd(string username, string password)
-        {
-            USER_INFO_1 userInfo = new USER_INFO_1();
-            userInfo.usri1_name = username;
-            userInfo.usri1_password = password;
-            userInfo.usri1_priv = 1;
+    internal static void NetUserAdd(string username, string password)
+    {
+        USER_INFO_1 userInfo = new USER_INFO_1();
+        userInfo.usri1_name = username;
+        userInfo.usri1_password = password;
+        userInfo.usri1_priv = 1;
 
-            uint parm_err;
-            uint result = NetUserAdd(null, 1, ref userInfo, out parm_err);
+        uint parm_err;
+        uint result = NetUserAdd(null, 1, ref userInfo, out parm_err);
 
-            if (result != ExitCodes.NERR_Success)
-            {
-                // most likely result == ERROR_ACCESS_DENIED
-                // due to running without elevated privileges
-                throw new Win32Exception((int)result);
-            }
+        if (result != ExitCodes.NERR_Success)
+        {
+            // most likely result == ERROR_ACCESS_DENIED
+            // due to running without elevated privileges
+            throw new Win32Exception((int)result);
         }
+    }
 
-        internal static bool ProcessTokenToSid(SafeProcessHandle token, out SecurityIdentifier sid)
+    internal static bool ProcessTokenToSid(SafeProcessHandle token, out SecurityIdentifier sid)
+    {
+        bool ret = false;
+        sid = null;
+        IntPtr tu = IntPtr.Zero;
+        try
         {
-            bool ret = false;
-            sid = null;
-            IntPtr tu = IntPtr.Zero;
-            try
-            {
-                TOKEN_USER tokUser;
-                const int bufLength = 256;
-
-                tu = Marshal.AllocHGlobal(bufLength);
-                int cb = bufLength;
-                ret = GetTokenInformation(token, 1, tu, cb, ref cb);
-                if (ret)
-                {
-                    tokUser = Marshal.PtrToStructure<TOKEN_USER>(tu);
-                    sid = new SecurityIdentifier(tokUser.User.Sid);
-                }
-                return ret;
-            }
-            catch (Exception)
-            {
-                return false;
-            }
-            finally
+            TOKEN_USER tokUser;
+            const int bufLength = 256;
+
+            tu = Marshal.AllocHGlobal(bufLength);
+            int cb = bufLength;
+            ret = GetTokenInformation(token, 1, tu, cb, ref cb);
+            if (ret)
             {
-                if (tu != IntPtr.Zero)
-                    Marshal.FreeHGlobal(tu);
+                tokUser = Marshal.PtrToStructure<TOKEN_USER>(tu);
+                sid = new SecurityIdentifier(tokUser.User.Sid);
             }
+            return ret;
         }
-
-        internal static class ExitCodes
+        catch (Exception)
+        {
+            return false;
+        }
+        finally
         {
-            internal const uint NERR_Success = 0;
-            internal const uint NERR_UserNotFound = 2221;
+            if (tu != IntPtr.Zero)
+                Marshal.FreeHGlobal(tu);
         }
     }
+
+    internal static class ExitCodes
+    {
+        internal const uint NERR_Success = 0;
+        internal const uint NERR_UserNotFound = 2221;
+    }
 }
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessModuleTests.Windows.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessModuleTests.Windows.cs
new file mode 100644 (file)
index 0000000..ca5360e
--- /dev/null
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Diagnostics.Tests
+{
+    public partial class ProcessModuleTests : ProcessTestBase
+    {
+        [ConditionalFact(typeof(PathFeatures), nameof(PathFeatures.AreAllLongPathsAvailable))]
+        public void LongModuleFileNamesAreSupported()
+        {
+            // To be able to test Long Path support for ProcessModule.FileName we need a .dll that has a path > 260 chars.
+            // Since Long Paths support can be disabled (see the ConditionalFact attribute usage above),
+            // we just copy "LongName.dll" from bin to a temp directory with a long name and load it from there.
+            // Loading from new path is possible because the type exposed by the assembly is not referenced in any explicit way.
+            const string libraryName = "LongPath.dll";
+            const int minPathLength = 261;
+
+            string testBinPath = Path.GetDirectoryName(typeof(ProcessModuleTests).Assembly.Location);
+            string libraryToCopy = Path.Combine(testBinPath, libraryName);
+            Assert.True(File.Exists(libraryToCopy), $"{libraryName} was not present in bin folder '{testBinPath}'");
+
+            string directoryWithLongName = Path.Combine(TestDirectory, new string('a', Math.Max(1, minPathLength - TestDirectory.Length)));
+            Directory.CreateDirectory(directoryWithLongName);
+
+            string longNamePath = Path.Combine(directoryWithLongName, libraryName);
+            Assert.True(longNamePath.Length > minPathLength);
+
+            File.Copy(libraryToCopy, longNamePath);
+            Assert.True(File.Exists(longNamePath));
+
+            IntPtr moduleHandle = Interop.Kernel32.LoadLibrary(longNamePath);
+            if (moduleHandle == IntPtr.Zero)
+            {
+                Assert.Equal(126, Marshal.GetLastWin32Error()); // ERROR_MOD_NOT_FOUND
+                Assert.Equal(Architecture.X86, RuntimeInformation.ProcessArchitecture);
+                return; // we have failed to load the module on x86, we skip the rest of the test (it's best effort)
+            }
+
+            try
+            {
+                string[] modulePaths = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().Select(module => module.FileName).ToArray();
+                Assert.Contains(longNamePath, modulePaths);
+            }
+            finally
+            {
+                Interop.Kernel32.FreeLibrary(moduleHandle);
+            }
+        }
+    }
+}
index 59fae43..33f8471 100644 (file)
@@ -1,15 +1,13 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System.IO;
 using System.Linq;
-using System.Reflection;
 using Microsoft.DotNet.RemoteExecutor;
 using Xunit;
 
 namespace System.Diagnostics.Tests
 {
-    public class ProcessModuleTests : ProcessTestBase
+    public partial class ProcessModuleTests : ProcessTestBase
     {
         [Fact]
         public void TestModuleProperties()
@@ -91,40 +89,5 @@ namespace System.Diagnostics.Tests
             process.Dispose();
             Assert.Equal(expectedCount, disposedCount);
         }
-
-        public static bool Is_LongModuleFileNamesAreSupported_TestEnabled
-            => PathFeatures.AreAllLongPathsAvailable() // we want to test long paths
-            && !PlatformDetection.IsMonoRuntime // Assembly.LoadFile used the way this test is implemented fails on Mono
-            && OperatingSystem.IsWindowsVersionAtLeast(8); // it's specific to Windows and does not work on Windows 7
-
-        [ConditionalFact(typeof(ProcessModuleTests), nameof(Is_LongModuleFileNamesAreSupported_TestEnabled))]
-        public void LongModuleFileNamesAreSupported()
-        {
-            // To be able to test Long Path support for ProcessModule.FileName we need a .dll that has a path > 260 chars.
-            // Since Long Paths support can be disabled (see the ConditionalFact attribute usage above),
-            // we just copy "LongName.dll" from bin to a temp directory with a long name and load it from there.
-            // Loading from new path is possible because the type exposed by the assembly is not referenced in any explicit way.
-            const string libraryName = "LongPath.dll";
-            const int minPathLength = 261;
-
-            string testBinPath = Path.GetDirectoryName(typeof(ProcessModuleTests).Assembly.Location);
-            string libraryToCopy = Path.Combine(testBinPath, libraryName);
-            Assert.True(File.Exists(libraryToCopy), $"{libraryName} was not present in bin folder '{testBinPath}'");
-
-            string directoryWithLongName = Path.Combine(TestDirectory, new string('a', Math.Max(1, minPathLength - TestDirectory.Length)));
-            Directory.CreateDirectory(directoryWithLongName);
-
-            string longNamePath = Path.Combine(directoryWithLongName, libraryName);
-            Assert.True(longNamePath.Length > minPathLength);
-
-            File.Copy(libraryToCopy, longNamePath);
-            Assert.True(File.Exists(longNamePath));
-
-            Assembly loaded = Assembly.LoadFile(longNamePath);
-            Assert.Equal(longNamePath, loaded.Location);
-
-            string[] modulePaths = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().Select(module => module.FileName).ToArray();
-            Assert.Contains(longNamePath, modulePaths);
-        }
     }
 }
index 776b696..bfcfb2c 100644 (file)
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <DefineConstants Condition="'$(TargetsWindows)' == 'true'">$(DefineConstants);TargetsWindows</DefineConstants>
     <Compile Include="AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+    <Compile Include="ProcessModuleTests.Windows.cs" />
     <Compile Include="ProcessTests.Windows.cs" />
     <Compile Include="ProcessThreadTests.Windows.cs" />
     <Compile Include="$(CoreLibSharedDir)System\PasteArguments.Windows.cs"
              Link="System\PasteArguments.Windows.cs" />
+    <Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
+         Link="Common\Interop\Windows\Interop.Libraries.cs" />
+    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LoadLibrary.cs"
+         Link="Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs" />
+    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.FreeLibrary.cs"
+             Link="Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
   </ItemGroup>
   <ItemGroup Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true'">
     <Compile Include="Interop.Unix.cs" />