commit 76d92152cb131572a1d5dbbec98e04f33bd2c985
parent 1ea38f17a42e55a5bdef1badebe5fcb770f6689d
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Mon, 6 Apr 2020 23:45:37 -0700
Show wil exceptions to the user in a cleaner fashion (#80)
Diffstat:
6 files changed, 130 insertions(+), 8 deletions(-)
diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp
@@ -109,12 +109,12 @@ namespace AppInstaller::CLI
Logging::Telemetry().LogException(command->FullName(), "wil::ResultException", re.what());
context.Reporter.Error() <<
"An unexpected error occurred while executing the command: " << std::endl <<
- re.what() << std::endl;
+ GetUserPresentableMessage(re) << std::endl;
return re.GetErrorCode();
}
catch (const winrt::hresult_error& hre)
{
- std::string message = Utility::ConvertToUTF8(hre.message());
+ std::string message = GetUserPresentableMessage(hre);
Logging::Telemetry().LogException(command->FullName(), "winrt::hresult_error", message);
context.Reporter.Error() <<
"An unexpected error occurred while executing the command: " << std::endl <<
@@ -126,7 +126,7 @@ namespace AppInstaller::CLI
Logging::Telemetry().LogException(command->FullName(), "std::exception", e.what());
context.Reporter.Error() <<
"An unexpected error occurred while executing the command: " << std::endl <<
- e.what() << std::endl;
+ GetUserPresentableMessage(e) << std::endl;
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
}
catch (...)
diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
@@ -208,7 +208,7 @@ namespace AppInstaller::CLI::Workflow
const auto& manifest = context.Get<Execution::Data::Manifest>();
Logging::Telemetry().LogInstallerFailure(manifest.Id, manifest.Version, manifest.Channel, "MSIX", re.GetErrorCode());
- context.Reporter.Error() << Utility::ConvertToUTF8(re.GetFailureInfo().pszMessage) << std::endl;
+ context.Reporter.Error() << GetUserPresentableMessage(re) << std::endl;
AICLI_TERMINATE_CONTEXT(re.GetErrorCode());
}
diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj
@@ -202,6 +202,7 @@
<ClCompile Include="DateTime.cpp" />
<ClCompile Include="Deployment.cpp" />
<ClCompile Include="Downloader.cpp" />
+ <ClCompile Include="Errors.cpp" />
<ClCompile Include="FileLogger.cpp" />
<ClCompile Include="HttpStream\HttpClientWrapper.cpp" />
<ClCompile Include="HttpStream\HttpLocalCache.cpp" />
diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters
@@ -149,6 +149,9 @@
<ClCompile Include="Versions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="Errors.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "pch.h"
+#include "Public/AppInstallerErrors.h"
+#include "Public/AppInstallerStrings.h"
+
+
+namespace AppInstaller
+{
+ namespace
+ {
+ const char* const GetMessageForAppInstallerHR(HRESULT hr)
+ {
+ switch (hr)
+ {
+ case APPINSTALLER_CLI_ERROR_INTERNAL_ERROR:
+ return "Internal Error";
+ case APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS:
+ return "Invalid command line arguments";
+ case APPINSTALLER_CLI_ERROR_COMMAND_FAILED:
+ return "Executing command failed";
+ case APPINSTALLER_CLI_ERROR_MANIFEST_FAILED:
+ return "Opening manifest failed";
+ case APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED:
+ return "Running ShellExecute failed";
+ case APPINSTALLER_CLI_ERROR_DOWNLOAD_FAILED:
+ return "Downloading installer failed";
+ case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX:
+ return "Cannot write to index; it is a higher schema version";
+ case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED:
+ return "The index is corrupt";
+ case APPINSTALLER_CLI_ERROR_SOURCES_INVALID:
+ return "The configured source information is corrupt";
+ case APPINSTALLER_CLI_ERROR_SOURCE_NAME_ALREADY_EXISTS:
+ return "The source name is already configured";
+ case APPINSTALLER_CLI_ERROR_INVALID_SOURCE_TYPE:
+ return "The source type is invalid";
+ case APPINSTALLER_CLI_ERROR_PACKAGE_IS_BUNDLE:
+ return "The MSIX file is a bundle, not a package";
+ case APPINSTALLER_CLI_ERROR_SOURCE_DATA_MISSING:
+ return "Data required by the source is missing";
+ case APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER:
+ return "None of the installers are applicable for the current system";
+ case APPINSTALLER_CLI_ERROR_INSTALLER_HASH_MISMATCH:
+ return "The installer file's hash does not match the manifest";
+ case APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST:
+ return "The source name does not exist";
+ case APPINSTALLER_CLI_ERROR_SOURCE_ARG_ALREADY_EXISTS:
+ return "The source location is already configured under another name";
+ case APPINSTALLER_CLI_ERROR_NO_APPLICATIONS_FOUND:
+ return "No applications found";
+ case APPINSTALLER_CLI_ERROR_NO_SOURCES_DEFINED:
+ return "No sources are configured";
+ case APPINSTALLER_CLI_ERROR_MULTIPLE_APPLICATIONS_FOUND:
+ return "Multiple applications found matching the criteria";
+ case APPINSTALLER_CLI_ERROR_NO_MANIFEST_FOUND:
+ return "No manifest found matching the criteria";
+ default:
+ return "Uknown Error Code";
+ }
+ }
+
+ void GetUserPresentableMessageForHR(std::ostringstream& strstr, HRESULT hr)
+ {
+ strstr << "0x" << std::hex << std::setw(8) << std::setfill('0') << hr << " : ";
+
+ if (HRESULT_FACILITY(hr) == APPINSTALLER_CLI_ERROR_FACILITY)
+ {
+ strstr << GetMessageForAppInstallerHR(hr);
+ }
+ else
+ {
+ strstr << std::system_category().message(hr);
+ }
+ }
+ }
+
+ std::string GetUserPresentableMessage(const wil::ResultException& re)
+ {
+ const auto& info = re.GetFailureInfo();
+
+ std::ostringstream strstr;
+
+ // We assume that if the exception has a message, that message is relevant to show to the user.
+ if (info.pszMessage)
+ {
+ strstr << Utility::ConvertToUTF8(info.pszMessage) << std::endl;
+ }
+
+ GetUserPresentableMessageForHR(strstr, re.GetErrorCode());
+
+ return strstr.str();
+ }
+
+ std::string GetUserPresentableMessage(const winrt::hresult_error& hre)
+ {
+ return Utility::ConvertToUTF8(hre.message());
+ }
+
+ std::string GetUserPresentableMessage(const std::exception& e)
+ {
+ return e.what();
+ }
+}
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h
@@ -1,17 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-
#pragma once
+#include <wil/result_macros.h>
+#include <winrt/base.h>
+
+#include <exception>
+#include <string>
-#define APPINSTALLER_CLI_ERROR_FACILITY 0x8A150000
+
+#define APPINSTALLER_CLI_ERROR_FACILITY 0xA15
#define APPINSTALLER_CLI_ERROR_INTERNAL_ERROR ((HRESULT)0x8A150001)
#define APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS ((HRESULT)0x8A150002)
#define APPINSTALLER_CLI_ERROR_COMMAND_FAILED ((HRESULT)0x8A150003)
#define APPINSTALLER_CLI_ERROR_MANIFEST_FAILED ((HRESULT)0x8A150004)
-#define APPINSTALLER_CLI_ERROR_WORKFLOW_FAILED ((HRESULT)0x8A150005)
+//#define APPINSTALLER_CLI_ERROR_WORKFLOW_FAILED ((HRESULT)0x8A150005) // Unused, can be repurposed
#define APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED ((HRESULT)0x8A150006)
-#define APPINSTALLER_CLI_ERROR_RUNTIME_ERROR ((HRESULT)0x8A150007)
+//#define APPINSTALLER_CLI_ERROR_RUNTIME_ERROR ((HRESULT)0x8A150007) // Unused, can be repurposed
#define APPINSTALLER_CLI_ERROR_DOWNLOAD_FAILED ((HRESULT)0x8A150008)
#define APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX ((HRESULT)0x8A150009)
#define APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED ((HRESULT)0x8A15000A)
@@ -28,3 +33,11 @@
#define APPINSTALLER_CLI_ERROR_NO_SOURCES_DEFINED ((HRESULT)0x8A150015)
#define APPINSTALLER_CLI_ERROR_MULTIPLE_APPLICATIONS_FOUND ((HRESULT)0x8A150016)
#define APPINSTALLER_CLI_ERROR_NO_MANIFEST_FOUND ((HRESULT)0x8A150017)
+
+namespace AppInstaller
+{
+ // Gets error messages that are presentable to the user.
+ std::string GetUserPresentableMessage(const wil::ResultException& re);
+ std::string GetUserPresentableMessage(const winrt::hresult_error& hre);
+ std::string GetUserPresentableMessage(const std::exception& e);
+}