From 9587a2d646049fcb2a94461212b1fbbff06bf1a0 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 25 Oct 2018 02:20:08 -0700 Subject: [PATCH 1/6] Add a manifest to dotnet.exe with supported version of Windows Also remove any manifest from apphost.exe as it will get the one from the app when it's used --- src/corehost/cli/apphost/CMakeLists.txt | 7 +++++++ src/corehost/cli/dotnet/CMakeLists.txt | 3 ++- src/corehost/cli/dotnet/dotnet.manifest | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/corehost/cli/dotnet/dotnet.manifest diff --git a/src/corehost/cli/apphost/CMakeLists.txt b/src/corehost/cli/apphost/CMakeLists.txt index cc610cd119..4dac1f30ec 100644 --- a/src/corehost/cli/apphost/CMakeLists.txt +++ b/src/corehost/cli/apphost/CMakeLists.txt @@ -26,3 +26,10 @@ include(../exe.cmake) add_definitions(-DFEATURE_APPHOST=1) install_library_and_symbols (apphost) + +# Disable manifest generation into the file .exe on Windows +if(WIN32) + set_property(TARGET ${PROJECT_NAME} PROPERTY + LINK_FLAGS "/MANIFEST:NO" + ) +endif() \ No newline at end of file diff --git a/src/corehost/cli/dotnet/CMakeLists.txt b/src/corehost/cli/dotnet/CMakeLists.txt index 5b3b392666..d071365d37 100644 --- a/src/corehost/cli/dotnet/CMakeLists.txt +++ b/src/corehost/cli/dotnet/CMakeLists.txt @@ -5,7 +5,8 @@ cmake_minimum_required (VERSION 2.6) project(dotnet) set(DOTNET_HOST_EXE_NAME "dotnet") set(SOURCES - ../fxr/fx_ver.cpp) + ../fxr/fx_ver.cpp + dotnet.manifest) include(../exe.cmake) install_library_and_symbols (dotnet) diff --git a/src/corehost/cli/dotnet/dotnet.manifest b/src/corehost/cli/dotnet/dotnet.manifest new file mode 100644 index 0000000000..caf8501d6a --- /dev/null +++ b/src/corehost/cli/dotnet/dotnet.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file From 667f9c0ce7b40c5ccd204e7b80dc2d32d020d600 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 25 Oct 2018 02:25:30 -0700 Subject: [PATCH 2/6] Only add the manifest on Windows --- src/corehost/cli/dotnet/CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/corehost/cli/dotnet/CMakeLists.txt b/src/corehost/cli/dotnet/CMakeLists.txt index d071365d37..fa666cf57f 100644 --- a/src/corehost/cli/dotnet/CMakeLists.txt +++ b/src/corehost/cli/dotnet/CMakeLists.txt @@ -5,8 +5,13 @@ cmake_minimum_required (VERSION 2.6) project(dotnet) set(DOTNET_HOST_EXE_NAME "dotnet") set(SOURCES - ../fxr/fx_ver.cpp - dotnet.manifest) + ../fxr/fx_ver.cpp) + +if(WIN32) + list(APPEND SOURCES + dotnet.manifest) +endif() + include(../exe.cmake) install_library_and_symbols (dotnet) From 255b5692536852f5f432f4e9006aee9bcbc8c7fb Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Fri, 26 Oct 2018 06:22:02 -0700 Subject: [PATCH 3/6] Add automated test for the dotnet.exe manifest and supported OSes --- .../TestWindowsOsShimsApp/Program.cs | 149 ++++++++++++++++++ .../TestWindowsOsShimsApp.csproj | 11 ++ .../GivenThatICareAboutWindowsOsShims.cs | 49 ++++++ 3 files changed, 209 insertions(+) create mode 100644 src/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs create mode 100644 src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj create mode 100644 src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs diff --git a/src/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs new file mode 100644 index 0000000000..79238addbf --- /dev/null +++ b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs @@ -0,0 +1,149 @@ +using System; +using System.Runtime.InteropServices; + +namespace TestWindowsOsShimsApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + Console.WriteLine(string.Join(Environment.NewLine, args)); + Console.WriteLine($"Framework Version:{GetFrameworkVersionFromAppDomain()}"); + + #if WINDOWS + Version osVersion = RtlGetVersion(); + if (osVersion == null) + { + Console.WriteLine("Failed to get OS version through RtlGetVersion."); + } + else + { + Console.WriteLine($"Detected true OS version: {osVersion.Major}.{osVersion.Minor}"); + if (OsVersionIsNewerThan(osVersion)) + { + Console.WriteLine($"Reported OS version is newer or equal to the true OS version - no shims."); + } + else + { + Console.WriteLine($"Reported OS version is lower than the true OS version - shims in use."); + } + } + #endif + } + + private static string GetFrameworkVersionFromAppDomain() + { + return System.AppDomain.CurrentDomain.GetData("FX_PRODUCT_VERSION") as string; + } + +#if WINDOWS + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct OSVERSIONINFOEX + { + + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] // + internal string szCSDVersion; + internal ushort wServicePackMajor; + internal ushort wServicePackMinor; + internal ushort wSuiteMask; + internal byte wProductType; + internal byte wReserved; + } + + [Flags] + enum ConditionMask : byte + { + VER_EQUAL = 1, + VER_GREATER = 2, + VER_GREATER_EQUAL = 3, + VER_LESS = 4, + VER_LESS_EQUAL = 5, + VER_AND = 6, + VER_OR = 7 + } + + [Flags] + enum TypeMask : uint + { + VER_MINORVERSION = 0x0000001, + VER_MAJORVERSION = 0x0000002, + VER_BUILDNUMBER = 0x0000004, + VER_PLATFORMID = 0x0000008, + VER_SERVICEPACKMINOR = 0x0000010, + VER_SERVICEPACKMAJOR = 0x0000020, + VER_SUITENAME = 0x0000040, + VER_PRODUCT_TYPE = 0x0000080 + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal unsafe struct RTL_OSVERSIONINFOEX + { + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + internal fixed char szCSDVersion[128]; + } + + [DllImport("ntdll.dll", ExactSpelling=true)] + private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool VerifyVersionInfo(ref OSVERSIONINFOEX lpVersionInfo, TypeMask dwTypeMask, ulong dwlConditionMask); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern ulong VerSetConditionMask(ulong dwlConditionMask, TypeMask dwTypeBitMask, ConditionMask dwConditionMask); + + internal unsafe static int RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) + { + osvi = new RTL_OSVERSIONINFOEX(); + osvi.dwOSVersionInfoSize = (uint)sizeof(RTL_OSVERSIONINFOEX); + return RtlGetVersion(ref osvi); + } + + internal static Version RtlGetVersion() + { + if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0) + { + return new Version((int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion); + } + else + { + return null; + } + } + + internal static bool OsVersionIsNewerThan(Version osVersion) + { + // check if newer than + OSVERSIONINFOEX osv = new OSVERSIONINFOEX() + { + dwOSVersionInfoSize = (uint)Marshal.SizeOf(), + dwMajorVersion = (uint)osVersion.Major, + dwMinorVersion = (uint)osVersion.Minor + }; + + var conditionMask = 0uL; + conditionMask = VerSetConditionMask(conditionMask, TypeMask.VER_MAJORVERSION, ConditionMask.VER_GREATER_EQUAL); + conditionMask = VerSetConditionMask(conditionMask, TypeMask.VER_MINORVERSION, ConditionMask.VER_GREATER_EQUAL); + + if (VerifyVersionInfo(ref osv, TypeMask.VER_MAJORVERSION | TypeMask.VER_MINORVERSION, conditionMask)) + { + return true; + } + else + { + return false; + } + } +#endif + } +} diff --git a/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj new file mode 100644 index 0000000000..849498a7a3 --- /dev/null +++ b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj @@ -0,0 +1,11 @@ + + + + $(NETCoreAppFramework) + Exe + $(MNAVersion) + WINDOWS;$(DefineConstants) + true + + + diff --git a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs new file mode 100644 index 0000000000..c388bfc26d --- /dev/null +++ b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs @@ -0,0 +1,49 @@ +using System; +using Xunit; + +namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.WindowsOsShims +{ + public class GivenThatICareAboutWindowsOsShims : IClassFixture + { + private SharedTestState sharedTestState; + + public GivenThatICareAboutWindowsOsShims(SharedTestState fixture) + { + sharedTestState = fixture; + } + + [Fact] + public void MuxerRunsPortableAppWithoutWindowsOsShims() + { + TestProjectFixture portableAppFixture = sharedTestState.PortableTestWindowsOsShimsAppFixture.Copy(); + + portableAppFixture.BuiltDotnet.Exec(portableAppFixture.TestProject.AppDll) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Reported OS version is newer or equal to the true OS version - no shims."); + } + + public class SharedTestState : IDisposable + { + private static RepoDirectoriesProvider RepoDirectories { get; set; } + + public TestProjectFixture PortableTestWindowsOsShimsAppFixture { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + + PortableTestWindowsOsShimsAppFixture = new TestProjectFixture("TestWindowsOsShimsApp", RepoDirectories) + .EnsureRestored(RepoDirectories.CorehostPackages) + .PublishProject(); + } + + public void Dispose() + { + //PortableTestWindowsOsShimsAppFixture.Dispose(); + } + } + } +} From cdda072b7e7bdf373e7642e699cb0abeb790bf14 Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Fri, 26 Oct 2018 07:22:42 -0700 Subject: [PATCH 4/6] Add a comment about inability to test apphost for now. --- .../TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj | 1 + .../HostActivationTests/GivenThatICareAboutWindowsOsShims.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj index 849498a7a3..70d4c67081 100644 --- a/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj +++ b/src/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj @@ -2,6 +2,7 @@ $(NETCoreAppFramework) + $(TestTargetRid) Exe $(MNAVersion) WINDOWS;$(DefineConstants) diff --git a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs index c388bfc26d..b22e0b45d9 100644 --- a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs +++ b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs @@ -25,6 +25,9 @@ public void MuxerRunsPortableAppWithoutWindowsOsShims() .And.HaveStdOutContaining("Reported OS version is newer or equal to the true OS version - no shims."); } + // Testing the standalone version (apphost) would require to make a copy of the entire SDK + // and overwrite the apphost.exe in it. Currently this is just too expensive for one test (160MB of data). + public class SharedTestState : IDisposable { private static RepoDirectoriesProvider RepoDirectories { get; set; } From 4dc89222bc68c5029bb57b29800f44c2cdaab78e Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Mon, 29 Oct 2018 04:00:30 -0700 Subject: [PATCH 5/6] Make the test only run on Windows as this is Windows only feature. --- .../GivenThatICareAboutWindowsOsShims.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs index b22e0b45d9..dca8f2c93c 100644 --- a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs +++ b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; using Xunit; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.WindowsOsShims @@ -15,6 +16,12 @@ public GivenThatICareAboutWindowsOsShims(SharedTestState fixture) [Fact] public void MuxerRunsPortableAppWithoutWindowsOsShims() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Manifests are only supported on Windows OSes. + return; + } + TestProjectFixture portableAppFixture = sharedTestState.PortableTestWindowsOsShimsAppFixture.Copy(); portableAppFixture.BuiltDotnet.Exec(portableAppFixture.TestProject.AppDll) From 357f049fcdce2e776a151350d936a079a5a3e1e0 Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Mon, 29 Oct 2018 09:48:01 -0700 Subject: [PATCH 6/6] Fix missing dispose in tests. --- .../HostActivationTests/GivenThatICareAboutWindowsOsShims.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs index dca8f2c93c..559d987139 100644 --- a/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs +++ b/src/test/HostActivationTests/GivenThatICareAboutWindowsOsShims.cs @@ -52,7 +52,7 @@ public SharedTestState() public void Dispose() { - //PortableTestWindowsOsShimsAppFixture.Dispose(); + PortableTestWindowsOsShimsAppFixture.Dispose(); } } }