diff --git a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs index 1abb3ad75b9697..73d808145f7ee4 100644 --- a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs +++ b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs @@ -494,11 +494,9 @@ public void AppHost_CLI_FrameworkDependent_MissingRuntimeFramework_ErrorReported } } - [Theory] + [Fact] [PlatformSpecific(TestPlatforms.Windows)] // GUI app host is only supported on Windows. - [InlineData(true)] - [InlineData(false)] - public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReportedInDialog(bool missingHostfxr) + public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReportedInDialog() { var fixture = sharedTestState.PortableAppFixture_Built .Copy(); @@ -515,22 +513,12 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported string expectedErrorCode; string expectedUrlQuery; - string expectedUrlParameter = null; - if (missingHostfxr) - { - expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x"); - expectedUrlQuery = "missing_runtime=true&"; - expectedUrlParameter = $"&apphost_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; - } - else - { - invalidDotNet = new DotNetBuilder(invalidDotNet, sharedTestState.RepoDirectories.BuiltDotnet, "missingFramework") - .Build() - .BinPath; - expectedErrorCode = Constants.ErrorCode.FrameworkMissingFailure.ToString("x"); - expectedUrlQuery = $"framework={Constants.MicrosoftNETCoreApp}&framework_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; - } + invalidDotNet = new DotNetBuilder(invalidDotNet, sharedTestState.RepoDirectories.BuiltDotnet, "missingFramework") + .Build() + .BinPath; + expectedErrorCode = Constants.ErrorCode.FrameworkMissingFailure.ToString("x"); + expectedUrlQuery = $"framework={Constants.MicrosoftNETCoreApp}&framework_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"; Command command = Command.Create(appExe) .EnableTracingAndCaptureOutputs() .DotNetRoot(invalidDotNet) @@ -541,16 +529,45 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported command.Process.Kill(); var result = command.WaitForExit(true) - .Should().Fail(); - - result.And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}") + .Should().Fail() + .And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}") .And.HaveStdErrContaining($"url: 'https://aka.ms/dotnet-core-applaunch?{expectedUrlQuery}") .And.HaveStdErrContaining("&gui=true"); + } + } - if (expectedUrlParameter != null) - { - result.And.HaveStdErrContaining(expectedUrlParameter); - } + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void AppHost_GUI_MissingRuntime_ErrorReportedInDialog() + { + var fixture = sharedTestState.PortableAppFixture_Built + .Copy(); + + string appExe = fixture.TestProject.AppExe; + File.Copy(sharedTestState.BuiltAppHost, appExe, overwrite: true); + AppHostExtensions.BindAppHost(appExe); + AppHostExtensions.SetWindowsGraphicalUserInterfaceBit(appExe); + + string invalidDotNet = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "guiErrors")); + using (new TestArtifact(invalidDotNet)) + { + Directory.CreateDirectory(invalidDotNet); + var command = Command.Create(appExe) + .EnableTracingAndCaptureOutputs() + .DotNetRoot(invalidDotNet) + .MultilevelLookup(false) + .Start(); + + WaitForPopupFromProcess(command.Process); + command.Process.Kill(); + + var expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x"); + var result = command.WaitForExit(true) + .Should().Fail() + .And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}") + .And.HaveStdErrContaining($"url: 'https://aka.ms/dotnet-core-applaunch?missing_runtime=true") + .And.HaveStdErrContaining("gui=true") + .And.HaveStdErrContaining($"&apphost_version={sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); } } diff --git a/src/native/corehost/apphost/apphost.windows.cpp b/src/native/corehost/apphost/apphost.windows.cpp index a614c78ed22925..4149c7311f11ce 100644 --- a/src/native/corehost/apphost/apphost.windows.cpp +++ b/src/native/corehost/apphost/apphost.windows.cpp @@ -61,11 +61,12 @@ namespace if (pal::getenv(_X("DOTNET_DISABLE_GUI_ERRORS"), &gui_errors_disabled) && pal::xtoi(gui_errors_disabled.c_str()) == 1) return; - pal::string_t dialogMsg = _X("To run this application, you must install .NET.\n\n"); + pal::string_t dialogMsg; pal::string_t url; const pal::string_t url_prefix = _X(" - ") DOTNET_CORE_APPLAUNCH_URL _X("?"); if (error_code == StatusCode::CoreHostLibMissingFailure) { + dialogMsg = pal::string_t(_X("To run this application, you must install .NET Desktop Runtime ")) + _STRINGIFY(COMMON_HOST_PKG_VER) + _X(" (") + get_arch() + _X(").\n\n"); pal::string_t line; pal::stringstream_t ss(g_buffered_errors); while (std::getline(ss, line, _X('\n'))) { @@ -81,6 +82,7 @@ namespace { // We don't have a great way of passing out different kinds of detailed error info across components, so // just match the expected error string. See fx_resolver.messages.cpp. + dialogMsg = pal::string_t(_X("To run this application, you must install .NET.\n\n")); pal::string_t line; pal::stringstream_t ss(g_buffered_errors); while (std::getline(ss, line, _X('\n'))){