From 0020460b6d1bff309cf1c76b986f7c8a4dc49c34 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 30 Aug 2021 16:00:16 -0700 Subject: [PATCH 01/17] Add expected return codes --- .../v1.1.0/manifest.installer.1.1.0.json | 46 ++++++++++- .../v1.1.0/manifest.singleton.1.1.0.json | 48 +++++++++++- .../ExecutionContextData.h | 7 ++ src/AppInstallerCLICore/Resources.h | 13 +++- .../Workflows/InstallFlow.cpp | 76 ++++++++++++++++++- .../Workflows/InstallFlow.h | 16 ++++ .../Workflows/MsiInstallFlow.cpp | 19 +---- .../Workflows/MsiInstallFlow.h | 2 +- .../ShellExecuteInstallerHandler.cpp | 19 +---- .../Workflows/ShellExecuteInstallerHandler.h | 2 +- .../Shared/Strings/en-us/winget.resw | 33 ++++++++ .../AppInstallerCLITests.vcxproj | 3 + .../AppInstallerCLITests.vcxproj.filters | 3 + .../InstallFlowTest_ExpectedReturnCodes.yaml | 24 ++++++ src/AppInstallerCLITests/WorkFlow.cpp | 22 ++++++ src/AppInstallerCommonCore/Errors.cpp | 18 +++++ .../Manifest/ManifestSchemaValidation.cpp | 10 ++- .../Manifest/ManifestValidation.cpp | 14 ++++ .../Manifest/ManifestYamlPopulator.cpp | 30 ++++++++ .../Public/AppInstallerErrors.h | 9 +++ .../Public/AppInstallerLanguageUtilities.h | 2 +- .../Public/winget/ManifestCommon.h | 12 +++ .../Public/winget/ManifestInstaller.h | 2 + .../Public/winget/ManifestValidation.h | 1 + .../Public/winget/ManifestYamlPopulator.h | 3 + 25 files changed, 385 insertions(+), 49 deletions(-) create mode 100644 src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index 9091196e91..b3ce588943 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -132,18 +132,50 @@ } } }, + "ReturnCode": { + "type": "integer", + "not": { + "enum": [ 0 ] + } + }, "InstallerSuccessCodes": { "type": [ "array", "null" ], "items": { - "type": "integer", - "not": { - "enum": [ 0 ] - } + "$ref": "#/definitions/ReturnCode" }, "maxItems": 16, "uniqueItems": true, "description": "List of additional non-zero installer success exit codes other than known default values by winget" }, + "ExpectedReturnCodes": { + "type": "object", + "properties": { + "PackageInUse": { + "$ref": "#/definitions/ReturnCode" + }, + "InstallInProgress": { + "$ref": "#/definitions/ReturnCode" + }, + "FileInUse": { + "$ref": "#/definitions/ReturnCode" + }, + "MissingDependency": { + "$ref": "#/definitions/ReturnCode" + }, + "DiskFull": { + "$ref": "#/definitions/ReturnCode" + }, + "InsufficientMemory": { + "$ref": "#/definitions/ReturnCode" + }, + "NoNetwork": { + "$ref": "#/definitions/ReturnCode" + }, + "ContactSupport": { + "$ref": "#/definitions/ReturnCode" + } + } + }, "UpgradeBehavior": { "type": [ "string", "null" ], "enum": [ @@ -329,6 +361,9 @@ "InstallerSuccessCodes": { "$ref": "#/definitions/InstallerSuccessCodes" }, + "ExpectedReturnCodes": { + "$ref": "#/definitions/ExpectedReturnCodes" + }, "UpgradeBehavior": { "$ref": "#/definitions/UpgradeBehavior" }, @@ -399,6 +434,9 @@ "InstallerSuccessCodes": { "$ref": "#/definitions/InstallerSuccessCodes" }, + "ExpectedReturnCodes": { + "$ref": "#/definitions/ExpectedReturnCodes" + }, "UpgradeBehavior": { "$ref": "#/definitions/UpgradeBehavior" }, diff --git a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json index 4e9f11d0ce..15f6602000 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json @@ -165,18 +165,52 @@ } } }, + "ReturnCode": { + "type": "integer", + "not": { + "enum": [ 0 ] + }, + "description": "An exit code that can be returned by the installer after execution" + }, "InstallerSuccessCodes": { "type": [ "array", "null" ], "items": { - "type": "integer", - "not": { - "enum": [ 0 ] - } + "$ref": "#/definitions/ReturnCode" }, "maxItems": 16, "uniqueItems": true, "description": "List of additional non-zero installer success exit codes other than known default values by winget" }, + "ExpectedReturnCodes": { + "type": "object", + "properties": { + "PackageInUse": { + "$ref": "#/definitions/ReturnCode" + }, + "InstallInProgress": { + "$ref": "#/definitions/ReturnCode" + }, + "FileInUse": { + "$ref": "#/definitions/ReturnCode" + }, + "MissingDependency": { + "$ref": "#/definitions/ReturnCode" + }, + "DiskFull": { + "$ref": "#/definitions/ReturnCode" + }, + "InsufficientMemory": { + "$ref": "#/definitions/ReturnCode" + }, + "NoNetwork": { + "$ref": "#/definitions/ReturnCode" + }, + "ContactSupport": { + "$ref": "#/definitions/ReturnCode" + } + }, + "description": "Installer exit codes for common errors" + }, "UpgradeBehavior": { "type": [ "string", "null" ], "enum": [ @@ -361,6 +395,9 @@ "InstallerSuccessCodes": { "$ref": "#/definitions/InstallerSuccessCodes" }, + "ExpectedReturnCodes": { + "$ref": "#/definitions/ExpectedReturnCodes" + }, "UpgradeBehavior": { "$ref": "#/definitions/UpgradeBehavior" }, @@ -523,6 +560,9 @@ "InstallerSuccessCodes": { "$ref": "#/definitions/InstallerSuccessCodes" }, + "ExpectedReturnCodes": { + "$ref": "#/definitions/ExpectedReturnCodes" + }, "UpgradeBehavior": { "$ref": "#/definitions/UpgradeBehavior" }, diff --git a/src/AppInstallerCLICore/ExecutionContextData.h b/src/AppInstallerCLICore/ExecutionContextData.h index e285a7ba4e..cc29a64a22 100644 --- a/src/AppInstallerCLICore/ExecutionContextData.h +++ b/src/AppInstallerCLICore/ExecutionContextData.h @@ -34,6 +34,7 @@ namespace AppInstaller::CLI::Execution InstallerPath, LogPath, InstallerArgs, + InstallerReturnCode, CompletionData, InstalledPackageVersion, UninstallString, @@ -152,6 +153,12 @@ namespace AppInstaller::CLI::Execution using value_t = std::string; }; + template <> + struct DataMapping + { + using value_t = DWORD; + }; + template <> struct DataMapping { diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 41331d9474..0203d37ca8 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -85,25 +85,36 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(ImportPackageAlreadyInstalled); WINGET_DEFINE_RESOURCE_STRINGID(ImportSearchFailed); WINGET_DEFINE_RESOURCE_STRINGID(ImportSourceNotInstalled); + WINGET_DEFINE_RESOURCE_STRINGID(InstallAndUpgradeCommandsReportDependencies); + WINGET_DEFINE_RESOURCE_STRINGID(InstallationAbandoned); WINGET_DEFINE_RESOURCE_STRINGID(InstallationDisclaimer1); WINGET_DEFINE_RESOURCE_STRINGID(InstallationDisclaimer2); WINGET_DEFINE_RESOURCE_STRINGID(InstallationDisclaimerMSStore); WINGET_DEFINE_RESOURCE_STRINGID(InstallationRequiresHigherWindows); WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandLongDescription); - WINGET_DEFINE_RESOURCE_STRINGID(InstallAndUpgradeCommandsReportDependencies); WINGET_DEFINE_RESOURCE_STRINGID(InstallCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(InstalledPackageNotAvailable); WINGET_DEFINE_RESOURCE_STRINGID(InstalledPackageVersionNotAvailable); WINGET_DEFINE_RESOURCE_STRINGID(InstallerBlockedByPolicy); WINGET_DEFINE_RESOURCE_STRINGID(InstallerFailedSecurityCheck); WINGET_DEFINE_RESOURCE_STRINGID(InstallerFailedVirusScan); + WINGET_DEFINE_RESOURCE_STRINGID(InstallerFailedWithCode); WINGET_DEFINE_RESOURCE_STRINGID(InstallerHashMismatchAdminBlock); WINGET_DEFINE_RESOURCE_STRINGID(InstallerHashMismatchError); WINGET_DEFINE_RESOURCE_STRINGID(InstallerHashMismatchOverridden); WINGET_DEFINE_RESOURCE_STRINGID(InstallerHashMismatchOverrideRequired); WINGET_DEFINE_RESOURCE_STRINGID(InstallerHashVerified); + WINGET_DEFINE_RESOURCE_STRINGID(InstallerLogAvailable); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowInstallSuccess); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowRegistrationDeferred); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeContactSupport); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeDiskFull); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeFileInUse); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeInstallInProgress); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeInsufficientMemory); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeMissingDependency); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeNoNetwork); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodePackageInUse); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowStartingPackageInstall); WINGET_DEFINE_RESOURCE_STRINGID(InstallForceArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(InstallScopeDescription); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 073aa62fc0..b6faee5830 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -54,6 +54,41 @@ namespace AppInstaller::CLI::Workflow return false; } } + + struct ExpectedReturnCode + { + ExpectedReturnCode(InstallerReturnCodeEnum installerReturnCode, HRESULT hr, Resource::StringId message) : + InstallerReturnCode(installerReturnCode), HResult(hr), Message(message) {} + + static ExpectedReturnCode GetExpectedReturnCode(InstallerReturnCodeEnum returnCode) + { + switch (returnCode) + { + case InstallerReturnCodeEnum::PackageInUse: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE, Resource::String::InstallFlowReturnCodePackageInUse); + case InstallerReturnCodeEnum::InstallInProgress: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS, Resource::String::InstallFlowReturnCodeInstallInProgress); + case InstallerReturnCodeEnum::FileInUse: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE, Resource::String::InstallFlowReturnCodeFileInUse); + case InstallerReturnCodeEnum::MissingDependency: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY, Resource::String::InstallFlowReturnCodeMissingDependency); + case InstallerReturnCodeEnum::DiskFull: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL, Resource::String::InstallFlowReturnCodeDiskFull); + case InstallerReturnCodeEnum::InsufficientMemory: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY, Resource::String::InstallFlowReturnCodeInsufficientMemory); + case InstallerReturnCodeEnum::NoNetwork: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK, Resource::String::InstallFlowReturnCodeNoNetwork); + case InstallerReturnCodeEnum::ContactSupport: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT, Resource::String::InstallFlowReturnCodeContactSupport); + default: + THROW_HR(E_UNEXPECTED); + } + } + + InstallerReturnCodeEnum InstallerReturnCode; + HRESULT HResult; + Resource::StringId Message; + }; } void EnsureApplicableInstaller(Execution::Context& context) @@ -427,7 +462,8 @@ namespace AppInstaller::CLI::Workflow context << GetInstallerArgs << RenameDownloadedInstaller << - ShellExecuteInstallImpl; + ShellExecuteInstallImpl << + ReportInstallerResult("ShellExecute"sv); } void DirectMSIInstall(Execution::Context& context) @@ -435,7 +471,8 @@ namespace AppInstaller::CLI::Workflow context << GetInstallerArgs << RenameDownloadedInstaller << - DirectMSIInstallImpl; + DirectMSIInstallImpl << + ReportInstallerResult("MsiInstallProduct"sv); } void MsixInstall(Execution::Context& context) @@ -480,6 +517,41 @@ namespace AppInstaller::CLI::Workflow } } + void ReportInstallerResult::operator()(Execution::Context& context) const + { + DWORD installResult = context.Get(); + const auto& additionalSuccessCodes = context.Get()->InstallerSuccessCodes; + if (installResult != 0 && (std::find(additionalSuccessCodes.begin(), additionalSuccessCodes.end(), installResult) == additionalSuccessCodes.end())) + { + const auto& manifest = context.Get(); + Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, m_installerType, installResult); + context.Reporter.Error() << Resource::String::InstallerFailedWithCode << ' ' << installResult << std::endl; + + // Show installer log path if exists + if (context.Contains(Execution::Data::LogPath) && std::filesystem::exists(context.Get())) + { + context.Reporter.Info() << Resource::String::InstallerLogAvailable << ' ' << context.Get().u8string() << std::endl; + } + + // Show a specific message if we can identify the return code + for (const auto& expectedReturnCode : context.Get()->ExpectedReturnCodes) + { + if (installResult == expectedReturnCode.second) + { + auto returnCode = ExpectedReturnCode::GetExpectedReturnCode(expectedReturnCode.first); + context.Reporter.Error() << returnCode.Message << std::endl; + AICLI_TERMINATE_CONTEXT(returnCode.HResult); + } + } + + AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); + } + else + { + context.Reporter.Info() << Resource::String::InstallFlowInstallSuccess << std::endl; + } + } + void RemoveInstaller(Execution::Context& context) { // Path may not be present if installed from a URL for MSIX diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index 887821d431..988e6e12fb 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -114,6 +114,22 @@ namespace AppInstaller::CLI::Workflow // Outputs: None void MsixInstall(Execution::Context& context); + // Reports the return code returned by the installer. + // Required Args: None + // Inputs: Installer, InstallerResult + // Outputs: None + struct ReportInstallerResult : public WorkflowTask + { + ReportInstallerResult(std::string_view installerType) : WorkflowTask("ReportInstallerResult"), m_installerType(installerType) {} + + void operator()(Execution::Context& context) const override; + + private: + // Installer type used when reporting failures + std::string_view m_installerType; + }; + + // Deletes the installer file. // Required Args: None // Inputs: InstallerPath diff --git a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp index 1bc8dab520..be0fd4e608 100644 --- a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.cpp @@ -33,7 +33,6 @@ namespace AppInstaller::CLI::Workflow context.Reporter.Info() << Resource::String::InstallFlowStartingPackageInstall << std::endl; const std::filesystem::path& installerPath = context.Get(); - const auto& additionalSuccessCodes = context.Get()->InstallerSuccessCodes; Msi::MsiParsedArguments parsedArgs = Msi::ParseMSIArguments(context.Get()); @@ -45,26 +44,12 @@ namespace AppInstaller::CLI::Workflow if (!installResult) { - context.Reporter.Warn() << "Installation abandoned" << std::endl; + context.Reporter.Warn() << Resource::String::InstallationAbandoned << std::endl; AICLI_TERMINATE_CONTEXT(E_ABORT); } - else if (installResult.value() != 0 && (std::find(additionalSuccessCodes.begin(), additionalSuccessCodes.end(), installResult.value()) == additionalSuccessCodes.end())) - { - const auto& manifest = context.Get(); - Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, "ShellExecute", installResult.value()); - - context.Reporter.Error() << "Installer failed with exit code: " << installResult.value() << std::endl; - // Show installer log path if exists - if (context.Contains(Execution::Data::LogPath) && std::filesystem::exists(context.Get())) - { - context.Reporter.Info() << "Installer log is available at: " << context.Get().u8string() << std::endl; - } - - AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); - } else { - context.Reporter.Info() << Resource::String::InstallFlowInstallSuccess << std::endl; + context.Add(installResult.value()); } } } diff --git a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h index 6104c212e3..7aac116148 100644 --- a/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/MsiInstallFlow.h @@ -8,6 +8,6 @@ namespace AppInstaller::CLI::Workflow // Ensures that there is an applicable installer. // Required Args: None // Inputs: InstallerArgs, Installer, InstallerPath, Manifest - // Outputs: None + // Outputs: InstallerReturnCode void DirectMSIInstallImpl(Execution::Context& context); } diff --git a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp index cabdbf0a31..47d26d5ac4 100644 --- a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp +++ b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp @@ -188,7 +188,6 @@ namespace AppInstaller::CLI::Workflow context.Reporter.Info() << Resource::String::InstallFlowStartingPackageInstall << std::endl; const std::string& installerArgs = context.Get(); - const auto& additionalSuccessCodes = context.Get()->InstallerSuccessCodes; auto installResult = context.Reporter.ExecuteWithProgress( std::bind(InvokeShellExecute, @@ -198,26 +197,12 @@ namespace AppInstaller::CLI::Workflow if (!installResult) { - context.Reporter.Warn() << "Installation abandoned" << std::endl; + context.Reporter.Warn() << Resource::String::InstallationAbandoned << std::endl; AICLI_TERMINATE_CONTEXT(E_ABORT); } - else if (installResult.value() != 0 && (std::find(additionalSuccessCodes.begin(), additionalSuccessCodes.end(), installResult.value()) == additionalSuccessCodes.end())) - { - const auto& manifest = context.Get(); - Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, "ShellExecute", installResult.value()); - - context.Reporter.Error() << "Installer failed with exit code: " << installResult.value() << std::endl; - // Show installer log path if exists - if (context.Contains(Execution::Data::LogPath) && std::filesystem::exists(context.Get())) - { - context.Reporter.Info() << "Installer log is available at: " << context.Get().u8string() << std::endl; - } - - AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); - } else { - context.Reporter.Info() << Resource::String::InstallFlowInstallSuccess << std::endl; + context.Add(installResult.value()); } } diff --git a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h index 227ac22f5f..ee2142e27e 100644 --- a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h +++ b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.h @@ -14,7 +14,7 @@ namespace AppInstaller::CLI::Workflow // Install is done through invoking ShellExecute on downloaded installer. // Required Args: None // Inputs: Manifest?, InstallerPath, InstallerArgs - // Outputs: None + // Outputs: InstallerReturnCode void ShellExecuteInstallImpl(Execution::Context& context); // Uninstall is done through invoking ShellExecute on uninstall string. diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 2e0d477ebf..6a40a7ce7b 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1031,4 +1031,37 @@ Do you agree to the terms? The optional header is not applicable without specifying a Rest source + + Application is currently running. Exit the application then try again. + + + Another installation is already in progress. Try again later. + + + One or more file is being used. Exit the application then try again. + + + This package has a dependency missing from your system. + + + There's no more space on your PC. Make space, then try again. + + + There's not enough memory available to install. Close other applications then try again. + + + This application requires internet connectivity. Connect to a network then try again. + + + This application encountered an error during installation. Contact support. + + + Installation abandoned + + + Installer failed with exit code: + + + Installer log is available at: + \ No newline at end of file diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index 0b17df13c8..1cca3098fa 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -258,6 +258,9 @@ true + + true + true diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 240870f9b2..071f4d1fc7 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -348,6 +348,9 @@ TestData + + TestData + TestData diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml new file mode 100644 index 0000000000..6eeca17089 --- /dev/null +++ b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml @@ -0,0 +1,24 @@ +PackageIdentifier: AppInstallerCliTest.TestInstaller +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Installer +ShortDescription: AppInstaller Test Installer +Publisher: Microsoft Corporation +Moniker: AICLITestExe +License: Test +Installers: + - Architecture: x86 + InstallerUrl: https://ThisIsNotUsed + InstallerType: exe + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B + ExpectedReturnCodes: + PackageInUse: 1 + InstallInProgress: 2 + FileInUse: 3 + MissingDependency: 4 + DiskFull: 5 + InsufficientMemory: 6 + NoNetwork: 7 + ContactSupport: 8 +ManifestType: singleton +ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp index 0d48b01536..06d52b4b23 100644 --- a/src/AppInstallerCLITests/WorkFlow.cpp +++ b/src/AppInstallerCLITests/WorkFlow.cpp @@ -433,6 +433,8 @@ void OverrideForDirectMsi(TestContext& context) std::ofstream file(temp, std::ofstream::out); file << context.Get(); file.close(); + + context.Add(0); } }); } @@ -568,6 +570,26 @@ TEST_CASE("InstallFlowNonZeroExitCode", "[InstallFlow][workflow]") REQUIRE(installResultStr.find("/silentwithprogress") != std::string::npos); } +TEST_CASE("InstallFlow_ExpectedReturnCodes", "[InstallFlow][workflow]") +{ + TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + + std::ostringstream installOutput; + TestContext context{ installOutput, std::cin }; + OverrideForShellExecute(context); + context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_ExpectedReturnCodes.yaml").GetPath().u8string()); + context.Args.AddArg(Execution::Args::Type::Override, "/ExitCode 8"sv); + + InstallCommand install({}); + install.Execute(context); + INFO(installOutput.str()); + + // Verify install failed with the right message + REQUIRE_TERMINATED_WITH(context, APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT); + REQUIRE(std::filesystem::exists(installResultPath.GetPath())); + REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::InstallFlowReturnCodeContactSupport).get()) != std::string::npos); +} + TEST_CASE("InstallFlowWithNonApplicableArchitecture", "[InstallFlow][workflow]") { TestCommon::TempFile installResultPath("TestExeInstalled.txt"); diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp index 64a607bca1..271347f432 100644 --- a/src/AppInstallerCommonCore/Errors.cpp +++ b/src/AppInstallerCommonCore/Errors.cpp @@ -146,6 +146,24 @@ namespace AppInstaller return "License not agreed to"; case APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR: return "Error reading input in prompt"; + case APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT: + return "Arguments for msiexec are invalid"; + case APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE: + return "Application is currently running.Exit the application then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS: + return "Another installation is already in progress.Try again later."; + case APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE: + return "One or more file is being used.Exit the application then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY: + return "This package has a dependency missing from your system."; + case APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL: + return "There's no more space on your PC. Make space, then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY: + return "There's not enough memory available to install. Close other applications then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK: + return "This application requires internet connectivity.Connect to a network then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT: + return "This application encountered an error during installation.Contact support."; default: return "Unknown Error Code"; } diff --git a/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp index 43ba5068d8..34088a63f9 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp @@ -24,7 +24,15 @@ namespace AppInstaller::Manifest::YamlParser // List of fields that use non string scalar types const std::map ManifestFieldTypes= { - { "InstallerSuccessCodes"sv, YamlScalarType::Int } + { "InstallerSuccessCodes"sv, YamlScalarType::Int }, + { "PackageInUse"sv, YamlScalarType::Int }, + { "InstallInProgress"sv, YamlScalarType::Int }, + { "FileInUse"sv, YamlScalarType::Int }, + { "MissingDependency"sv, YamlScalarType::Int }, + { "DiskFull"sv, YamlScalarType::Int }, + { "InsufficientMemory"sv, YamlScalarType::Int }, + { "NoNetwork"sv, YamlScalarType::Int }, + { "ContactSupport"sv, YamlScalarType::Int }, }; YamlScalarType GetManifestScalarValueType(const std::string& key) diff --git a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp index b72c6c4c72..0972bf3b3a 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp @@ -142,6 +142,20 @@ namespace AppInstaller::Manifest { resultErrors.emplace_back(ManifestError::InvalidBcp47Value, "InstallerLocale", installer.Locale); } + + // Check expected return codes for duplicates + std::set returnCodeSet; + returnCodeSet.insert(installer.InstallerSuccessCodes.begin(), installer.InstallerSuccessCodes.end()); + for (const auto& code : installer.ExpectedReturnCodes) + { + if (!returnCodeSet.insert(code.second).second) + { + resultErrors.emplace_back(ManifestError::DuplicateReturnCodeEntry); + + // Stop checking to avoid repeated errors + break; + } + } } // Validate localizations diff --git a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp index 3f4d9aa27a..061307d5a2 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp @@ -249,6 +249,16 @@ namespace AppInstaller::Manifest std::move(v1InstallerFields.begin(), v1InstallerFields.end(), std::inserter(result, result.end())); } } + + if (manifestVersion >= ManifestVer{ s_ManifestVersionV1_1 }) + { + std::vector v1_1CommonFields = + { + { "ExpectedReturnCodes", [this](const YAML::Node& value)->ValidationErrors { m_p_returnCodes = &(m_p_installer->ExpectedReturnCodes); return ValidateAndProcessFields(value, ExpectedReturnCodesFieldInfos); } }, + }; + + std::move(v1_1CommonFields.begin(), v1_1CommonFields.end(), std::inserter(result, result.end())); + } } return result; @@ -282,6 +292,25 @@ namespace AppInstaller::Manifest return result; } + std::vector ManifestYamlPopulator::GetExpectedReturnCodesFieldProcessInfo(const ManifestVer& manifestVersion) + { + std::vector result = {}; + + if (manifestVersion >= ManifestVer{ s_ManifestVersionV1_1 }) + { + result.emplace_back("PackageInUse", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::PackageInUse] = static_cast(value.as()); return {}; }); + result.emplace_back("InstallInProgress", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::InstallInProgress] = static_cast(value.as()); return {}; }); + result.emplace_back("FileInUse", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::FileInUse] = static_cast(value.as()); return {}; }); + result.emplace_back("MissingDependency", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::MissingDependency] = static_cast(value.as()); return {}; }); + result.emplace_back("DiskFull", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::DiskFull] = static_cast(value.as()); return {}; }); + result.emplace_back("InsufficientMemory", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::InsufficientMemory] = static_cast(value.as()); return {}; }); + result.emplace_back("NoNetwork", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::NoNetwork] = static_cast(value.as()); return {}; }); + result.emplace_back("ContactSupport", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::ContactSupport] = static_cast(value.as()); return {}; }); + } + + return result; + } + std::vector ManifestYamlPopulator::GetLocalizationFieldProcessInfo(const ManifestVer& manifestVersion, bool forRootFields) { // Common fields across versions @@ -536,6 +565,7 @@ namespace AppInstaller::Manifest RootFieldInfos = GetRootFieldProcessInfo(manifestVersion); InstallerFieldInfos = GetInstallerFieldProcessInfo(manifestVersion); SwitchesFieldInfos = GetSwitchesFieldProcessInfo(manifestVersion); + ExpectedReturnCodesFieldInfos = GetExpectedReturnCodesFieldProcessInfo(manifestVersion); DependenciesFieldInfos = GetDependenciesFieldProcessInfo(manifestVersion); PackageDependenciesFieldInfos = GetPackageDependenciesFieldProcessInfo(manifestVersion); LocalizationFieldInfos = GetLocalizationFieldProcessInfo(manifestVersion); diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 391db61644..142347f135 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -80,6 +80,15 @@ #define APPINSTALLER_CLI_ERROR_LICENSE_NOT_ACCEPTED ((HRESULT)0x8a150041) #define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8a150042) #define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150043) +#define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150044) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150045) +#define APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE ((HRESULT)0x8a150046) +#define APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY ((HRESULT)0x8a150047) +#define APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL ((HRESULT)0x8a150048) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8a150049) +#define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a15004A) +#define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a15004B) + namespace AppInstaller { diff --git a/src/AppInstallerCommonCore/Public/AppInstallerLanguageUtilities.h b/src/AppInstallerCommonCore/Public/AppInstallerLanguageUtilities.h index e7cacc3a6e..0b673d346c 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerLanguageUtilities.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerLanguageUtilities.h @@ -138,7 +138,7 @@ namespace AppInstaller const typename Variant::variant_t& GetVariant(Enum e) const { auto itr = m_data.find(e); - THROW_HR_IF_MSG(E_NOT_SET, itr == m_data.cend(), "GetVariant(%d)", e); + THROW_HR_IF_MSG(E_NOT_SET, itr == m_data.cend(), "GetVariant(%d)", static_cast(e)); return itr->second; } diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index 80596dfa9b..118abb9c44 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -97,6 +97,18 @@ namespace AppInstaller::Manifest SilentWithProgress, }; + enum class InstallerReturnCodeEnum + { + PackageInUse, + InstallInProgress, + FileInUse, + MissingDependency, + DiskFull, + InsufficientMemory, + NoNetwork, + ContactSupport, + }; + enum class PlatformEnum { Unknown, diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h index 8579296c37..32b342a47e 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h @@ -51,6 +51,8 @@ namespace AppInstaller::Manifest std::vector InstallerSuccessCodes; + std::map ExpectedReturnCodes; + UpdateBehaviorEnum UpdateBehavior = UpdateBehaviorEnum::Install; std::vector Commands; diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h b/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h index a0bbf70a65..cd14230985 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h @@ -39,6 +39,7 @@ namespace AppInstaller::Manifest const char* const InconsistentMultiFileManifestDefaultLocale = "DefaultLocale value in version manifest does not match PackageLocale value in defaultLocale manifest."; const char* const FieldFailedToProcess = "Failed to process field."; const char* const InvalidBcp47Value = "The locale value is not a well formed bcp47 language tag."; + const char* const DuplicateReturnCodeEntry = "Duplicate installer return code found."; } struct ValidationError diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h b/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h index 73ab9fb1ef..9085681ef9 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h @@ -29,6 +29,7 @@ namespace AppInstaller::Manifest std::vector RootFieldInfos; std::vector InstallerFieldInfos; std::vector SwitchesFieldInfos; + std::vector ExpectedReturnCodesFieldInfos; std::vector DependenciesFieldInfos; std::vector PackageDependenciesFieldInfos; std::vector LocalizationFieldInfos; @@ -38,6 +39,7 @@ namespace AppInstaller::Manifest AppInstaller::Manifest::Manifest* m_p_manifest = nullptr; AppInstaller::Manifest::ManifestInstaller* m_p_installer = nullptr; std::map* m_p_switches = nullptr; + std::map* m_p_returnCodes = nullptr; AppInstaller::Manifest::DependencyList* m_p_dependencyList = nullptr; AppInstaller::Manifest::Dependency* m_p_packageDependency = nullptr; AppInstaller::Manifest::ManifestLocalization* m_p_localization = nullptr; @@ -50,6 +52,7 @@ namespace AppInstaller::Manifest std::vector GetRootFieldProcessInfo(const ManifestVer& manifestVersion); std::vector GetInstallerFieldProcessInfo(const ManifestVer& manifestVersion, bool forRootFields = false); std::vector GetSwitchesFieldProcessInfo(const ManifestVer& manifestVersion); + std::vector GetExpectedReturnCodesFieldProcessInfo(const ManifestVer& manifestVersion); std::vector GetDependenciesFieldProcessInfo(const ManifestVer& manifestVersion); std::vector GetPackageDependenciesFieldProcessInfo(const ManifestVer& manifestVersion); std::vector GetLocalizationFieldProcessInfo(const ManifestVer& manifestVersion, bool forRootFields = false); From efe329e9b8f4e447baa53cded980083228a7c479 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 30 Aug 2021 19:27:44 -0700 Subject: [PATCH 02/17] Change name in schema definition --- .../v1.1.0/manifest.installer.1.1.0.json | 20 +++++++++---------- .../v1.1.0/manifest.singleton.1.1.0.json | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index b3ce588943..61bd915c87 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -132,7 +132,7 @@ } } }, - "ReturnCode": { + "InstallerReturnCode": { "type": "integer", "not": { "enum": [ 0 ] @@ -141,7 +141,7 @@ "InstallerSuccessCodes": { "type": [ "array", "null" ], "items": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "maxItems": 16, "uniqueItems": true, @@ -151,28 +151,28 @@ "type": "object", "properties": { "PackageInUse": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "InstallInProgress": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "FileInUse": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "MissingDependency": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "DiskFull": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "InsufficientMemory": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "NoNetwork": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "ContactSupport": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" } } }, diff --git a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json index 15f6602000..f94a6b4582 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json @@ -165,7 +165,7 @@ } } }, - "ReturnCode": { + "InstallerReturnCode": { "type": "integer", "not": { "enum": [ 0 ] @@ -175,7 +175,7 @@ "InstallerSuccessCodes": { "type": [ "array", "null" ], "items": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "maxItems": 16, "uniqueItems": true, @@ -185,28 +185,28 @@ "type": "object", "properties": { "PackageInUse": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "InstallInProgress": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "FileInUse": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "MissingDependency": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "DiskFull": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "InsufficientMemory": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "NoNetwork": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" }, "ContactSupport": { - "$ref": "#/definitions/ReturnCode" + "$ref": "#/definitions/InstallerReturnCode" } }, "description": "Installer exit codes for common errors" From 5db8bf3445e46bcf9d2c51bde46ba343d8243485 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 1 Sep 2021 16:48:29 -0700 Subject: [PATCH 03/17] Move install error codes to higher range --- .../Public/AppInstallerErrors.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 142347f135..4b0b2f6e20 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -80,14 +80,15 @@ #define APPINSTALLER_CLI_ERROR_LICENSE_NOT_ACCEPTED ((HRESULT)0x8a150041) #define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8a150042) #define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150043) -#define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150044) -#define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150045) -#define APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE ((HRESULT)0x8a150046) -#define APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY ((HRESULT)0x8a150047) -#define APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL ((HRESULT)0x8a150048) -#define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8a150049) -#define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a15004A) -#define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a15004B) + +#define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150101) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150102) +#define APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE ((HRESULT)0x8a150103) +#define APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY ((HRESULT)0x8a150104) +#define APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL ((HRESULT)0x8a150105) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8a150106) +#define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a150107) +#define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a150108) namespace AppInstaller From faee8fe69ffef843785241a0ad477652e6e95066 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 1 Sep 2021 16:51:16 -0700 Subject: [PATCH 04/17] Allow mapping multiple installer error codes to same response --- .../v1.1.0/manifest.installer.1.1.0.json | 48 ++++++------- .../v1.1.0/manifest.singleton.1.1.0.json | 46 ++++++------ .../Workflows/InstallFlow.cpp | 35 +++++---- .../InstallFlowTest_ExpectedReturnCodes.yaml | 24 ++++--- .../Manifest/ManifestCommon.cpp | 71 +++++++++++++++++++ .../Manifest/ManifestSchemaValidation.cpp | 9 +-- .../Manifest/ManifestValidation.cpp | 4 +- .../Manifest/ManifestYamlPopulator.cpp | 48 ++++++++++--- .../Public/winget/ManifestCommon.h | 14 +++- .../Public/winget/ManifestInstaller.h | 2 +- .../Public/winget/ManifestYamlPopulator.h | 3 +- 11 files changed, 204 insertions(+), 100 deletions(-) diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index 61bd915c87..14b4466b69 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -148,33 +148,29 @@ "description": "List of additional non-zero installer success exit codes other than known default values by winget" }, "ExpectedReturnCodes": { - "type": "object", - "properties": { - "PackageInUse": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "InstallInProgress": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "FileInUse": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "MissingDependency": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "DiskFull": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "InsufficientMemory": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "NoNetwork": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "ContactSupport": { - "$ref": "#/definitions/InstallerReturnCode" + "type": [ "array", "null" ], + "items": { + "type": "object", + "properties": { + "InstallerReturnCode": { + "$ref": "#/definitions/InstallerReturnCode" + }, + "ReturnResponse": { + "type": [ "string", "null" ], + "enum": [ + "PackageInUse", + "InstallInProgress", + "FileInUse", + "MissingDependency", + "DiskFull", + "InsufficientMemory", + "NoNetwork", + "ContactSupport" + ] + } } - } + }, + "description": "Installer exit codes for common errors" }, "UpgradeBehavior": { "type": [ "string", "null" ], diff --git a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json index f94a6b4582..f6175000dc 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json @@ -182,33 +182,29 @@ "description": "List of additional non-zero installer success exit codes other than known default values by winget" }, "ExpectedReturnCodes": { - "type": "object", - "properties": { - "PackageInUse": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "InstallInProgress": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "FileInUse": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "MissingDependency": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "DiskFull": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "InsufficientMemory": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "NoNetwork": { - "$ref": "#/definitions/InstallerReturnCode" - }, - "ContactSupport": { - "$ref": "#/definitions/InstallerReturnCode" + "type": [ "array", "null" ], + "items": { + "type": "object", + "properties": { + "InstallerReturnCode": { + "$ref": "#/definitions/InstallerReturnCode" + }, + "ReturnResponse": { + "type": [ "string", "null" ], + "enum": [ + "PackageInUse", + "InstallInProgress", + "FileInUse", + "MissingDependency", + "DiskFull", + "InsufficientMemory", + "NoNetwork", + "ContactSupport" + ] + } } }, + "maxItems": 16, "description": "Installer exit codes for common errors" }, "UpgradeBehavior": { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index b6faee5830..04eee99844 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -57,35 +57,35 @@ namespace AppInstaller::CLI::Workflow struct ExpectedReturnCode { - ExpectedReturnCode(InstallerReturnCodeEnum installerReturnCode, HRESULT hr, Resource::StringId message) : + ExpectedReturnCode(ExpectedReturnCodeEnum installerReturnCode, HRESULT hr, Resource::StringId message) : InstallerReturnCode(installerReturnCode), HResult(hr), Message(message) {} - static ExpectedReturnCode GetExpectedReturnCode(InstallerReturnCodeEnum returnCode) + static ExpectedReturnCode GetExpectedReturnCode(ExpectedReturnCodeEnum returnCode) { switch (returnCode) { - case InstallerReturnCodeEnum::PackageInUse: + case ExpectedReturnCodeEnum::PackageInUse: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE, Resource::String::InstallFlowReturnCodePackageInUse); - case InstallerReturnCodeEnum::InstallInProgress: + case ExpectedReturnCodeEnum::InstallInProgress: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS, Resource::String::InstallFlowReturnCodeInstallInProgress); - case InstallerReturnCodeEnum::FileInUse: + case ExpectedReturnCodeEnum::FileInUse: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE, Resource::String::InstallFlowReturnCodeFileInUse); - case InstallerReturnCodeEnum::MissingDependency: + case ExpectedReturnCodeEnum::MissingDependency: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY, Resource::String::InstallFlowReturnCodeMissingDependency); - case InstallerReturnCodeEnum::DiskFull: + case ExpectedReturnCodeEnum::DiskFull: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL, Resource::String::InstallFlowReturnCodeDiskFull); - case InstallerReturnCodeEnum::InsufficientMemory: + case ExpectedReturnCodeEnum::InsufficientMemory: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY, Resource::String::InstallFlowReturnCodeInsufficientMemory); - case InstallerReturnCodeEnum::NoNetwork: + case ExpectedReturnCodeEnum::NoNetwork: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK, Resource::String::InstallFlowReturnCodeNoNetwork); - case InstallerReturnCodeEnum::ContactSupport: + case ExpectedReturnCodeEnum::ContactSupport: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT, Resource::String::InstallFlowReturnCodeContactSupport); default: THROW_HR(E_UNEXPECTED); } } - InstallerReturnCodeEnum InstallerReturnCode; + ExpectedReturnCodeEnum InstallerReturnCode; HRESULT HResult; Resource::StringId Message; }; @@ -534,14 +534,13 @@ namespace AppInstaller::CLI::Workflow } // Show a specific message if we can identify the return code - for (const auto& expectedReturnCode : context.Get()->ExpectedReturnCodes) + const auto& expectedReturnCodes = context.Get()->ExpectedReturnCodes; + auto expectedReturnCodeItr = expectedReturnCodes.find(installResult); + if (expectedReturnCodeItr != expectedReturnCodes.end() && expectedReturnCodeItr->second != ExpectedReturnCodeEnum::Unknown) { - if (installResult == expectedReturnCode.second) - { - auto returnCode = ExpectedReturnCode::GetExpectedReturnCode(expectedReturnCode.first); - context.Reporter.Error() << returnCode.Message << std::endl; - AICLI_TERMINATE_CONTEXT(returnCode.HResult); - } + auto returnCode = ExpectedReturnCode::GetExpectedReturnCode(expectedReturnCodeItr->second); + context.Reporter.Error() << returnCode.Message << std::endl; + AICLI_TERMINATE_CONTEXT(returnCode.HResult); } AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml index 6eeca17089..4a7937f29c 100644 --- a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml +++ b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml @@ -12,13 +12,21 @@ Installers: InstallerType: exe InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B ExpectedReturnCodes: - PackageInUse: 1 - InstallInProgress: 2 - FileInUse: 3 - MissingDependency: 4 - DiskFull: 5 - InsufficientMemory: 6 - NoNetwork: 7 - ContactSupport: 8 + - InstallerReturnCode: 1 + ReturnResponse: PackageInUse + - InstallerReturnCode: 2 + ReturnResponse: InstallInProgress + - InstallerReturnCode: 3 + ReturnResponse: FileInUse + - InstallerReturnCode: 4 + ReturnResponse: MissingDependency + - InstallerReturnCode: 5 + ReturnResponse: DiskFull + - InstallerReturnCode: 6 + ReturnResponse: InsufficientMemory + - InstallerReturnCode: 7 + ReturnResponse: NoNetwork + - InstallerReturnCode: 8 + ReturnResponse: ContactSupport ManifestType: singleton ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index fcbaf0747d..66b7ab9244 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -262,6 +262,46 @@ namespace AppInstaller::Manifest } } + ExpectedReturnCodeEnum ConvertToExpectedReturnCodeEnum(const std::string& in) + { + ExpectedReturnCodeEnum result = ExpectedReturnCodeEnum::Unknown; + + if (Utility::CaseInsensitiveEquals(in, "PackageInUse")) + { + result = ExpectedReturnCodeEnum::PackageInUse; + } + else if (Utility::CaseInsensitiveEquals(in, "InstallInProgress")) + { + result = ExpectedReturnCodeEnum::InstallInProgress; + } + else if (Utility::CaseInsensitiveEquals(in, "FileInUse")) + { + result = ExpectedReturnCodeEnum::FileInUse; + } + else if (Utility::CaseInsensitiveEquals(in, "MissingDependency")) + { + result = ExpectedReturnCodeEnum::MissingDependency; + } + else if (Utility::CaseInsensitiveEquals(in, "DiskFull")) + { + result = ExpectedReturnCodeEnum::DiskFull; + } + else if (Utility::CaseInsensitiveEquals(in, "InsufficientMemory")) + { + result = ExpectedReturnCodeEnum::InsufficientMemory; + } + else if (Utility::CaseInsensitiveEquals(in, "NoNetwork")) + { + result = ExpectedReturnCodeEnum::NoNetwork; + } + else if (Utility::CaseInsensitiveEquals(in, "ContactSupport")) + { + result = ExpectedReturnCodeEnum::ContactSupport; + } + + return result; + } + std::string_view InstallerTypeToString(InstallerTypeEnum installerType) { switch (installerType) @@ -378,4 +418,35 @@ namespace AppInstaller::Manifest return {}; } } + + std::map GetDefaultKnownReturnCodes(InstallerTypeEnum installerType) + { + switch (installerType) + { + case InstallerTypeEnum::Burn: + case InstallerTypeEnum::Wix: + case InstallerTypeEnum::Msi: + // See https://docs.microsoft.com/windows/win32/msi/error-codes + return + { + { ERROR_INSTALL_ALREADY_RUNNING, ExpectedReturnCodeEnum::InstallInProgress }, + { ERROR_DISK_FULL, ExpectedReturnCodeEnum::DiskFull }, + // { ERROR_SUCCESS_REBOOT_REQUIRED, ExpectedReturnCodeEnum::RebootRequiredSuccess }, + // { ERROR_SUCCESS_REBOOT_INITIATED, ExpectedReturnCodeEnum::RebootRequiredSuccess }, + // { ERROR_INSTALL_USEREXIT, ExpectedReturnCodeEnum::UserCancelled }, + }; + case InstallerTypeEnum::Inno: + // See https://jrsoftware.org/ishelp/index.php?topic=setupexitcodes + return + { + // { 2, ExpectedReturnCodeEnum::UserCancelled }, + // { 5, ExpectedReturnCodeEnum::UserCancelled }, + // { 8, ExpectedReturnCodeEnum::RebootRequiredFailure }, + }; + case InstallerTypeEnum::Msix: + // See https://docs.microsoft.com/en-us/windows/win32/appxpkg/troubleshooting + default: + return {}; + } + } } diff --git a/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp index 34088a63f9..8d7dc48679 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestSchemaValidation.cpp @@ -25,14 +25,7 @@ namespace AppInstaller::Manifest::YamlParser const std::map ManifestFieldTypes= { { "InstallerSuccessCodes"sv, YamlScalarType::Int }, - { "PackageInUse"sv, YamlScalarType::Int }, - { "InstallInProgress"sv, YamlScalarType::Int }, - { "FileInUse"sv, YamlScalarType::Int }, - { "MissingDependency"sv, YamlScalarType::Int }, - { "DiskFull"sv, YamlScalarType::Int }, - { "InsufficientMemory"sv, YamlScalarType::Int }, - { "NoNetwork"sv, YamlScalarType::Int }, - { "ContactSupport"sv, YamlScalarType::Int }, + { "InstallerReturnCode"sv, YamlScalarType::Int }, }; YamlScalarType GetManifestScalarValueType(const std::string& key) diff --git a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp index 0972bf3b3a..0e777c602c 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp @@ -143,12 +143,12 @@ namespace AppInstaller::Manifest resultErrors.emplace_back(ManifestError::InvalidBcp47Value, "InstallerLocale", installer.Locale); } - // Check expected return codes for duplicates + // Check expected return codes for duplicates between successful and expected error codes std::set returnCodeSet; returnCodeSet.insert(installer.InstallerSuccessCodes.begin(), installer.InstallerSuccessCodes.end()); for (const auto& code : installer.ExpectedReturnCodes) { - if (!returnCodeSet.insert(code.second).second) + if (!returnCodeSet.insert(code.first).second) { resultErrors.emplace_back(ManifestError::DuplicateReturnCodeEntry); diff --git a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp index 061307d5a2..6fc61b98f3 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp @@ -254,7 +254,7 @@ namespace AppInstaller::Manifest { std::vector v1_1CommonFields = { - { "ExpectedReturnCodes", [this](const YAML::Node& value)->ValidationErrors { m_p_returnCodes = &(m_p_installer->ExpectedReturnCodes); return ValidateAndProcessFields(value, ExpectedReturnCodesFieldInfos); } }, + { "ExpectedReturnCodes", [this](const YAML::Node& value)->ValidationErrors { return ProcessExpectedReturnCodesNode(value); } }, }; std::move(v1_1CommonFields.begin(), v1_1CommonFields.end(), std::inserter(result, result.end())); @@ -298,14 +298,8 @@ namespace AppInstaller::Manifest if (manifestVersion >= ManifestVer{ s_ManifestVersionV1_1 }) { - result.emplace_back("PackageInUse", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::PackageInUse] = static_cast(value.as()); return {}; }); - result.emplace_back("InstallInProgress", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::InstallInProgress] = static_cast(value.as()); return {}; }); - result.emplace_back("FileInUse", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::FileInUse] = static_cast(value.as()); return {}; }); - result.emplace_back("MissingDependency", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::MissingDependency] = static_cast(value.as()); return {}; }); - result.emplace_back("DiskFull", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::DiskFull] = static_cast(value.as()); return {}; }); - result.emplace_back("InsufficientMemory", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::InsufficientMemory] = static_cast(value.as()); return {}; }); - result.emplace_back("NoNetwork", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::NoNetwork] = static_cast(value.as()); return {}; }); - result.emplace_back("ContactSupport", [this](const YAML::Node& value)->ValidationErrors { (*m_p_returnCodes)[InstallerReturnCodeEnum::ContactSupport] = static_cast(value.as()); return {}; }); + result.emplace_back("InstallerReturnCode", [this](const YAML::Node& value)->ValidationErrors { m_p_expectedReturnCode->InstallerReturnCode = static_cast(value.as()); return {}; }); + result.emplace_back("ReturnResponse", [this](const YAML::Node& value)->ValidationErrors { m_p_expectedReturnCode->ReturnResponse = ConvertToExpectedReturnCodeEnum(value.as()); return {}; }); } return result; @@ -531,7 +525,7 @@ namespace AppInstaller::Manifest return resultErrors; } - std::vector ManifestYamlPopulator::ProcessAgreementsNode(const YAML::Node& agreementsNode) + ValidationErrors ManifestYamlPopulator::ProcessAgreementsNode(const YAML::Node& agreementsNode) { ValidationErrors resultErrors; std::vector agreements; @@ -553,6 +547,30 @@ namespace AppInstaller::Manifest return resultErrors; } + ValidationErrors ManifestYamlPopulator::ProcessExpectedReturnCodesNode(const YAML::Node& returnCodesNode) + { + THROW_HR_IF(E_INVALIDARG, !returnCodesNode.IsSequence()); + + ValidationErrors resultErrors; + std::map returnCodes; + + for (auto const& entry : returnCodesNode.Sequence()) + { + ExpectedReturnCode returnCode; + m_p_expectedReturnCode = &returnCode; + auto errors = ValidateAndProcessFields(entry, ExpectedReturnCodesFieldInfos); + std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); + + if (!returnCodes.insert({ returnCode.InstallerReturnCode, returnCode.ReturnResponse }).second) + { + resultErrors.emplace_back(ManifestError::DuplicateReturnCodeEntry); + } + } + + m_p_installer->ExpectedReturnCodes = returnCodes; + return resultErrors; + } + ValidationErrors ManifestYamlPopulator::PopulateManifestInternal(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation) { m_fullValidation = fullValidation; @@ -624,6 +642,16 @@ namespace AppInstaller::Manifest } } + // Populate installer default return codes if not present + auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.InstallerType); + for (auto const& defaultReturnCode : defaultReturnCodes) + { + if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end()) + { + installer.ExpectedReturnCodes[defaultReturnCode.first] = defaultReturnCode.second; + } + } + manifest.Installers.emplace_back(std::move(installer)); } diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index 118abb9c44..09c8eb5857 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -97,8 +97,9 @@ namespace AppInstaller::Manifest SilentWithProgress, }; - enum class InstallerReturnCodeEnum + enum class ExpectedReturnCodeEnum { + Unknown, PackageInUse, InstallInProgress, FileInUse, @@ -109,6 +110,12 @@ namespace AppInstaller::Manifest ContactSupport, }; + struct ExpectedReturnCode + { + DWORD InstallerReturnCode; + ExpectedReturnCodeEnum ReturnResponse; + }; + enum class PlatformEnum { Unknown, @@ -259,6 +266,8 @@ namespace AppInstaller::Manifest ManifestTypeEnum ConvertToManifestTypeEnum(const std::string& in); + ExpectedReturnCodeEnum ConvertToExpectedReturnCodeEnum(const std::string& in); + std::string_view InstallerTypeToString(InstallerTypeEnum installerType); std::string_view ScopeToString(ScopeEnum scope); @@ -274,4 +283,7 @@ namespace AppInstaller::Manifest // Get a list of default switches for known installer types std::map GetDefaultKnownSwitches(InstallerTypeEnum installerType); + + // Get a lsit of default return codes for known installer types + std::map GetDefaultKnownReturnCodes(InstallerTypeEnum installerType); } \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h index 32b342a47e..1197e3cbab 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h @@ -51,7 +51,7 @@ namespace AppInstaller::Manifest std::vector InstallerSuccessCodes; - std::map ExpectedReturnCodes; + std::map ExpectedReturnCodes; UpdateBehaviorEnum UpdateBehavior = UpdateBehaviorEnum::Install; diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h b/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h index 9085681ef9..c5cb378c48 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestYamlPopulator.h @@ -39,7 +39,7 @@ namespace AppInstaller::Manifest AppInstaller::Manifest::Manifest* m_p_manifest = nullptr; AppInstaller::Manifest::ManifestInstaller* m_p_installer = nullptr; std::map* m_p_switches = nullptr; - std::map* m_p_returnCodes = nullptr; + AppInstaller::Manifest::ExpectedReturnCode* m_p_expectedReturnCode = nullptr; AppInstaller::Manifest::DependencyList* m_p_dependencyList = nullptr; AppInstaller::Manifest::Dependency* m_p_packageDependency = nullptr; AppInstaller::Manifest::ManifestLocalization* m_p_localization = nullptr; @@ -69,6 +69,7 @@ namespace AppInstaller::Manifest void ProcessDependenciesNode(DependencyType type, const YAML::Node& rootNode); std::vector ProcessPackageDependenciesNode(const YAML::Node& rootNode); std::vector ProcessAgreementsNode(const YAML::Node& agreementsNode); + std::vector ProcessExpectedReturnCodesNode(const YAML::Node& returnCodesNode); std::vector PopulateManifestInternal(const YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, bool fullValidation); }; From e6242067c7696a69c3728361bb614b429b2ec007 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 1 Sep 2021 16:53:48 -0700 Subject: [PATCH 05/17] Include MSIX install in error code checking --- .../Workflows/InstallFlow.cpp | 22 +++++++++++++------ .../Workflows/InstallFlow.h | 10 ++++++--- src/AppInstallerCommonCore/Errors.cpp | 7 ++++++ .../Public/AppInstallerErrors.h | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 04eee99844..ba6ded3882 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -500,11 +500,9 @@ namespace AppInstaller::CLI::Workflow } catch (const wil::ResultException& re) { - const auto& manifest = context.Get(); - Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, "MSIX", re.GetErrorCode()); - - context.Reporter.Error() << GetUserPresentableMessage(re) << std::endl; - AICLI_TERMINATE_CONTEXT(re.GetErrorCode()); + context.Add(re.GetErrorCode()); + context << ReportInstallerResult("MSIX", /* isHResult */ true); + return; } if (registrationDeferred) @@ -525,7 +523,17 @@ namespace AppInstaller::CLI::Workflow { const auto& manifest = context.Get(); Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, m_installerType, installResult); - context.Reporter.Error() << Resource::String::InstallerFailedWithCode << ' ' << installResult << std::endl; + + HRESULT hr = APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED; + if (m_isHResult) + { + hr = installResult; + context.Reporter.Error() << Resource::String::InstallerFailedWithCode << ' ' << GetUserPresentableMessage(installResult) << std::endl; + } + else + { + context.Reporter.Error() << Resource::String::InstallerFailedWithCode << ' ' << installResult << std::endl; + } // Show installer log path if exists if (context.Contains(Execution::Data::LogPath) && std::filesystem::exists(context.Get())) @@ -543,7 +551,7 @@ namespace AppInstaller::CLI::Workflow AICLI_TERMINATE_CONTEXT(returnCode.HResult); } - AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); + AICLI_TERMINATE_CONTEXT(hr); } else { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index 988e6e12fb..90ae383b9a 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -116,17 +116,21 @@ namespace AppInstaller::CLI::Workflow // Reports the return code returned by the installer. // Required Args: None - // Inputs: Installer, InstallerResult + // Inputs: Manifest, Installer, InstallerResult // Outputs: None struct ReportInstallerResult : public WorkflowTask { - ReportInstallerResult(std::string_view installerType) : WorkflowTask("ReportInstallerResult"), m_installerType(installerType) {} + ReportInstallerResult(std::string_view installerType, bool isHResult = false) : + WorkflowTask("ReportInstallerResult"), m_installerType(installerType), m_isHResult(isHResult) {} void operator()(Execution::Context& context) const override; private: - // Installer type used when reporting failures + // Installer type used when reporting failures. std::string_view m_installerType; + // Whether the installer result is an HRESULT. + // In case of failure we would return that HRESULT directly instead of a generic one. + bool m_isHResult; }; diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp index 271347f432..249ba440aa 100644 --- a/src/AppInstallerCommonCore/Errors.cpp +++ b/src/AppInstallerCommonCore/Errors.cpp @@ -206,6 +206,13 @@ namespace AppInstaller return e.what(); } + std::string GetUserPresentableMessage(HRESULT hr) + { + std::ostringstream strstr; + GetUserPresentableMessageForHR(strstr, hr); + return strstr.str(); + } + #ifndef WINGET_DISABLE_FOR_FUZZING std::string GetUserPresentableMessage(const winrt::hresult_error& hre) { diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 4b0b2f6e20..9cc44bc555 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -96,6 +96,7 @@ namespace AppInstaller // Gets error messages that are presentable to the user. std::string GetUserPresentableMessage(const wil::ResultException& re); std::string GetUserPresentableMessage(const std::exception& e); + std::string GetUserPresentableMessage(HRESULT hr); #ifndef WINGET_DISABLE_FOR_FUZZING std::string GetUserPresentableMessage(const winrt::hresult_error& hre); From 384d6f247712a44d3c8dd2d9dc719fca9a7c7c69 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Thu, 2 Sep 2021 17:04:18 -0700 Subject: [PATCH 06/17] Use specific error for MSI install --- src/AppInstallerCLICore/Workflows/InstallFlow.cpp | 10 ++++------ src/AppInstallerCLICore/Workflows/InstallFlow.h | 9 +++++---- src/AppInstallerCommonCore/Errors.cpp | 2 ++ src/AppInstallerCommonCore/Public/AppInstallerErrors.h | 1 + 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index ba6ded3882..5ca6923a67 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -463,7 +463,7 @@ namespace AppInstaller::CLI::Workflow GetInstallerArgs << RenameDownloadedInstaller << ShellExecuteInstallImpl << - ReportInstallerResult("ShellExecute"sv); + ReportInstallerResult("ShellExecute"sv, APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED); } void DirectMSIInstall(Execution::Context& context) @@ -472,7 +472,7 @@ namespace AppInstaller::CLI::Workflow GetInstallerArgs << RenameDownloadedInstaller << DirectMSIInstallImpl << - ReportInstallerResult("MsiInstallProduct"sv); + ReportInstallerResult("MsiInstallProduct"sv, APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED, /* isHResult */ true); } void MsixInstall(Execution::Context& context) @@ -501,7 +501,7 @@ namespace AppInstaller::CLI::Workflow catch (const wil::ResultException& re) { context.Add(re.GetErrorCode()); - context << ReportInstallerResult("MSIX", /* isHResult */ true); + context << ReportInstallerResult("MSIX", re.GetErrorCode(), /* isHResult */ true); return; } @@ -524,10 +524,8 @@ namespace AppInstaller::CLI::Workflow const auto& manifest = context.Get(); Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, m_installerType, installResult); - HRESULT hr = APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED; if (m_isHResult) { - hr = installResult; context.Reporter.Error() << Resource::String::InstallerFailedWithCode << ' ' << GetUserPresentableMessage(installResult) << std::endl; } else @@ -551,7 +549,7 @@ namespace AppInstaller::CLI::Workflow AICLI_TERMINATE_CONTEXT(returnCode.HResult); } - AICLI_TERMINATE_CONTEXT(hr); + AICLI_TERMINATE_CONTEXT(m_hr); } else { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h index 90ae383b9a..3a5d90fbf5 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.h +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -120,16 +120,17 @@ namespace AppInstaller::CLI::Workflow // Outputs: None struct ReportInstallerResult : public WorkflowTask { - ReportInstallerResult(std::string_view installerType, bool isHResult = false) : - WorkflowTask("ReportInstallerResult"), m_installerType(installerType), m_isHResult(isHResult) {} + ReportInstallerResult(std::string_view installerType, HRESULT hr, bool isHResult = false) : + WorkflowTask("ReportInstallerResult"), m_installerType(installerType), m_hr(hr), m_isHResult(isHResult) {} void operator()(Execution::Context& context) const override; private: // Installer type used when reporting failures. std::string_view m_installerType; - // Whether the installer result is an HRESULT. - // In case of failure we would return that HRESULT directly instead of a generic one. + // Result to return if the installer failed. + HRESULT m_hr; + // Whether the installer result is an HRESULT. This guides how we show it. bool m_isHResult; }; diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp index 249ba440aa..4b14855421 100644 --- a/src/AppInstallerCommonCore/Errors.cpp +++ b/src/AppInstallerCommonCore/Errors.cpp @@ -148,6 +148,8 @@ namespace AppInstaller return "Error reading input in prompt"; case APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT: return "Arguments for msiexec are invalid"; + case APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED: + return "Running MSI install failed"; case APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE: return "Application is currently running.Exit the application then try again."; case APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS: diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 9cc44bc555..0becf26ca6 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -80,6 +80,7 @@ #define APPINSTALLER_CLI_ERROR_LICENSE_NOT_ACCEPTED ((HRESULT)0x8a150041) #define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8a150042) #define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150043) +#define APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED ((HRESULT)0x8a150044) #define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150101) #define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150102) From 56be7e9ff408d53debcba517592c6bfda49fc780 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 13 Sep 2021 12:36:49 -0700 Subject: [PATCH 07/17] Add more exit code categories --- .../v1.1.0/manifest.installer.1.1.0.json | 9 +++++- .../v1.1.0/manifest.singleton.1.1.0.json | 9 +++++- src/AppInstallerCLICore/Resources.h | 7 +++++ .../Workflows/InstallFlow.cpp | 14 ++++++++++ .../Shared/Strings/en-us/winget.resw | 23 ++++++++++++++- .../InstallFlowTest_ExpectedReturnCodes.yaml | 14 ++++++++++ src/AppInstallerCommonCore/Errors.cpp | 14 ++++++++++ .../Manifest/ManifestCommon.cpp | 28 +++++++++++++++++++ .../Public/AppInstallerErrors.h | 7 +++++ .../Public/winget/ManifestCommon.h | 7 +++++ 10 files changed, 129 insertions(+), 3 deletions(-) diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index ba2d65b37c..0b9ee1e4cd 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -168,7 +168,14 @@ "DiskFull", "InsufficientMemory", "NoNetwork", - "ContactSupport" + "ContactSupport", + "RebootRequiredToFinish", + "RebootRequiredForInstall", + "RebootInitiated", + "CancelledByUser", + "AlreadyInstalled", + "Downgrade", + "BlockedByPolicy" ] } } diff --git a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json index 5f5276cb02..3f1e7a41d1 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json @@ -201,7 +201,14 @@ "DiskFull", "InsufficientMemory", "NoNetwork", - "ContactSupport" + "ContactSupport", + "RebootRequiredToFinish", + "RebootRequiredForInstall", + "RebootInitiated", + "CancelledByUser", + "AlreadyInstalled", + "Downgrade", + "BlockedByPolicy" ] } } diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 58c4f1752e..1060e0de23 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -108,14 +108,21 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(InstallerLogAvailable); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowInstallSuccess); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowRegistrationDeferred); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeAlreadyInstalled); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeBlockedByPolicy); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeCancelledByUser); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeContactSupport); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeDiskFull); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeDowngrade); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeFileInUse); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeInstallInProgress); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeInsufficientMemory); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeMissingDependency); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeNoNetwork); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodePackageInUse); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeRebootInitiated); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeRebootRequiredForInstall); + WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowReturnCodeRebootRequiredToFinish); WINGET_DEFINE_RESOURCE_STRINGID(InstallFlowStartingPackageInstall); WINGET_DEFINE_RESOURCE_STRINGID(InstallForceArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(InstallScopeDescription); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 44fea1f2e4..150d252cea 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -80,6 +80,20 @@ namespace AppInstaller::CLI::Workflow return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK, Resource::String::InstallFlowReturnCodeNoNetwork); case ExpectedReturnCodeEnum::ContactSupport: return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT, Resource::String::InstallFlowReturnCodeContactSupport); + case ExpectedReturnCodeEnum::RebootRequiredToFinish: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH, Resource::String::InstallFlowReturnCodeRebootRequiredToFinish); + case ExpectedReturnCodeEnum::RebootRequiredForInstall: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL, Resource::String::InstallFlowReturnCodeRebootRequiredForInstall); + case ExpectedReturnCodeEnum::RebootInitiated: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED, Resource::String::InstallFlowReturnCodeRebootInitiated); + case ExpectedReturnCodeEnum::CancelledByUser: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER, Resource::String::InstallFlowReturnCodeCancelledByUser); + case ExpectedReturnCodeEnum::AlreadyInstalled: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED, Resource::String::InstallFlowReturnCodeAlreadyInstalled); + case ExpectedReturnCodeEnum::Downgrade: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE, Resource::String::InstallFlowReturnCodeDowngrade); + case ExpectedReturnCodeEnum::BlockedByPolicy: + return ExpectedReturnCode(returnCode, APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY, Resource::String::InstallFlowReturnCodeBlockedByPolicy); default: THROW_HR(E_UNEXPECTED); } diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 9aedbba2a3..5f173545b5 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1100,7 +1100,28 @@ Do you agree to the terms? This application requires internet connectivity. Connect to a network then try again. - This application encountered an error during installation. Contact support. + This application encountered an error during installation. Contact support. + + + Restart your PC to finish installation. + + + Your PC will restart to finish installation. + + + Installation failed. Restart your PC then try again. + + + You cancelled the installation. + + + Another version of this application is already installed. + + + A higher version of this application is already installed. + + + Organization policies are preventing installation. Contact your admin. Installation abandoned diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml index 4a7937f29c..918d5d927c 100644 --- a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml +++ b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml @@ -28,5 +28,19 @@ Installers: ReturnResponse: NoNetwork - InstallerReturnCode: 8 ReturnResponse: ContactSupport + - InstallerReturnCode: 9 + ReturnResponse: RebootRequiredToFinish + - InstallerReturnCode: 10 + ReturnResponse: RebootRequiredForInstall + - InstallerReturnCode: 11 + ReturnResponse: RebootInitiated + - InstallerReturnCode: 12 + ReturnResponse: CancelledByUser + - InstallerReturnCode: 13 + ReturnResponse: AlreadyInstalled + - InstallerReturnCode: 14 + ReturnResponse: Downgrade + - InstallerReturnCode: 15 + ReturnResponse: BlockedByPolicy ManifestType: singleton ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp index 82f1146807..057ffee5a0 100644 --- a/src/AppInstallerCommonCore/Errors.cpp +++ b/src/AppInstallerCommonCore/Errors.cpp @@ -176,6 +176,20 @@ namespace AppInstaller return "This application requires internet connectivity.Connect to a network then try again."; case APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT: return "This application encountered an error during installation.Contact support."; + case APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH: + return "Restart your PC to finish installation."; + case APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL: + return "Your PC will restart to finish installation."; + case APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED: + return "Installation failed. Restart your PC then try again."; + case APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER: + return "You cancelled the installation."; + case APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED: + return "Another version of this application is already installed."; + case APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE: + return "A higher version of this application is already installed."; + case APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY: + return "Organization policies are preventing installation. Contact your admin."; default: return "Unknown Error Code"; } diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index 9ab0abe8c1..cb77074789 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -318,6 +318,34 @@ namespace AppInstaller::Manifest { result = ExpectedReturnCodeEnum::ContactSupport; } + else if (Utility::CaseInsensitiveEquals(in, "RebootRequiredToFinish")) + { + result = ExpectedReturnCodeEnum::RebootRequiredToFinish; + } + else if (Utility::CaseInsensitiveEquals(in, "RebootRequiredForInstall")) + { + result = ExpectedReturnCodeEnum::RebootRequiredForInstall; + } + else if (Utility::CaseInsensitiveEquals(in, "RebootInitiated")) + { + result = ExpectedReturnCodeEnum::RebootInitiated; + } + else if (Utility::CaseInsensitiveEquals(in, "CancelledByUser")) + { + result = ExpectedReturnCodeEnum::CancelledByUser; + } + else if (Utility::CaseInsensitiveEquals(in, "AlreadyInstalled")) + { + result = ExpectedReturnCodeEnum::AlreadyInstalled; + } + else if (Utility::CaseInsensitiveEquals(in, "Downgrade")) + { + result = ExpectedReturnCodeEnum::Downgrade; + } + else if (Utility::CaseInsensitiveEquals(in, "BlockedByPolicy")) + { + result = ExpectedReturnCodeEnum::BlockedByPolicy; + } return result; } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 6fc41becb3..1cd2e19a9c 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -95,6 +95,13 @@ #define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8a150106) #define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a150107) #define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a150108) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH ((HRESULT)0x8a150109) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL ((HRESULT)0x8a150110) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED ((HRESULT)0x8a150111) +#define APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER ((HRESULT)0x8a150112) +#define APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED ((HRESULT)0x8a150113) +#define APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE ((HRESULT)0x8a150114) +#define APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY ((HRESULT)0x8a150115) namespace AppInstaller diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index d3de02af2e..2da10e3741 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -108,6 +108,13 @@ namespace AppInstaller::Manifest InsufficientMemory, NoNetwork, ContactSupport, + RebootRequiredToFinish, + RebootRequiredForInstall, + RebootInitiated, + CancelledByUser, + AlreadyInstalled, + Downgrade, + BlockedByPolicy, }; struct ExpectedReturnCode From 6d3497b3c485565a4224ab1ff9a76f857d76ed32 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 13 Sep 2021 12:42:05 -0700 Subject: [PATCH 08/17] Add default mapping --- .../Manifest/ManifestCommon.cpp | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index cb77074789..b623f2ed1c 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -491,20 +491,33 @@ namespace AppInstaller::Manifest { { ERROR_INSTALL_ALREADY_RUNNING, ExpectedReturnCodeEnum::InstallInProgress }, { ERROR_DISK_FULL, ExpectedReturnCodeEnum::DiskFull }, - // { ERROR_SUCCESS_REBOOT_REQUIRED, ExpectedReturnCodeEnum::RebootRequiredSuccess }, - // { ERROR_SUCCESS_REBOOT_INITIATED, ExpectedReturnCodeEnum::RebootRequiredSuccess }, - // { ERROR_INSTALL_USEREXIT, ExpectedReturnCodeEnum::UserCancelled }, + { ERROR_INSTALL_SERVICE_FAILURE, ExpectedReturnCodeEnum::ContactSupport }, + { ERROR_SUCCESS_REBOOT_REQUIRED, ExpectedReturnCodeEnum::RebootRequiredToFinish }, + { ERROR_SUCCESS_REBOOT_INITIATED, ExpectedReturnCodeEnum::RebootInitiated }, + { ERROR_INSTALL_USEREXIT, ExpectedReturnCodeEnum::CancelledByUser }, + { ERROR_PRODUCT_VERSION, ExpectedReturnCodeEnum::AlreadyInstalled }, + { ERROR_INSTALL_REJECTED, ExpectedReturnCodeEnum::BlockedByPolicy }, }; case InstallerTypeEnum::Inno: // See https://jrsoftware.org/ishelp/index.php?topic=setupexitcodes return { - // { 2, ExpectedReturnCodeEnum::UserCancelled }, - // { 5, ExpectedReturnCodeEnum::UserCancelled }, - // { 8, ExpectedReturnCodeEnum::RebootRequiredFailure }, + { 2, ExpectedReturnCodeEnum::CancelledByUser }, + { 5, ExpectedReturnCodeEnum::CancelledByUser }, + { 8, ExpectedReturnCodeEnum::RebootRequiredForInstall }, }; case InstallerTypeEnum::Msix: // See https://docs.microsoft.com/en-us/windows/win32/appxpkg/troubleshooting + return + { + { ERROR_INSTALL_PREREQUISITE_FAILED, ExpectedReturnCodeEnum::MissingDependency }, + { ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED, ExpectedReturnCodeEnum::MissingDependency }, + { ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE, ExpectedReturnCodeEnum::MissingDependency }, + { ERROR_INSTALL_OUT_OF_DISK_SPACE, ExpectedReturnCodeEnum::DiskFull }, + { ERROR_INSTALL_CANCEL, ExpectedReturnCodeEnum::CancelledByUser }, + { ERROR_PACKAGE_ALREADY_EXISTS, ExpectedReturnCodeEnum::AlreadyInstalled }, + { ERROR_INSTALL_PACKAGE_DOWNGRADE, ExpectedReturnCodeEnum::Downgrade }, + }; default: return {}; } From b33bc572bb5dde4e53db0eb53b8ac0ee7afc0d82 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 13 Sep 2021 12:55:42 -0700 Subject: [PATCH 09/17] Fix bad merge --- src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp | 3 +-- src/AppInstallerCommonCore/Public/AppInstallerErrors.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp index a311c551e4..346d84acf2 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestYamlPopulator.cpp @@ -266,7 +266,6 @@ namespace AppInstaller::Manifest if (manifestVersion >= ManifestVer{ s_ManifestVersionV1_1 }) { - std::move(v1_1CommonFields.begin(), v1_1CommonFields.end(), std::inserter(result, result.end())); std::vector fields_v1_1 = { { "InstallerAbortsTerminal", [this](const YAML::Node& value)->ValidationErrors { m_p_installer->InstallerAbortsTerminal = value.as(); return {}; } }, @@ -661,7 +660,7 @@ namespace AppInstaller::Manifest } m_p_installer->ExpectedReturnCodes = returnCodes; - + return resultErrors; } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 1cd2e19a9c..9268604936 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -79,13 +79,13 @@ #define APPINSTALLER_CLI_ERROR_STREAM_READ_FAILURE ((HRESULT)0x8a150040) #define APPINSTALLER_CLI_ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8a150041) #define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8a150042) -#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150043) #define APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST ((HRESULT)0x8a150043) #define APPINSTALLER_CLI_ERROR_RESTSOURCE_ENDPOINT_NOT_FOUND ((HRESULT)0x8a150044) #define APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED ((HRESULT)0x8a150045) #define APPINSTALLER_CLI_ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8a150046) #define APPINSTALLER_CLI_ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH ((HRESULT)0x8a150047) #define APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED ((HRESULT)0x8a150048) +#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150049) #define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150101) #define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150102) From ab7e7c9937743a9066cc8de501a3170b98ecc58e Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 13 Sep 2021 13:27:27 -0700 Subject: [PATCH 10/17] Spelling --- .github/actions/spelling/allow.txt | 3 +++ .vscode/settings.json | 6 ------ src/AppInstallerCommonCore/Public/winget/ManifestCommon.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 148007fb18..f1eb1d5e97 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -334,6 +334,7 @@ pdb PEVENT pfp PGP +php PII pipssource placeholders @@ -408,6 +409,7 @@ SERVICEPACKMAJOR SERVICEPACKMINOR setfill setschemaversion +setupexitcodes setvariable setw shcore @@ -536,6 +538,7 @@ URegular uri url urlmon +USEREXIT userguide USERPROFILE usersources diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 21cceeda8e..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "files.associations": { - "type_traits": "cpp", - "set": "cpp" - } -} \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h index 2da10e3741..2b7d9de06d 100644 --- a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h +++ b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -320,6 +320,6 @@ namespace AppInstaller::Manifest // Get a list of default switches for known installer types std::map GetDefaultKnownSwitches(InstallerTypeEnum installerType); - // Get a lsit of default return codes for known installer types + // Get a list of default return codes for known installer types std::map GetDefaultKnownReturnCodes(InstallerTypeEnum installerType); } \ No newline at end of file From e94dc485711914600af98401c5a54a5297f67050 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Mon, 13 Sep 2021 16:31:47 -0700 Subject: [PATCH 11/17] Add support for REST sources --- .../v1.1.0/manifest.installer.1.1.0.json | 2 +- .../RestInterface_1_1.cpp | 8 ++++++- .../1_1/Json/ManifestDeserializer_1_1.cpp | 24 +++++++++++++++++++ .../Rest/Schema/JsonHelper.cpp | 12 ++++++++++ .../Rest/Schema/JsonHelper.h | 2 ++ 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index 0b9ee1e4cd..00e05a191a 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -138,7 +138,7 @@ "enum": [ 0 ] }, "minimum": -2147483648, - "maximum": 429496729, + "maximum": 429496725, "description": "An exit code that can be returned by the installer after execution" }, "InstallerSuccessCodes": { diff --git a/src/AppInstallerCLITests/RestInterface_1_1.cpp b/src/AppInstallerCLITests/RestInterface_1_1.cpp index 905adba679..1009f92282 100644 --- a/src/AppInstallerCLITests/RestInterface_1_1.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_1.cpp @@ -176,7 +176,11 @@ namespace }], "Markets" : { "AllowedMarkets": [ "US" ] - } + }, + "ExpectedReturnCodes": [{ + "InstallerReturnCode": 3, + "ReturnResponse": "InstallInProgress" + }] } ] } @@ -293,6 +297,8 @@ namespace REQUIRE(actualInstaller.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe); REQUIRE(actualInstaller.Markets.AllowedMarkets.size() == 1); REQUIRE(actualInstaller.Markets.AllowedMarkets.at(0) == "US"); + REQUIRE(actualInstaller.ExpectedReturnCodes.size() == 1); + REQUIRE(actualInstaller.ExpectedReturnCodes[3] == ExpectedReturnCodeEnum::InstallInProgress); } }; } diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index d60fc3d985..e11c37e2f0 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -28,6 +28,9 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json constexpr std::string_view AllowedMarkets = "AllowedMarkets"sv; constexpr std::string_view ExcludedMarkets = "ExcludedMarkets"sv; constexpr std::string_view ElevationRequirement = "ElevationRequirement"sv; + constexpr std::string_view ExpectedReturnCodes = "ExpectedReturnCodes"sv; + constexpr std::string_view InstallerReturnCode = "InstallerReturnCode"sv; + constexpr std::string_view ReturnResponse = "ReturnResponse"sv; // Locale constexpr std::string_view ReleaseNotes = "ReleaseNotes"sv; @@ -123,6 +126,27 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json installer.Markets.AllowedMarkets = V1_0::Json::ManifestDeserializer::ConvertToManifestStringArray( JsonHelper::GetRawStringArrayFromJsonNode(marketsNode.value().get(), JsonHelper::GetUtilityString(AllowedMarkets))); } + + // Expected return codes + std::optional> expectedReturnCodesNode = JsonHelper::GetRawJsonArrayFromJsonNode(installerJsonObject, JsonHelper::GetUtilityString(ExpectedReturnCodes)); + if (expectedReturnCodesNode) + { + for (auto& returnCodeNode : expectedReturnCodesNode.value().get()) + { + ExpectedReturnCodeEnum returnResponse = Manifest::ConvertToExpectedReturnCodeEnum(JsonHelper::GetRawStringValueFromJsonNode(returnCodeNode, JsonHelper::GetUtilityString(ReturnResponse)).value_or("")); + DWORD installerReturnCode = JsonHelper::GetRawIntValueFromJsonNode(returnCodeNode, JsonHelper::GetUtilityString(InstallerReturnCode)).value_or(0); + + // Only add when it is valid + if (installerReturnCode != 0 && returnResponse != ExpectedReturnCodeEnum::Unknown) + { + if (!installer.ExpectedReturnCodes.insert({ installerReturnCode, returnResponse }).second) + { + AICLI_LOG(Repo, Error, << "Expected return codes cannot have repeated value."); + return {}; + } + } + } + } } return result; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.cpp index f8d5d25a23..8fd4b38ab3 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.cpp @@ -52,6 +52,18 @@ namespace AppInstaller::Repository::Rest::Schema return value.as_integer(); } + std::optional JsonHelper::GetRawIntValueFromJsonNode(const web::json::value& node, const utility::string_t& keyName) + { + std::optional> jsonValue = GetJsonValueFromNode(node, keyName); + + if (jsonValue) + { + return GetRawIntValueFromJsonValue(jsonValue.value().get()); + } + + return {}; + } + std::optional JsonHelper::GetRawBoolValueFromJsonValue(const web::json::value& value) { if (value.is_null() || !value.is_boolean()) diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.h b/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.h index e51b56a3d1..ca68c11ac1 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.h +++ b/src/AppInstallerRepositoryCore/Rest/Schema/JsonHelper.h @@ -23,6 +23,8 @@ namespace AppInstaller::Repository::Rest::Schema static std::optional GetRawIntValueFromJsonValue(const web::json::value& value); + static std::optional GetRawIntValueFromJsonNode(const web::json::value& value, const utility::string_t& keyName); + static utility::string_t GetUtilityString(std::string_view nodeName); static std::vector GetRawStringArrayFromJsonNode(const web::json::value& node, const utility::string_t& keyName); From 6c02825174b70da5c6f86d84d175f64d485a0d1f Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 13:27:33 -0700 Subject: [PATCH 12/17] PR comments --- .../v1.1.0/manifest.installer.1.1.0.json | 33 +- .../v1.1.0/manifest.singleton.1.1.0.json | 34 +- .../Workflows/InstallFlow.cpp | 4 +- src/AppInstallerCLIE2ETests/Constants.cs | 19 + .../Shared/Strings/en-us/winget.resw | 2 +- .../AppInstallerCLITests.vcxproj | 6 + .../AppInstallerCLITests.vcxproj.filters | 1044 +++++++++-------- .../RestInterface_1_1.cpp | 2 +- .../InstallFlowTest_ExpectedReturnCodes.yaml | 30 +- .../TestData/ManifestV1_1-Singleton.yaml | 6 + .../ManifestV1_1-MultiFile-Installer.yaml | 6 + src/AppInstallerCLITests/YamlManifest.cpp | 7 + .../Manifest/ManifestCommon.cpp | 45 +- .../1_1/Json/ManifestDeserializer_1_1.cpp | 2 +- 14 files changed, 646 insertions(+), 594 deletions(-) diff --git a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json index 00e05a191a..324507318b 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.installer.1.1.0.json @@ -159,27 +159,28 @@ "$ref": "#/definitions/InstallerReturnCode" }, "ReturnResponse": { - "type": [ "string", "null" ], + "type": "string", "enum": [ - "PackageInUse", - "InstallInProgress", - "FileInUse", - "MissingDependency", - "DiskFull", - "InsufficientMemory", - "NoNetwork", - "ContactSupport", - "RebootRequiredToFinish", - "RebootRequiredForInstall", - "RebootInitiated", - "CancelledByUser", - "AlreadyInstalled", - "Downgrade", - "BlockedByPolicy" + "packageInUse", + "installInProgress", + "fileInUse", + "missingDependency", + "diskFull", + "insufficientMemory", + "noNetwork", + "contactSupport", + "rebootRequiredToFinish", + "rebootRequiredForInstall", + "rebootInitiated", + "cancelledByUser", + "alreadyInstalled", + "downgrade", + "blockedByPolicy" ] } } }, + "maxItems": 128, "description": "Installer exit codes for common errors" }, "UpgradeBehavior": { diff --git a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json index 3f1e7a41d1..9ef00954d2 100644 --- a/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json +++ b/schemas/JSON/manifests/v1.1.0/manifest.singleton.1.1.0.json @@ -192,28 +192,28 @@ "$ref": "#/definitions/InstallerReturnCode" }, "ReturnResponse": { - "type": [ "string", "null" ], + "type": "string", "enum": [ - "PackageInUse", - "InstallInProgress", - "FileInUse", - "MissingDependency", - "DiskFull", - "InsufficientMemory", - "NoNetwork", - "ContactSupport", - "RebootRequiredToFinish", - "RebootRequiredForInstall", - "RebootInitiated", - "CancelledByUser", - "AlreadyInstalled", - "Downgrade", - "BlockedByPolicy" + "packageInUse", + "installInProgress", + "fileInUse", + "missingDependency", + "diskFull", + "insufficientMemory", + "noNetwork", + "contactSupport", + "rebootRequiredToFinish", + "rebootRequiredForInstall", + "rebootInitiated", + "cancelledByUser", + "alreadyInstalled", + "downgrade", + "blockedByPolicy" ] } } }, - "maxItems": 16, + "maxItems": 128, "description": "Installer exit codes for common errors" }, "UpgradeBehavior": { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp index 150d252cea..8f6b17964a 100644 --- a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp +++ b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -491,7 +491,7 @@ namespace AppInstaller::CLI::Workflow GetInstallerArgs << RenameDownloadedInstaller << DirectMSIInstallImpl << - ReportInstallerResult("MsiInstallProduct"sv, APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED, /* isHResult */ true); + ReportInstallerResult("MsiInstallProduct"sv, APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED); } void MsixInstall(Execution::Context& context) @@ -520,7 +520,7 @@ namespace AppInstaller::CLI::Workflow catch (const wil::ResultException& re) { context.Add(re.GetErrorCode()); - context << ReportInstallerResult("MSIX", re.GetErrorCode(), /* isHResult */ true); + context << ReportInstallerResult("MSIX"sv, re.GetErrorCode(), /* isHResult */ true); return; } diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index 3bc90c69f8..e1a3a8d4e2 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -134,6 +134,25 @@ public class ErrorCode public const int ERROR_SOURCE_OPEN_FAILED = unchecked((int)0x8a150045); public const int ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED = unchecked((int)0x8a150046); public const int ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH = unchecked((int)0x8a150047); + public const int ERROR_MISSING_RESOURCE_FILE = unchecked((int)0x8a150048); + public const int ERROR_MSI_INSTALL_FAILED = unchecked((int)0x8a150049); + public const int ERROR_INVALID_MSIEXEC_ARGUMENT = unchecked((int)0x8a150050); + + public const int ERROR_INSTALL_PACKAGE_IN_USE = unchecked((int)0x8a150101); + public const int ERROR_INSTALL_INSTALL_IN_PROGRESS = unchecked((int)0x8a150102); + public const int ERROR_INSTALL_FILE_IN_USE = unchecked((int)0x8a150103); + public const int ERROR_INSTALL_MISSING_DEPENDENCY = unchecked((int)0x8a150104); + public const int ERROR_INSTALL_DISK_FULL = unchecked((int)0x8a150105); + public const int ERROR_INSTALL_INSUFFICIENT_MEMORY = unchecked((int)0x8a150106); + public const int ERROR_INSTALL_NO_NETWORK = unchecked((int)0x8a150107); + public const int ERROR_INSTALL_CONTACT_SUPPORT = unchecked((int)0x8a150108); + public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH = unchecked((int)0x8a150109); + public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL = unchecked((int)0x8a150110); + public const int ERROR_INSTALL_REBOOT_INITIATED = unchecked((int)0x8a150111); + public const int ERROR_INSTALL_CANCELLED_BY_USER = unchecked((int)0x8a150112); + public const int ERROR_INSTALL_ALREADY_INSTALLED = unchecked((int)0x8a150113); + public const int ERROR_INSTALL_DOWNGRADE = unchecked((int)0x8a150114); + public const int ERROR_INSTALL_BLOCKED_BY_POLICY = unchecked((int)0x8a150115); } } } diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index f31bfdf851..84811ce8b3 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1104,7 +1104,7 @@ Do you agree to the terms? Another installation is already in progress. Try again later. - One or more file is being used. Exit the application then try again. + One or more file are being used. Exit the application then try again. This package has a dependency missing from your system. diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index cfa51bfa1c..3057c3d1e9 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -340,6 +340,12 @@ true + + true + + + true + true diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 1fa388803d..3cbc648c79 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -1,520 +1,526 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {d5cac203-3846-4b39-a1cd-8de9303757b4} - - - {69fcd25c-e737-4d28-a6d1-39ce491bf293} - - - {81fadc81-4327-4b9e-b588-97155b770aa3} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - - - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d5cac203-3846-4b39-a1cd-8de9303757b4} + + + {69fcd25c-e737-4d28-a6d1-39ce491bf293} + + + {81fadc81-4327-4b9e-b588-97155b770aa3} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + \ No newline at end of file diff --git a/src/AppInstallerCLITests/RestInterface_1_1.cpp b/src/AppInstallerCLITests/RestInterface_1_1.cpp index 1009f92282..16e789f469 100644 --- a/src/AppInstallerCLITests/RestInterface_1_1.cpp +++ b/src/AppInstallerCLITests/RestInterface_1_1.cpp @@ -298,7 +298,7 @@ namespace REQUIRE(actualInstaller.Markets.AllowedMarkets.size() == 1); REQUIRE(actualInstaller.Markets.AllowedMarkets.at(0) == "US"); REQUIRE(actualInstaller.ExpectedReturnCodes.size() == 1); - REQUIRE(actualInstaller.ExpectedReturnCodes[3] == ExpectedReturnCodeEnum::InstallInProgress); + REQUIRE(actualInstaller.ExpectedReturnCodes.at(3) == ExpectedReturnCodeEnum::InstallInProgress); } }; } diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml index 918d5d927c..e2574f9f6d 100644 --- a/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml +++ b/src/AppInstallerCLITests/TestData/InstallFlowTest_ExpectedReturnCodes.yaml @@ -13,34 +13,34 @@ Installers: InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B ExpectedReturnCodes: - InstallerReturnCode: 1 - ReturnResponse: PackageInUse + ReturnResponse: packageInUse - InstallerReturnCode: 2 - ReturnResponse: InstallInProgress + ReturnResponse: installInProgress - InstallerReturnCode: 3 - ReturnResponse: FileInUse + ReturnResponse: fileInUse - InstallerReturnCode: 4 - ReturnResponse: MissingDependency + ReturnResponse: missingDependency - InstallerReturnCode: 5 - ReturnResponse: DiskFull + ReturnResponse: diskFull - InstallerReturnCode: 6 - ReturnResponse: InsufficientMemory + ReturnResponse: insufficientMemory - InstallerReturnCode: 7 - ReturnResponse: NoNetwork + ReturnResponse: noNetwork - InstallerReturnCode: 8 - ReturnResponse: ContactSupport + ReturnResponse: contactSupport - InstallerReturnCode: 9 - ReturnResponse: RebootRequiredToFinish + ReturnResponse: rebootRequiredToFinish - InstallerReturnCode: 10 - ReturnResponse: RebootRequiredForInstall + ReturnResponse: rebootRequiredForInstall - InstallerReturnCode: 11 - ReturnResponse: RebootInitiated + ReturnResponse: rebootInitiated - InstallerReturnCode: 12 - ReturnResponse: CancelledByUser + ReturnResponse: cancelledByUser - InstallerReturnCode: 13 - ReturnResponse: AlreadyInstalled + ReturnResponse: alreadyInstalled - InstallerReturnCode: 14 - ReturnResponse: Downgrade + ReturnResponse: downgrade - InstallerReturnCode: 15 - ReturnResponse: BlockedByPolicy + ReturnResponse: blockedByPolicy ManifestType: singleton ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCLITests/TestData/ManifestV1_1-Singleton.yaml b/src/AppInstallerCLITests/TestData/ManifestV1_1-Singleton.yaml index 4816fec1f8..9d0f04aa95 100644 --- a/src/AppInstallerCLITests/TestData/ManifestV1_1-Singleton.yaml +++ b/src/AppInstallerCLITests/TestData/ManifestV1_1-Singleton.yaml @@ -91,6 +91,9 @@ AppsAndFeaturesEntries: Markets: AllowedMarkets: - US +ExpectedReturnCodes: + - InstallerReturnCode: 10 + ReturnResponse: packageInUse Installers: - Architecture: x86 @@ -149,6 +152,9 @@ Installers: Markets: ExcludedMarkets: - "US" + ExpectedReturnCodes: + - InstallerReturnCode: 2 + ReturnResponse: contactSupport ManifestType: singleton ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCLITests/TestData/MultiFileManifestV1_1/ManifestV1_1-MultiFile-Installer.yaml b/src/AppInstallerCLITests/TestData/MultiFileManifestV1_1/ManifestV1_1-MultiFile-Installer.yaml index ce08541266..bb52de165a 100644 --- a/src/AppInstallerCLITests/TestData/MultiFileManifestV1_1/ManifestV1_1-MultiFile-Installer.yaml +++ b/src/AppInstallerCLITests/TestData/MultiFileManifestV1_1/ManifestV1_1-MultiFile-Installer.yaml @@ -67,6 +67,9 @@ AppsAndFeaturesEntries: Markets: AllowedMarkets: - "US" +ExpectedReturnCodes: + - InstallerReturnCode: 10 + ReturnResponse: packageInUse Installers: - Architecture: x86 @@ -125,6 +128,9 @@ Installers: Markets: ExcludedMarkets: - "US" + ExpectedReturnCodes: + - InstallerReturnCode: 2 + ReturnResponse: contactSupport - Architecture: x64 InstallerType: exe InstallerUrl: https://www.microsoft.com/msixsdk/msixsdkx64.exe diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp index b31b74120d..9bcb2f6e22 100644 --- a/src/AppInstallerCLITests/YamlManifest.cpp +++ b/src/AppInstallerCLITests/YamlManifest.cpp @@ -223,6 +223,8 @@ TEST_CASE("ReadBadManifests", "[ManifestValidation]") { "Manifest-Bad-DuplicateKey.yaml", "Duplicate field found in the manifest." }, { "Manifest-Bad-DuplicateKey-DifferentCase.yaml", "Duplicate field found in the manifest." }, { "Manifest-Bad-DuplicateKey-DifferentCase-lower.yaml", "Duplicate field found in the manifest." }, + { "Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml", "Duplicate installer return code found." }, + { "Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml", "Duplicate installer return code found." }, { "Manifest-Bad-IdInvalid.yaml", "Failed to validate against schema associated with property name 'Id'" }, { "Manifest-Bad-IdMissing.yaml", "Missing required property 'Id'" }, { "Manifest-Bad-InstallersMissing.yaml", "Missing required property 'Installers'" }, @@ -423,6 +425,8 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes REQUIRE(manifest.DefaultInstallerInfo.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe); REQUIRE(manifest.DefaultInstallerInfo.Markets.AllowedMarkets.size() == 1); REQUIRE(manifest.DefaultInstallerInfo.Markets.AllowedMarkets.at(0) == "US"); + REQUIRE(manifest.DefaultInstallerInfo.ExpectedReturnCodes.size() == 1); + REQUIRE(manifest.DefaultInstallerInfo.ExpectedReturnCodes.at(10) == ExpectedReturnCodeEnum::PackageInUse); } if (isSingleton) @@ -484,6 +488,7 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes REQUIRE(installer1.Markets.AllowedMarkets.size() == 0); REQUIRE(installer1.Markets.ExcludedMarkets.size() == 1); REQUIRE(installer1.Markets.ExcludedMarkets.at(0) == "US"); + REQUIRE(installer1.ExpectedReturnCodes.at(2) == ExpectedReturnCodeEnum::ContactSupport); } if (!isSingleton) @@ -513,6 +518,8 @@ void VerifyV1ManifestContent(const Manifest& manifest, bool isSingleton, Manifes REQUIRE(installer2.AppsAndFeaturesEntries.at(0).InstallerType == InstallerTypeEnum::Exe); REQUIRE(installer2.Markets.AllowedMarkets.size() == 1); REQUIRE(installer2.Markets.AllowedMarkets.at(0) == "US"); + REQUIRE(installer2.ExpectedReturnCodes.size() == 1); + REQUIRE(installer2.ExpectedReturnCodes.at(10) == ExpectedReturnCodeEnum::PackageInUse); } // Localization diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp index b623f2ed1c..d4fd35c431 100644 --- a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp +++ b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -284,65 +284,66 @@ namespace AppInstaller::Manifest ExpectedReturnCodeEnum ConvertToExpectedReturnCodeEnum(const std::string& in) { + std::string inStrLower = Utility::ToLower(in); ExpectedReturnCodeEnum result = ExpectedReturnCodeEnum::Unknown; - if (Utility::CaseInsensitiveEquals(in, "PackageInUse")) + if (inStrLower == "packageinuse") { result = ExpectedReturnCodeEnum::PackageInUse; } - else if (Utility::CaseInsensitiveEquals(in, "InstallInProgress")) + else if (inStrLower == "installinprogress") { result = ExpectedReturnCodeEnum::InstallInProgress; } - else if (Utility::CaseInsensitiveEquals(in, "FileInUse")) + else if (inStrLower == "fileinuse") { result = ExpectedReturnCodeEnum::FileInUse; } - else if (Utility::CaseInsensitiveEquals(in, "MissingDependency")) + else if (inStrLower == "missingdependency") { result = ExpectedReturnCodeEnum::MissingDependency; } - else if (Utility::CaseInsensitiveEquals(in, "DiskFull")) + else if (inStrLower == "diskfull") { result = ExpectedReturnCodeEnum::DiskFull; } - else if (Utility::CaseInsensitiveEquals(in, "InsufficientMemory")) + else if (inStrLower == "insufficientmemory") { result = ExpectedReturnCodeEnum::InsufficientMemory; } - else if (Utility::CaseInsensitiveEquals(in, "NoNetwork")) + else if (inStrLower == "nonetwork") { result = ExpectedReturnCodeEnum::NoNetwork; } - else if (Utility::CaseInsensitiveEquals(in, "ContactSupport")) + else if (inStrLower == "contactsupport") { result = ExpectedReturnCodeEnum::ContactSupport; } - else if (Utility::CaseInsensitiveEquals(in, "RebootRequiredToFinish")) + else if (inStrLower == "rebootrequiredtofinish") { result = ExpectedReturnCodeEnum::RebootRequiredToFinish; } - else if (Utility::CaseInsensitiveEquals(in, "RebootRequiredForInstall")) + else if (inStrLower == "rebootrequiredforinstall") { result = ExpectedReturnCodeEnum::RebootRequiredForInstall; } - else if (Utility::CaseInsensitiveEquals(in, "RebootInitiated")) + else if (inStrLower == "rebootinitiated") { result = ExpectedReturnCodeEnum::RebootInitiated; } - else if (Utility::CaseInsensitiveEquals(in, "CancelledByUser")) + else if (inStrLower == "cancelledbyuser") { result = ExpectedReturnCodeEnum::CancelledByUser; } - else if (Utility::CaseInsensitiveEquals(in, "AlreadyInstalled")) + else if (inStrLower == "alreadyinstalled") { result = ExpectedReturnCodeEnum::AlreadyInstalled; } - else if (Utility::CaseInsensitiveEquals(in, "Downgrade")) + else if (inStrLower == "downgrade") { result = ExpectedReturnCodeEnum::Downgrade; } - else if (Utility::CaseInsensitiveEquals(in, "BlockedByPolicy")) + else if (inStrLower == "blockedbypolicy") { result = ExpectedReturnCodeEnum::BlockedByPolicy; } @@ -510,13 +511,13 @@ namespace AppInstaller::Manifest // See https://docs.microsoft.com/en-us/windows/win32/appxpkg/troubleshooting return { - { ERROR_INSTALL_PREREQUISITE_FAILED, ExpectedReturnCodeEnum::MissingDependency }, - { ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED, ExpectedReturnCodeEnum::MissingDependency }, - { ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE, ExpectedReturnCodeEnum::MissingDependency }, - { ERROR_INSTALL_OUT_OF_DISK_SPACE, ExpectedReturnCodeEnum::DiskFull }, - { ERROR_INSTALL_CANCEL, ExpectedReturnCodeEnum::CancelledByUser }, - { ERROR_PACKAGE_ALREADY_EXISTS, ExpectedReturnCodeEnum::AlreadyInstalled }, - { ERROR_INSTALL_PACKAGE_DOWNGRADE, ExpectedReturnCodeEnum::Downgrade }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_PREREQUISITE_FAILED), ExpectedReturnCodeEnum::MissingDependency }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED), ExpectedReturnCodeEnum::MissingDependency }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE), ExpectedReturnCodeEnum::MissingDependency }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_OUT_OF_DISK_SPACE), ExpectedReturnCodeEnum::DiskFull }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_CANCEL), ExpectedReturnCodeEnum::CancelledByUser }, + { HRESULT_FROM_WIN32(ERROR_PACKAGE_ALREADY_EXISTS), ExpectedReturnCodeEnum::AlreadyInstalled }, + { HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_DOWNGRADE), ExpectedReturnCodeEnum::Downgrade }, }; default: return {}; diff --git a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp index e11c37e2f0..c3cfced5b1 100644 --- a/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp +++ b/src/AppInstallerRepositoryCore/Rest/Schema/1_1/Json/ManifestDeserializer_1_1.cpp @@ -134,7 +134,7 @@ namespace AppInstaller::Repository::Rest::Schema::V1_1::Json for (auto& returnCodeNode : expectedReturnCodesNode.value().get()) { ExpectedReturnCodeEnum returnResponse = Manifest::ConvertToExpectedReturnCodeEnum(JsonHelper::GetRawStringValueFromJsonNode(returnCodeNode, JsonHelper::GetUtilityString(ReturnResponse)).value_or("")); - DWORD installerReturnCode = JsonHelper::GetRawIntValueFromJsonNode(returnCodeNode, JsonHelper::GetUtilityString(InstallerReturnCode)).value_or(0); + DWORD installerReturnCode = static_cast(JsonHelper::GetRawIntValueFromJsonNode(returnCodeNode, JsonHelper::GetUtilityString(InstallerReturnCode)).value_or(0)); // Only add when it is valid if (installerReturnCode != 0 && returnResponse != ExpectedReturnCodeEnum::Unknown) From 7b6b908c940a76e5065842119dea2fca2b80da94 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 13:38:58 -0700 Subject: [PATCH 13/17] Spelling --- .github/actions/spelling/expect.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 8926b5b968..596fce2769 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -7,6 +7,7 @@ agg aicli AICLIC ajor +alreadyinstalled amrutha anonymized APARTMENTTHREADED @@ -20,8 +21,8 @@ argumentlist ARMNT arp arphelper -Ashwini ashpatil +Ashwini asm ASwitch Atest @@ -38,6 +39,7 @@ bght bitmask bkup blargle +blockedbypolicy blogs Bluetooth bomgar @@ -45,6 +47,7 @@ BOMs brk Buf BUILTINS +cancelledbyuser casemap casemappings cch @@ -67,6 +70,7 @@ COINIT COMGLB commandline Concat +contactsupport contosa contosainstaller contoso @@ -85,6 +89,7 @@ deigh deleteifnotneeded desktopappinstaller dirs +diskfull dnld dustojnikhummer dvinns @@ -105,6 +110,7 @@ experimentalfeatures fcb fd fedorapeople +fileinuse fintimes Fixfor flargle @@ -148,7 +154,9 @@ IMutable IName inet inor +installinprogress installshield +insufficientmemory IPackage IPersist IService @@ -201,6 +209,7 @@ middleware midl minexample minschema +missingdependency MMmmbbbb monicka MPNS @@ -223,6 +232,7 @@ mytool netlify Newtonsoft NOEXPAND +nonetwork normer NOSEPARATOR NOTAPROPERTY @@ -234,6 +244,7 @@ NX objbase ofile Packagedx +packageinuse pathparts pathpaths Patil @@ -262,6 +273,9 @@ qb qword rbegin readonly +rebootinitiated +rebootrequiredforinstall +rebootrequiredtofinish redirector regexes REGSAM From c3efcaab23fdfa431f03263a31f130b609dde613 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 14:44:46 -0700 Subject: [PATCH 14/17] Add missing files --- ...Bad-DuplicateReturnCode-ExpectedCodes.yaml | 21 +++++++++++++++++++ ...-Bad-DuplicateReturnCode-SuccessCodes.yaml | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml create mode 100644 src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml diff --git a/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml b/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml new file mode 100644 index 0000000000..20ad197fa4 --- /dev/null +++ b/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-ExpectedCodes.yaml @@ -0,0 +1,21 @@ +# Bad manifest. Expected return codes repeat the same return code +PackageIdentifier: AppInstallerCliTest.TestInstaller +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Installer +ShortDescription: AppInstaller Test Installer +Publisher: Microsoft Corporation +Moniker: AICLITestExe +License: Test +Installers: + - Architecture: x86 + InstallerUrl: https://ThisIsNotUsed + InstallerType: exe + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B + ExpectedReturnCodes: + - InstallerReturnCode: 1 + ReturnResponse: PackageInUse + - InstallerReturnCode: 1 + ReturnResponse: InstallInProgress +ManifestType: singleton +ManifestVersion: 1.1.0 diff --git a/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml b/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml new file mode 100644 index 0000000000..515300acc3 --- /dev/null +++ b/src/AppInstallerCLITests/TestData/Manifest-Bad-DuplicateReturnCode-SuccessCodes.yaml @@ -0,0 +1,21 @@ +# Bad manifest. Expected return codes repeat the same return code +PackageIdentifier: AppInstallerCliTest.TestInstaller +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Installer +ShortDescription: AppInstaller Test Installer +Publisher: Microsoft Corporation +Moniker: AICLITestExe +License: Test +Installers: + - Architecture: x86 + InstallerUrl: https://ThisIsNotUsed + InstallerType: exe + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B + InstallerSuccessCodes: + - 1 + ExpectedReturnCodes: + - InstallerReturnCode: 1 + ReturnResponse: PackageInUse +ManifestType: singleton +ManifestVersion: 1.1.0 From bf741a6036f9ee98bbf9eeccf01d708479361ab2 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 14:45:56 -0700 Subject: [PATCH 15/17] Typo --- src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 84811ce8b3..f6728b1f6d 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1104,7 +1104,7 @@ Do you agree to the terms? Another installation is already in progress. Try again later. - One or more file are being used. Exit the application then try again. + One or more files are being used. Exit the application then try again. This package has a dependency missing from your system. From a675b97be0e98e695f2a9775464a6833eb8142cd Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 14:49:03 -0700 Subject: [PATCH 16/17] Learning to count in hex :D --- src/AppInstallerCLIE2ETests/Constants.cs | 14 +++++++------- .../Public/AppInstallerErrors.h | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index e1a3a8d4e2..09cfe00a3e 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -136,7 +136,7 @@ public class ErrorCode public const int ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH = unchecked((int)0x8a150047); public const int ERROR_MISSING_RESOURCE_FILE = unchecked((int)0x8a150048); public const int ERROR_MSI_INSTALL_FAILED = unchecked((int)0x8a150049); - public const int ERROR_INVALID_MSIEXEC_ARGUMENT = unchecked((int)0x8a150050); + public const int ERROR_INVALID_MSIEXEC_ARGUMENT = unchecked((int)0x8a15004a); public const int ERROR_INSTALL_PACKAGE_IN_USE = unchecked((int)0x8a150101); public const int ERROR_INSTALL_INSTALL_IN_PROGRESS = unchecked((int)0x8a150102); @@ -147,12 +147,12 @@ public class ErrorCode public const int ERROR_INSTALL_NO_NETWORK = unchecked((int)0x8a150107); public const int ERROR_INSTALL_CONTACT_SUPPORT = unchecked((int)0x8a150108); public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH = unchecked((int)0x8a150109); - public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL = unchecked((int)0x8a150110); - public const int ERROR_INSTALL_REBOOT_INITIATED = unchecked((int)0x8a150111); - public const int ERROR_INSTALL_CANCELLED_BY_USER = unchecked((int)0x8a150112); - public const int ERROR_INSTALL_ALREADY_INSTALLED = unchecked((int)0x8a150113); - public const int ERROR_INSTALL_DOWNGRADE = unchecked((int)0x8a150114); - public const int ERROR_INSTALL_BLOCKED_BY_POLICY = unchecked((int)0x8a150115); + public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL = unchecked((int)0x8a15010a); + public const int ERROR_INSTALL_REBOOT_INITIATED = unchecked((int)0x8a15010b); + public const int ERROR_INSTALL_CANCELLED_BY_USER = unchecked((int)0x8a15010c); + public const int ERROR_INSTALL_ALREADY_INSTALLED = unchecked((int)0x8a15010d); + public const int ERROR_INSTALL_DOWNGRADE = unchecked((int)0x8a15010e); + public const int ERROR_INSTALL_BLOCKED_BY_POLICY = unchecked((int)0x8a15010f); } } } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index fa92caf951..1e140f164f 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -86,7 +86,7 @@ #define APPINSTALLER_CLI_ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH ((HRESULT)0x8a150047) #define APPINSTALLER_CLI_ERROR_MISSING_RESOURCE_FILE ((HRESULT)0x8a150048) #define APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED ((HRESULT)0x8a150049) -#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a150050) +#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a15004a) #define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150101) #define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150102) @@ -97,12 +97,12 @@ #define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a150107) #define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a150108) #define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH ((HRESULT)0x8a150109) -#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL ((HRESULT)0x8a150110) -#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED ((HRESULT)0x8a150111) -#define APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER ((HRESULT)0x8a150112) -#define APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED ((HRESULT)0x8a150113) -#define APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE ((HRESULT)0x8a150114) -#define APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY ((HRESULT)0x8a150115) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL ((HRESULT)0x8a15010a) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED ((HRESULT)0x8a15010b) +#define APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER ((HRESULT)0x8a15010c) +#define APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED ((HRESULT)0x8a15010d) +#define APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE ((HRESULT)0x8a15010e) +#define APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY ((HRESULT)0x8a15010f) namespace AppInstaller From b2ca8159e6ad5706824914e9df4c0a69535cd781 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 14 Sep 2021 15:01:28 -0700 Subject: [PATCH 17/17] Uppercase error code constants --- src/AppInstallerCLIE2ETests/Constants.cs | 78 +++++++++---------- .../Public/AppInstallerErrors.h | 70 ++++++++--------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index 09cfe00a3e..0aeb74cc93 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -58,8 +58,8 @@ public class ErrorCode public const int ERROR_FILE_NOT_FOUND = unchecked((int)0x80070002); public const int ERROR_PATH_NOT_FOUND = unchecked((int)0x80070003); public const int ERROR_NO_RANGES_PROCESSED = unchecked((int)0x80070138); - public const int OPC_E_ZIP_MISSING_END_OF_CENTRAL_DIRECTORY = unchecked((int)0x8051100f); - public const int ERROR_OLD_WIN_VERSION = unchecked((int)0x8007047e); + public const int OPC_E_ZIP_MISSING_END_OF_CENTRAL_DIRECTORY = unchecked((int)0x8051100F); + public const int ERROR_OLD_WIN_VERSION = unchecked((int)0x8007047E); public const int HTTP_E_STATUS_NOT_FOUND = unchecked((int)0x80190194); // AICLI custom HRESULTs @@ -109,50 +109,50 @@ public class ErrorCode public const int ERROR_UPDATE_ALL_HAS_FAILURE = unchecked((int)0x8A15002C); public const int ERROR_INSTALLER_SECURITY_CHECK_FAILED = unchecked((int)0x8A15002D); public const int ERROR_DOWNLOAD_SIZE_MISMATCH = unchecked((int)0x8A15002E); - public const int ERROR_NO_UNINSTALL_INFO_FOUND = unchecked((int)0x8a15002F); - public const int ERROR_EXEC_UNINSTALL_COMMAND_FAILED = unchecked((int)0x8a150030); + public const int ERROR_NO_UNINSTALL_INFO_FOUND = unchecked((int)0x8A15002F); + public const int ERROR_EXEC_UNINSTALL_COMMAND_FAILED = unchecked((int)0x8A150030); public const int ERROR_ICU_BREAK_ITERATOR_ERROR = unchecked((int)0x8A150031); public const int ERROR_ICU_CASEMAP_ERROR = unchecked((int)0x8A150032); public const int ERROR_ICU_REGEX_ERROR = unchecked((int)0x8A150033); - public const int ERROR_IMPORT_INSTALL_FAILED = unchecked((int)0x8a150034); - public const int ERROR_NOT_ALL_PACKAGES_FOUND = unchecked((int)0x8a150035); - public const int ERROR_JSON_INVALID_FILE = unchecked((int)0x8a150036); + public const int ERROR_IMPORT_INSTALL_FAILED = unchecked((int)0x8A150034); + public const int ERROR_NOT_ALL_PACKAGES_FOUND = unchecked((int)0x8A150035); + public const int ERROR_JSON_INVALID_FILE = unchecked((int)0x8A150036); public const int ERROR_SOURCE_NOT_REMOTE = unchecked((int)0x8A150037); public const int ERROR_UNSUPPORTED_RESTSOURCE = unchecked((int)0x8A150038); public const int ERROR_RESTSOURCE_INVALID_DATA = unchecked((int)0x8A150039); - public const int ERROR_BLOCKED_BY_POLICY = unchecked((int)0x8a15003A); - public const int ERROR_RESTSOURCE_INTERNAL_ERROR = unchecked((int)0x8a15003B); - public const int ERROR_RESTSOURCE_INVALID_URL = unchecked((int)0x8a15003C); - public const int ERROR_RESTSOURCE_UNSUPPORTED_MIME_TYPE = unchecked((int)0x8a15003D); - public const int ERROR_RESTSOURCE_INVALID_VERSION = unchecked((int)0x8a15003E); - public const int ERROR_SOURCE_DATA_INTEGRITY_FAILURE = unchecked((int)0x8a15003F); - public const int ERROR_STREAM_READ_FAILURE = unchecked((int)0x8a150040); - public const int ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED = unchecked((int)0x8a150041); - public const int ERROR_PROMPT_INPUT_ERROR = unchecked((int)0x8a150042); - public const int ERROR_UNSUPPORTED_SOURCE_REQUEST = unchecked((int)0x8a150043); - public const int ERROR_RESTSOURCE_ENDPOINT_NOT_FOUND = unchecked((int)0x8a150044); - public const int ERROR_SOURCE_OPEN_FAILED = unchecked((int)0x8a150045); - public const int ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED = unchecked((int)0x8a150046); - public const int ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH = unchecked((int)0x8a150047); - public const int ERROR_MISSING_RESOURCE_FILE = unchecked((int)0x8a150048); - public const int ERROR_MSI_INSTALL_FAILED = unchecked((int)0x8a150049); - public const int ERROR_INVALID_MSIEXEC_ARGUMENT = unchecked((int)0x8a15004a); + public const int ERROR_BLOCKED_BY_POLICY = unchecked((int)0x8A15003A); + public const int ERROR_RESTSOURCE_INTERNAL_ERROR = unchecked((int)0x8A15003B); + public const int ERROR_RESTSOURCE_INVALID_URL = unchecked((int)0x8A15003C); + public const int ERROR_RESTSOURCE_UNSUPPORTED_MIME_TYPE = unchecked((int)0x8A15003D); + public const int ERROR_RESTSOURCE_INVALID_VERSION = unchecked((int)0x8A15003E); + public const int ERROR_SOURCE_DATA_INTEGRITY_FAILURE = unchecked((int)0x8A15003F); + public const int ERROR_STREAM_READ_FAILURE = unchecked((int)0x8A150040); + public const int ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED = unchecked((int)0x8A150041); + public const int ERROR_PROMPT_INPUT_ERROR = unchecked((int)0x8A150042); + public const int ERROR_UNSUPPORTED_SOURCE_REQUEST = unchecked((int)0x8A150043); + public const int ERROR_RESTSOURCE_ENDPOINT_NOT_FOUND = unchecked((int)0x8A150044); + public const int ERROR_SOURCE_OPEN_FAILED = unchecked((int)0x8A150045); + public const int ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED = unchecked((int)0x8A150046); + public const int ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH = unchecked((int)0x8A150047); + public const int ERROR_MISSING_RESOURCE_FILE = unchecked((int)0x8A150048); + public const int ERROR_MSI_INSTALL_FAILED = unchecked((int)0x8A150049); + public const int ERROR_INVALID_MSIEXEC_ARGUMENT = unchecked((int)0x8A15004A); - public const int ERROR_INSTALL_PACKAGE_IN_USE = unchecked((int)0x8a150101); - public const int ERROR_INSTALL_INSTALL_IN_PROGRESS = unchecked((int)0x8a150102); - public const int ERROR_INSTALL_FILE_IN_USE = unchecked((int)0x8a150103); - public const int ERROR_INSTALL_MISSING_DEPENDENCY = unchecked((int)0x8a150104); - public const int ERROR_INSTALL_DISK_FULL = unchecked((int)0x8a150105); - public const int ERROR_INSTALL_INSUFFICIENT_MEMORY = unchecked((int)0x8a150106); - public const int ERROR_INSTALL_NO_NETWORK = unchecked((int)0x8a150107); - public const int ERROR_INSTALL_CONTACT_SUPPORT = unchecked((int)0x8a150108); - public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH = unchecked((int)0x8a150109); - public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL = unchecked((int)0x8a15010a); - public const int ERROR_INSTALL_REBOOT_INITIATED = unchecked((int)0x8a15010b); - public const int ERROR_INSTALL_CANCELLED_BY_USER = unchecked((int)0x8a15010c); - public const int ERROR_INSTALL_ALREADY_INSTALLED = unchecked((int)0x8a15010d); - public const int ERROR_INSTALL_DOWNGRADE = unchecked((int)0x8a15010e); - public const int ERROR_INSTALL_BLOCKED_BY_POLICY = unchecked((int)0x8a15010f); + public const int ERROR_INSTALL_PACKAGE_IN_USE = unchecked((int)0x8A150101); + public const int ERROR_INSTALL_INSTALL_IN_PROGRESS = unchecked((int)0x8A150102); + public const int ERROR_INSTALL_FILE_IN_USE = unchecked((int)0x8A150103); + public const int ERROR_INSTALL_MISSING_DEPENDENCY = unchecked((int)0x8A150104); + public const int ERROR_INSTALL_DISK_FULL = unchecked((int)0x8A150105); + public const int ERROR_INSTALL_INSUFFICIENT_MEMORY = unchecked((int)0x8A150106); + public const int ERROR_INSTALL_NO_NETWORK = unchecked((int)0x8A150107); + public const int ERROR_INSTALL_CONTACT_SUPPORT = unchecked((int)0x8A150108); + public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH = unchecked((int)0x8A150109); + public const int ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL = unchecked((int)0x8A15010A); + public const int ERROR_INSTALL_REBOOT_INITIATED = unchecked((int)0x8A15010B); + public const int ERROR_INSTALL_CANCELLED_BY_USER = unchecked((int)0x8A15010C); + public const int ERROR_INSTALL_ALREADY_INSTALLED = unchecked((int)0x8A15010D); + public const int ERROR_INSTALL_DOWNGRADE = unchecked((int)0x8A15010E); + public const int ERROR_INSTALL_BLOCKED_BY_POLICY = unchecked((int)0x8A15010F); } } } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h index 1e140f164f..72cb419070 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -64,45 +64,45 @@ #define APPINSTALLER_CLI_ERROR_ICU_BREAK_ITERATOR_ERROR ((HRESULT)0x8A150031) #define APPINSTALLER_CLI_ERROR_ICU_CASEMAP_ERROR ((HRESULT)0x8A150032) #define APPINSTALLER_CLI_ERROR_ICU_REGEX_ERROR ((HRESULT)0x8A150033) -#define APPINSTALLER_CLI_ERROR_IMPORT_INSTALL_FAILED ((HRESULT)0x8a150034) -#define APPINSTALLER_CLI_ERROR_NOT_ALL_PACKAGES_FOUND ((HRESULT)0x8a150035) -#define APPINSTALLER_CLI_ERROR_JSON_INVALID_FILE ((HRESULT)0x8a150036) +#define APPINSTALLER_CLI_ERROR_IMPORT_INSTALL_FAILED ((HRESULT)0x8A150034) +#define APPINSTALLER_CLI_ERROR_NOT_ALL_PACKAGES_FOUND ((HRESULT)0x8A150035) +#define APPINSTALLER_CLI_ERROR_JSON_INVALID_FILE ((HRESULT)0x8A150036) #define APPINSTALLER_CLI_ERROR_SOURCE_NOT_REMOTE ((HRESULT)0x8A150037) #define APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE ((HRESULT)0x8A150038) #define APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_DATA ((HRESULT)0x8A150039) -#define APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY ((HRESULT)0x8a15003A) -#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INTERNAL_ERROR ((HRESULT)0x8a15003B) -#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_URL ((HRESULT)0x8a15003C) -#define APPINSTALLER_CLI_ERROR_RESTSOURCE_UNSUPPORTED_MIME_TYPE ((HRESULT)0x8a15003D) -#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION ((HRESULT)0x8a15003E) -#define APPINSTALLER_CLI_ERROR_SOURCE_DATA_INTEGRITY_FAILURE ((HRESULT)0x8a15003F) -#define APPINSTALLER_CLI_ERROR_STREAM_READ_FAILURE ((HRESULT)0x8a150040) -#define APPINSTALLER_CLI_ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8a150041) -#define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8a150042) -#define APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST ((HRESULT)0x8a150043) -#define APPINSTALLER_CLI_ERROR_RESTSOURCE_ENDPOINT_NOT_FOUND ((HRESULT)0x8a150044) -#define APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED ((HRESULT)0x8a150045) -#define APPINSTALLER_CLI_ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8a150046) -#define APPINSTALLER_CLI_ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH ((HRESULT)0x8a150047) -#define APPINSTALLER_CLI_ERROR_MISSING_RESOURCE_FILE ((HRESULT)0x8a150048) -#define APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED ((HRESULT)0x8a150049) -#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8a15004a) +#define APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY ((HRESULT)0x8A15003A) +#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INTERNAL_ERROR ((HRESULT)0x8A15003B) +#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_URL ((HRESULT)0x8A15003C) +#define APPINSTALLER_CLI_ERROR_RESTSOURCE_UNSUPPORTED_MIME_TYPE ((HRESULT)0x8A15003D) +#define APPINSTALLER_CLI_ERROR_RESTSOURCE_INVALID_VERSION ((HRESULT)0x8A15003E) +#define APPINSTALLER_CLI_ERROR_SOURCE_DATA_INTEGRITY_FAILURE ((HRESULT)0x8A15003F) +#define APPINSTALLER_CLI_ERROR_STREAM_READ_FAILURE ((HRESULT)0x8A150040) +#define APPINSTALLER_CLI_ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8A150041) +#define APPINSTALLER_CLI_ERROR_PROMPT_INPUT_ERROR ((HRESULT)0x8A150042) +#define APPINSTALLER_CLI_ERROR_UNSUPPORTED_SOURCE_REQUEST ((HRESULT)0x8A150043) +#define APPINSTALLER_CLI_ERROR_RESTSOURCE_ENDPOINT_NOT_FOUND ((HRESULT)0x8A150044) +#define APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED ((HRESULT)0x8A150045) +#define APPINSTALLER_CLI_ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED ((HRESULT)0x8A150046) +#define APPINSTALLER_CLI_ERROR_CUSTOMHEADER_EXCEEDS_MAXLENGTH ((HRESULT)0x8A150047) +#define APPINSTALLER_CLI_ERROR_MISSING_RESOURCE_FILE ((HRESULT)0x8A150048) +#define APPINSTALLER_CLI_ERROR_MSI_INSTALL_FAILED ((HRESULT)0x8A150049) +#define APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT ((HRESULT)0x8A15004A) -#define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8a150101) -#define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8a150102) -#define APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE ((HRESULT)0x8a150103) -#define APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY ((HRESULT)0x8a150104) -#define APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL ((HRESULT)0x8a150105) -#define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8a150106) -#define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8a150107) -#define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8a150108) -#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH ((HRESULT)0x8a150109) -#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL ((HRESULT)0x8a15010a) -#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED ((HRESULT)0x8a15010b) -#define APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER ((HRESULT)0x8a15010c) -#define APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED ((HRESULT)0x8a15010d) -#define APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE ((HRESULT)0x8a15010e) -#define APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY ((HRESULT)0x8a15010f) +#define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE ((HRESULT)0x8A150101) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSTALL_IN_PROGRESS ((HRESULT)0x8A150102) +#define APPINSTALLER_CLI_ERROR_INSTALL_FILE_IN_USE ((HRESULT)0x8A150103) +#define APPINSTALLER_CLI_ERROR_INSTALL_MISSING_DEPENDENCY ((HRESULT)0x8A150104) +#define APPINSTALLER_CLI_ERROR_INSTALL_DISK_FULL ((HRESULT)0x8A150105) +#define APPINSTALLER_CLI_ERROR_INSTALL_INSUFFICIENT_MEMORY ((HRESULT)0x8A150106) +#define APPINSTALLER_CLI_ERROR_INSTALL_NO_NETWORK ((HRESULT)0x8A150107) +#define APPINSTALLER_CLI_ERROR_INSTALL_CONTACT_SUPPORT ((HRESULT)0x8A150108) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_FINISH ((HRESULT)0x8A150109) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_REQUIRED_TO_INSTALL ((HRESULT)0x8A15010A) +#define APPINSTALLER_CLI_ERROR_INSTALL_REBOOT_INITIATED ((HRESULT)0x8A15010B) +#define APPINSTALLER_CLI_ERROR_INSTALL_CANCELLED_BY_USER ((HRESULT)0x8A15010C) +#define APPINSTALLER_CLI_ERROR_INSTALL_ALREADY_INSTALLED ((HRESULT)0x8A15010D) +#define APPINSTALLER_CLI_ERROR_INSTALL_DOWNGRADE ((HRESULT)0x8A15010E) +#define APPINSTALLER_CLI_ERROR_INSTALL_BLOCKED_BY_POLICY ((HRESULT)0x8A15010F) namespace AppInstaller