From 658981adf73682cd02f06a12357ed29e029c4692 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Fri, 9 Dec 2022 14:32:34 +0100 Subject: [PATCH] ModernSettings: Improve indirect string loading Defender settings on Win11 use indirect strings in form: `@{Microsoft.SecHealthUI_8wekyb3d8bbwe?ms-resource://Microsoft.SecHealthUI/Resources/DisplayName}` `SHLoadIndirectString` is unable to load such indirect string, because it expects full package name (instead of package family name). In such case we will convert package family name to full name and try again. --- .../StartMenuHelper/ModernSettings.cpp | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/Src/StartMenu/StartMenuHelper/ModernSettings.cpp b/Src/StartMenu/StartMenuHelper/ModernSettings.cpp index ed0aa8d..257c772 100644 --- a/Src/StartMenu/StartMenuHelper/ModernSettings.cpp +++ b/Src/StartMenu/StartMenuHelper/ModernSettings.cpp @@ -7,6 +7,7 @@ #include "stdafx.h" #include "ModernSettings.h" #include "ResourceHelper.h" +#include #include #include #include @@ -126,12 +127,80 @@ static void ProcessAttributes(const void* buffer, size_t size, std::function((void*)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetPackagesByPackageFamily")); + if (pGetPackagesByPackageFamily) + { + UINT32 count = 0; + UINT32 bufferLength = 0; + + if (pGetPackagesByPackageFamily(packageFamily, &count, nullptr, &bufferLength, nullptr) == ERROR_INSUFFICIENT_BUFFER && count > 0) + { + std::vector names(count); + std::vector buffer(bufferLength); + + if (pGetPackagesByPackageFamily(packageFamily, &count, names.data(), &bufferLength, buffer.data()) == ERROR_SUCCESS && count > 0) + return names[0]; + } + } + + return {}; +} + +static std::pair ParseResourceString(const wchar_t* resourceString) +{ + std::wstring_view str = resourceString; + + if (str[0] == '@' && str[1] == '{') + { + str.remove_prefix(2); + if (str.back() == '}') + str.remove_suffix(1); + + auto pos = str.find('?'); + if (pos != str.npos) + return { str.substr(0, pos), str.substr(pos + 1) }; + } + + return {}; +} + +static std::wstring FormatResourceString(const std::wstring_view& package, const std::wstring_view& resource) +{ + std::wstring retval(L"@{"); + + retval += package; + retval += L"?"; + retval += resource; + retval += L"}"; + + return retval; +} + + static std::wstring TranslateIndirectString(const WCHAR* string) { std::wstring retval; retval.resize(1024); - if (SUCCEEDED(::SHLoadIndirectString(string, retval.data(), (UINT)retval.size(), nullptr))) + auto hr = ::SHLoadIndirectString(string, retval.data(), (UINT)retval.size(), nullptr); + + if (hr == E_INVALIDARG) + { + auto [package, resource] = ParseResourceString(string); + if (!package.empty() && !resource.empty()) + { + auto fullPackage = GetPackageFullName(std::wstring(package).c_str()); + if (!fullPackage.empty()) + { + auto fullStr = FormatResourceString(fullPackage, resource); + hr = ::SHLoadIndirectString(fullStr.c_str(), retval.data(), (UINT)retval.size(), nullptr); + } + } + } + + if (SUCCEEDED(hr)) { retval.resize(wcslen(retval.data())); return retval;