Skip to content

Commit

Permalink
External HR error message support (microsoft#4746)
Browse files Browse the repository at this point in the history
Fixes microsoft#3982 

## Change
Add support for externally defined HRESULTs to have a custom message.
Use this to provide a message for the errors associated with a Microsoft
Store package being unavailable for the current system.
  • Loading branch information
JohnMcPMS committed Aug 21, 2024
1 parent 83b2db4 commit d010e24
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw
Original file line number Diff line number Diff line change
Expand Up @@ -3106,4 +3106,7 @@ Please specify one of them using the --source option to proceed.</value>
<data name="ConfigureListUnit" xml:space="preserve">
<value>Unit</value>
</data>
<data name="StoreInstall_PackageNotAvailableForCurrentSystem" xml:space="preserve">
<value>The package is not compatible with the current Windows version or platform.</value>
</data>
</root>
63 changes: 46 additions & 17 deletions src/AppInstallerSharedLib/Errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ namespace AppInstaller
namespace
{
// A simple struct to hold the data
struct WinGetHResultData
struct HResultData
{
HRESULT Value;
std::string_view Symbol;
std::string_view Description;

bool operator<(const WinGetHResultData& other) const
bool operator<(const HResultData& other) const
{
return Value < other.Value;
}
Expand All @@ -31,7 +31,7 @@ namespace AppInstaller
Errors::HResultInformation(value, symbol), m_unlocalizedDescription(unlocalizedDescription)
{}

constexpr WinGetHResultInformation(const WinGetHResultData& data) :
constexpr WinGetHResultInformation(const HResultData& data) :
Errors::HResultInformation(data.Value, data.Symbol), m_unlocalizedDescription(data.Description)
{}

Expand All @@ -54,7 +54,7 @@ namespace AppInstaller
Errors::HResultInformation(value, symbol), m_unlocalizedDescription(unlocalizedDescription)
{}

constexpr WinGetHResultInformationUnlocalized(const WinGetHResultData& data) :
constexpr WinGetHResultInformationUnlocalized(const HResultData& data) :
Errors::HResultInformation(data.Value, data.Symbol), m_unlocalizedDescription(data.Description)
{}

Expand Down Expand Up @@ -83,9 +83,9 @@ namespace AppInstaller
}
};

#define WINGET_HRESULT_INFO(_name_,_description_) WinGetHResultData{ _name_, #_name_, _description_ }
#define WINGET_HRESULT_INFO(_name_,_description_) HResultData{ _name_, #_name_, _description_ }

constexpr const WinGetHResultData s_wingetHResultData[] =
constexpr const HResultData s_wingetHResultData[] =
{
// Changes to any of these errors require the corresponding resource string in winget.resw to be updated.
WINGET_HRESULT_INFO(APPINSTALLER_CLI_ERROR_INTERNAL_ERROR, "Internal Error"),
Expand Down Expand Up @@ -289,21 +289,41 @@ namespace AppInstaller
WINGET_HRESULT_INFO(WINGET_INSTALLED_STATUS_FILE_FOUND_WITHOUT_HASH_CHECK, "The file was found but the hash was not checked."),
};

const WinGetHResultData* FindWinGetHResultData(HRESULT value)
// Map externally defined HRESULTs to error messages we want to use here
constexpr const HResultData s_externalHResultData[] =
{
auto itr = std::lower_bound(std::cbegin(s_wingetHResultData), std::cend(s_wingetHResultData), WinGetHResultData{ value });
// Changes to any of these errors require the corresponding resource string in winget.resw to be updated.
HResultData{ static_cast<HRESULT>(0x803FB103), "StoreInstall_PackageNotAvailableForCurrentSystem", "The package is not compatible with the current Windows version or platform." },
HResultData{ static_cast<HRESULT>(0x803FB104), "StoreInstall_PackageNotAvailableForCurrentSystem", "The package is not compatible with the current Windows version or platform." },
HResultData{ static_cast<HRESULT>(0x803FB106), "StoreInstall_PackageNotAvailableForCurrentSystem", "The package is not compatible with the current Windows version or platform." },
};

if (itr != std::cend(s_wingetHResultData) && itr->Value == value)
template <size_t ArraySize>
const HResultData* FindHResultData(HRESULT value, const HResultData (&dataArray)[ArraySize])
{
auto itr = std::lower_bound(std::cbegin(dataArray), std::cend(dataArray), HResultData{ value });

if (itr != std::cend(dataArray) && itr->Value == value)
{
return itr;
}

return nullptr;
}

const HResultData* FindWinGetHResultData(HRESULT value)
{
return FindHResultData(value, s_wingetHResultData);
}

const HResultData* FindExternalHResultData(HRESULT value)
{
return FindHResultData(value, s_externalHResultData);
}

Utility::LocIndString GetMessageForAppInstallerHR(HRESULT hr)
{
const WinGetHResultData* data = FindWinGetHResultData(hr);
const HResultData* data = FindWinGetHResultData(hr);
return data ?
WinGetHResultInformation(*data).GetDescription() :
UnknownHResultInformation(hr).GetDescription();
Expand All @@ -319,7 +339,16 @@ namespace AppInstaller
}
else
{
strstr << std::system_category().message(hr);
const HResultData* data = FindExternalHResultData(hr);

if (data)
{
strstr << WinGetHResultInformation(*data).GetDescription();
}
else
{
strstr << std::system_category().message(hr);
}
}
}
}
Expand Down Expand Up @@ -402,7 +431,7 @@ namespace AppInstaller
{
if (HRESULT_FACILITY(value) == APPINSTALLER_CLI_ERROR_FACILITY)
{
const WinGetHResultData* data = FindWinGetHResultData(value);
const HResultData* data = FindWinGetHResultData(value);

if (data)
{
Expand All @@ -425,7 +454,7 @@ namespace AppInstaller

auto addToResultIf = [&](auto predicate)
{
for (const WinGetHResultData& data : s_wingetHResultData)
for (const HResultData& data : s_wingetHResultData)
{
if (predicate(data) &&
std::none_of(result.begin(), result.end(), [&](const std::unique_ptr<HResultInformation>& info) { return info->Value() == data.Value; }))
Expand All @@ -435,9 +464,9 @@ namespace AppInstaller
}
};

addToResultIf([&](const WinGetHResultData& data) { return Utility::CaseInsensitiveEquals(data.Symbol, value); });
addToResultIf([&](const WinGetHResultData& data) { return Utility::CaseInsensitiveContainsSubstring(data.Symbol, value); });
addToResultIf([&](const WinGetHResultData& data) { return Utility::CaseInsensitiveContainsSubstring(data.Description, value); });
addToResultIf([&](const HResultData& data) { return Utility::CaseInsensitiveEquals(data.Symbol, value); });
addToResultIf([&](const HResultData& data) { return Utility::CaseInsensitiveContainsSubstring(data.Symbol, value); });
addToResultIf([&](const HResultData& data) { return Utility::CaseInsensitiveContainsSubstring(data.Description, value); });

return result;
}
Expand All @@ -447,7 +476,7 @@ namespace AppInstaller
std::vector<std::unique_ptr<HResultInformation>> result;
result.reserve(ARRAYSIZE(s_wingetHResultData));

for (const WinGetHResultData& data : s_wingetHResultData)
for (const HResultData& data : s_wingetHResultData)
{
result.emplace_back(std::make_unique<WinGetHResultInformationUnlocalized>(data));
}
Expand Down

0 comments on commit d010e24

Please sign in to comment.