Skip to content

Commit 658981a

Browse files
committed
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.
1 parent b6f5402 commit 658981a

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

Src/StartMenu/StartMenuHelper/ModernSettings.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "stdafx.h"
88
#include "ModernSettings.h"
99
#include "ResourceHelper.h"
10+
#include <appmodel.h>
1011
#include <Shlobj.h>
1112
#include <Shlwapi.h>
1213
#include <functional>
@@ -126,12 +127,80 @@ static void ProcessAttributes(const void* buffer, size_t size, std::function<voi
126127

127128
///
128129

130+
static std::wstring GetPackageFullName(const wchar_t* packageFamily)
131+
{
132+
static auto pGetPackagesByPackageFamily = static_cast<decltype(&GetPackagesByPackageFamily)>((void*)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetPackagesByPackageFamily"));
133+
if (pGetPackagesByPackageFamily)
134+
{
135+
UINT32 count = 0;
136+
UINT32 bufferLength = 0;
137+
138+
if (pGetPackagesByPackageFamily(packageFamily, &count, nullptr, &bufferLength, nullptr) == ERROR_INSUFFICIENT_BUFFER && count > 0)
139+
{
140+
std::vector<PWSTR> names(count);
141+
std::vector<WCHAR> buffer(bufferLength);
142+
143+
if (pGetPackagesByPackageFamily(packageFamily, &count, names.data(), &bufferLength, buffer.data()) == ERROR_SUCCESS && count > 0)
144+
return names[0];
145+
}
146+
}
147+
148+
return {};
149+
}
150+
151+
static std::pair<std::wstring_view, std::wstring_view> ParseResourceString(const wchar_t* resourceString)
152+
{
153+
std::wstring_view str = resourceString;
154+
155+
if (str[0] == '@' && str[1] == '{')
156+
{
157+
str.remove_prefix(2);
158+
if (str.back() == '}')
159+
str.remove_suffix(1);
160+
161+
auto pos = str.find('?');
162+
if (pos != str.npos)
163+
return { str.substr(0, pos), str.substr(pos + 1) };
164+
}
165+
166+
return {};
167+
}
168+
169+
static std::wstring FormatResourceString(const std::wstring_view& package, const std::wstring_view& resource)
170+
{
171+
std::wstring retval(L"@{");
172+
173+
retval += package;
174+
retval += L"?";
175+
retval += resource;
176+
retval += L"}";
177+
178+
return retval;
179+
}
180+
181+
129182
static std::wstring TranslateIndirectString(const WCHAR* string)
130183
{
131184
std::wstring retval;
132185
retval.resize(1024);
133186

134-
if (SUCCEEDED(::SHLoadIndirectString(string, retval.data(), (UINT)retval.size(), nullptr)))
187+
auto hr = ::SHLoadIndirectString(string, retval.data(), (UINT)retval.size(), nullptr);
188+
189+
if (hr == E_INVALIDARG)
190+
{
191+
auto [package, resource] = ParseResourceString(string);
192+
if (!package.empty() && !resource.empty())
193+
{
194+
auto fullPackage = GetPackageFullName(std::wstring(package).c_str());
195+
if (!fullPackage.empty())
196+
{
197+
auto fullStr = FormatResourceString(fullPackage, resource);
198+
hr = ::SHLoadIndirectString(fullStr.c_str(), retval.data(), (UINT)retval.size(), nullptr);
199+
}
200+
}
201+
}
202+
203+
if (SUCCEEDED(hr))
135204
{
136205
retval.resize(wcslen(retval.data()));
137206
return retval;

0 commit comments

Comments
 (0)