Check AppUserModelId better.

This commit is contained in:
John Preston 2023-09-22 11:50:41 +04:00
parent 63a753d35c
commit c6c06c149d
4 changed files with 243 additions and 184 deletions

View File

@ -118,7 +118,7 @@ bool init() {
LOG(("App Error: Object registration failed."));
}
}
if (!AppUserModelId::validateShortcut()) {
if (!AppUserModelId::ValidateShortcut()) {
LOG(("App Error: Shortcut validation failed."));
return false;
}
@ -132,7 +132,7 @@ bool init() {
CoTaskMemFree(appUserModelId);
});
if (AppUserModelId::getId() != appUserModelId) {
if (AppUserModelId::Id() != appUserModelId) {
return false;
}
return true;
@ -308,7 +308,7 @@ void QueryFocusAssist() {
}
return;
}
const auto appUserModelId = AppUserModelId::getId();
const auto appUserModelId = AppUserModelId::Id();
auto blocked = true;
const auto guard = gsl::finally([&] {
if (FocusAssistBlocks != blocked) {
@ -500,7 +500,7 @@ Manager::Private::Private(Manager *instance)
bool Manager::Private::init() {
return base::WinRT::Try([&] {
_notifier = ToastNotificationManager::CreateToastNotifier(
AppUserModelId::getId());
AppUserModelId::Id());
});
}

View File

@ -209,9 +209,9 @@ bool ManageAppLink(
if (const auto propertyStore = shellLink.try_as<IPropertyStore>()) {
PROPVARIANT appIdPropVar;
hr = InitPropVariantFromString(AppUserModelId::getId().c_str(), &appIdPropVar);
hr = InitPropVariantFromString(AppUserModelId::Id().c_str(), &appIdPropVar);
if (SUCCEEDED(hr)) {
hr = propertyStore->SetValue(AppUserModelId::getKey(), appIdPropVar);
hr = propertyStore->SetValue(AppUserModelId::Key(), appIdPropVar);
PropVariantClear(&appIdPropVar);
if (SUCCEEDED(hr)) {
hr = propertyStore->Commit();
@ -262,7 +262,7 @@ void psDoCleanup() {
try {
Platform::AutostartToggle(false);
psSendToMenu(false, true);
AppUserModelId::cleanupShortcut();
AppUserModelId::CleanupShortcut();
DeleteMyModules();
} catch (...) {
}
@ -371,7 +371,7 @@ void start() {
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale#utf-8-support
setlocale(LC_ALL, ".UTF8");
const auto appUserModelId = AppUserModelId::getId();
const auto appUserModelId = AppUserModelId::Id();
SetCurrentProcessExplicitAppUserModelID(appUserModelId.c_str());
LOG(("AppUserModelID: %1").arg(appUserModelId));
}
@ -643,7 +643,7 @@ bool OpenSystemSettings(SystemSettingsType type) {
void NewVersionLaunched(int oldVersion) {
if (oldVersion <= 4009009) {
AppUserModelId::checkPinned();
AppUserModelId::CheckPinned();
}
if (oldVersion > 0 && oldVersion < 2008012) {
// Reset icons cache, because we've changed the application icon.

View File

@ -9,35 +9,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/win/windows_dlls.h"
#include "platform/win/windows_toast_activator.h"
#include "base/platform/win/base_windows_wrl.h"
#include "base/platform/win/base_windows_winrt.h"
#include "core/launcher.h"
#include <propvarutil.h>
#include <propkey.h>
using namespace Microsoft::WRL;
namespace Platform {
namespace AppUserModelId {
namespace {
constexpr auto kMaxFileLen = MAX_PATH * 2;
const PROPERTYKEY pkey_AppUserModel_ID = { { 0x9F4C2855, 0x9F79, 0x4B39, { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 5 };
const PROPERTYKEY pkey_AppUserModel_StartPinOption = { { 0x9F4C2855, 0x9F79, 0x4B39, { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 12 };
const PROPERTYKEY pkey_AppUserModel_ToastActivator = { { 0x9F4C2855, 0x9F79, 0x4B39, { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 26 };
#ifdef OS_WIN_STORE
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop.Store";
const WCHAR AppUserModelIdBase[] = L"Telegram.TelegramDesktop.Store";
#else // OS_WIN_STORE
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop";
const WCHAR AppUserModelIdBase[] = L"Telegram.TelegramDesktop";
#endif // OS_WIN_STORE
const WCHAR AppUserModelIdAlpha[] = L"Telegram.TelegramDesktop.Alpha";
} // namespace
QString pinnedPath() {
static const int maxFileLen = MAX_PATH * 10;
WCHAR wstrPath[maxFileLen];
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
[[nodiscard]] QString PinnedIconsPath() {
WCHAR wstrPath[kMaxFileLen] = {};
if (GetEnvironmentVariable(L"APPDATA", wstrPath, kMaxFileLen)) {
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
return appData.absolutePath()
+ u"/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/"_q;
@ -45,34 +41,74 @@ QString pinnedPath() {
return QString();
}
void checkPinned() {
static const int maxFileLen = MAX_PATH * 10;
} // namespace
HRESULT hr = CoInitialize(0);
if (!SUCCEEDED(hr)) return;
const std::wstring &MyExecutablePath() {
static const auto Path = [&] {
auto result = std::wstring(kMaxFileLen, 0);
const auto length = GetModuleFileName(
GetModuleHandle(nullptr),
result.data(),
kMaxFileLen);
if (!length || length == kMaxFileLen) {
result.clear();
} else {
result.resize(length + 1);
}
return result;
}();
return Path;
}
QString path = pinnedPath();
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
UniqueFileId MyExecutablePathId() {
return GetUniqueFileId(MyExecutablePath().c_str());
}
WCHAR src[MAX_PATH];
GetModuleFileName(GetModuleHandle(0), src, MAX_PATH);
BY_HANDLE_FILE_INFORMATION srcinfo = { 0 };
HANDLE srcfile = CreateFile(
src,
0x00,
0x00,
NULL,
UniqueFileId GetUniqueFileId(LPCWSTR path) {
auto info = BY_HANDLE_FILE_INFORMATION{};
const auto file = CreateFile(
path,
0,
0,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (srcfile == INVALID_HANDLE_VALUE) return;
BOOL srcres = GetFileInformationByHandle(srcfile, &srcinfo);
CloseHandle(srcfile);
if (!srcres) return;
nullptr);
if (file == INVALID_HANDLE_VALUE) {
return {};
}
const auto result = GetFileInformationByHandle(file, &info);
CloseHandle(file);
if (!result) {
return {};
}
return {
.part1 = info.dwVolumeSerialNumber,
.part2 = ((std::uint64_t(info.nFileIndexLow) << 32)
| std::uint64_t(info.nFileIndexHigh)),
};
}
void CheckPinned() {
if (!SUCCEEDED(CoInitialize(0))) {
return;
}
const auto coGuard = gsl::finally([] {
CoUninitialize();
});
const auto path = PinnedIconsPath();
const auto native = QDir::toNativeSeparators(path).toStdWString();
const auto srcid = MyExecutablePathId();
if (!srcid) {
return;
}
LOG(("Checking..."));
WIN32_FIND_DATA findData;
HANDLE findHandle = FindFirstFileEx(
(p + L"*").c_str(),
(native + L"*").c_str(),
FindExInfoStandard,
&findData,
FindExSearchNameMatch,
@ -83,62 +119,48 @@ void checkPinned() {
return;
}
do {
std::wstring fname = p + findData.cFileName;
std::wstring fname = native + findData.cFileName;
LOG(("Checking %1").arg(QString::fromStdWString(fname)));
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
} else {
DWORD attributes = GetFileAttributes(fname.c_str());
if (attributes >= 0xFFFFFFF) continue; // file does not exist
if (attributes >= 0xFFFFFFF) {
continue; // file does not exist
}
ComPtr<IShellLink> shellLink;
HRESULT hr = CoCreateInstance(
CLSID_ShellLink,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&shellLink));
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
CLSID_ShellLink);
if (!shellLink) {
continue;
}
auto persistFile = shellLink.try_as<IPersistFile>();
if (!persistFile) {
continue;
}
auto hr = persistFile->Load(fname.c_str(), STGM_READWRITE);
if (!SUCCEEDED(hr)) continue;
ComPtr<IPersistFile> persistFile;
hr = shellLink.As(&persistFile);
WCHAR dst[MAX_PATH] = { 0 };
hr = shellLink->GetPath(dst, MAX_PATH, nullptr, 0);
if (!SUCCEEDED(hr)) continue;
hr = persistFile->Load(fname.c_str(), STGM_READWRITE);
if (!SUCCEEDED(hr)) continue;
WCHAR dst[MAX_PATH];
hr = shellLink->GetPath(dst, MAX_PATH, 0, 0);
if (!SUCCEEDED(hr)) continue;
BY_HANDLE_FILE_INFORMATION dstinfo = { 0 };
HANDLE dstfile = CreateFile(
dst,
0x00,
0x00,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dstfile == INVALID_HANDLE_VALUE) continue;
BOOL dstres = GetFileInformationByHandle(dstfile, &dstinfo);
CloseHandle(dstfile);
if (!dstres) continue;
if (srcinfo.dwVolumeSerialNumber == dstinfo.dwVolumeSerialNumber
&& srcinfo.nFileIndexLow == dstinfo.nFileIndexLow
&& srcinfo.nFileIndexHigh == dstinfo.nFileIndexHigh) {
ComPtr<IPropertyStore> propertyStore;
hr = shellLink.As(&propertyStore);
if (!SUCCEEDED(hr)) return;
if (GetUniqueFileId(dst) == srcid) {
auto propertyStore = shellLink.try_as<IPropertyStore>();
if (!propertyStore) {
return;
}
PROPVARIANT appIdPropVar;
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
hr = propertyStore->GetValue(Key(), &appIdPropVar);
if (!SUCCEEDED(hr)) return;
LOG(("Reading..."));
WCHAR already[MAX_PATH];
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
if (SUCCEEDED(hr)) {
if (getId() == already) {
if (Id() == already) {
LOG(("Already!"));
PropVariantClear(&appIdPropVar);
return;
@ -150,10 +172,10 @@ void checkPinned() {
}
PropVariantClear(&appIdPropVar);
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
if (!SUCCEEDED(hr)) return;
hr = propertyStore->SetValue(getKey(), appIdPropVar);
hr = propertyStore->SetValue(Key(), appIdPropVar);
PropVariantClear(&appIdPropVar);
if (!SUCCEEDED(hr)) return;
@ -176,9 +198,8 @@ void checkPinned() {
}
QString systemShortcutPath() {
static const int maxFileLen = MAX_PATH * 10;
WCHAR wstrPath[maxFileLen];
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
WCHAR wstrPath[kMaxFileLen] = {};
if (GetEnvironmentVariable(L"APPDATA", wstrPath, kMaxFileLen)) {
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
const auto path = appData.absolutePath();
return path + u"/Microsoft/Windows/Start Menu/Programs/"_q;
@ -186,8 +207,11 @@ QString systemShortcutPath() {
return QString();
}
void cleanupShortcut() {
static const int maxFileLen = MAX_PATH * 10;
void CleanupShortcut() {
const auto myid = MyExecutablePathId();
if (!myid) {
return;
}
QString path = systemShortcutPath() + u"Telegram.lnk"_q;
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
@ -195,80 +219,69 @@ void cleanupShortcut() {
DWORD attributes = GetFileAttributes(p.c_str());
if (attributes >= 0xFFFFFFF) return; // file does not exist
ComPtr<IShellLink> shellLink;
HRESULT hr = CoCreateInstance(
CLSID_ShellLink,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&shellLink));
if (!SUCCEEDED(hr)) return;
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
CLSID_ShellLink);
if (!shellLink) {
return;
}
ComPtr<IPersistFile> persistFile;
hr = shellLink.As(&persistFile);
if (!SUCCEEDED(hr)) return;
auto persistFile = shellLink.try_as<IPersistFile>();
if (!persistFile) {
return;
}
hr = persistFile->Load(p.c_str(), STGM_READWRITE);
auto hr = persistFile->Load(p.c_str(), STGM_READWRITE);
if (!SUCCEEDED(hr)) return;
WCHAR szGotPath[MAX_PATH];
WIN32_FIND_DATA wfd;
hr = shellLink->GetPath(
szGotPath,
MAX_PATH,
(WIN32_FIND_DATA*)&wfd,
SLGP_SHORTPATH);
hr = shellLink->GetPath(szGotPath, MAX_PATH, nullptr, 0);
if (!SUCCEEDED(hr)) return;
const auto full = cExeDir() + cExeName();
if (QDir::toNativeSeparators(full).toStdWString() == szGotPath) {
if (GetUniqueFileId(szGotPath) == myid) {
QFile().remove(path);
}
}
bool validateShortcutAt(const QString &path) {
static const int maxFileLen = MAX_PATH * 10;
const auto native = QDir::toNativeSeparators(path).toStdWString();
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
DWORD attributes = GetFileAttributes(native.c_str());
if (attributes >= 0xFFFFFFF) {
return false; // file does not exist
}
DWORD attributes = GetFileAttributes(p.c_str());
if (attributes >= 0xFFFFFFF) return false; // file does not exist
ComPtr<IShellLink> shellLink;
HRESULT hr = CoCreateInstance(
CLSID_ShellLink,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&shellLink));
if (!SUCCEEDED(hr)) return false;
ComPtr<IPersistFile> persistFile;
hr = shellLink.As(&persistFile);
if (!SUCCEEDED(hr)) return false;
hr = persistFile->Load(p.c_str(), STGM_READWRITE);
if (!SUCCEEDED(hr)) return false;
WCHAR szGotPath[MAX_PATH];
WIN32_FIND_DATA wfd;
hr = shellLink->GetPath(
szGotPath,
MAX_PATH,
(WIN32_FIND_DATA*)&wfd,
SLGP_SHORTPATH);
if (!SUCCEEDED(hr)) return false;
const auto full = cExeDir() + cExeName();
if (QDir::toNativeSeparators(full).toStdWString() != szGotPath) {
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
CLSID_ShellLink);
if (!shellLink) {
return false;
}
ComPtr<IPropertyStore> propertyStore;
hr = shellLink.As(&propertyStore);
auto persistFile = shellLink.try_as<IPersistFile>();
if (!persistFile) {
return false;
}
auto hr = persistFile->Load(native.c_str(), STGM_READWRITE);
if (!SUCCEEDED(hr)) return false;
WCHAR szGotPath[kMaxFileLen] = { 0 };
hr = shellLink->GetPath(szGotPath, kMaxFileLen, nullptr, 0);
if (!SUCCEEDED(hr)) {
return false;
}
if (GetUniqueFileId(szGotPath) != MyExecutablePathId()) {
return false;
}
auto propertyStore = shellLink.try_as<IPropertyStore>();
if (!propertyStore) {
return false;
}
PROPVARIANT appIdPropVar;
PROPVARIANT toastActivatorPropVar;
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
hr = propertyStore->GetValue(Key(), &appIdPropVar);
if (!SUCCEEDED(hr)) return false;
hr = propertyStore->GetValue(
@ -278,7 +291,7 @@ bool validateShortcutAt(const QString &path) {
WCHAR already[MAX_PATH];
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
const auto good1 = SUCCEEDED(hr) && (getId() == already);
const auto good1 = SUCCEEDED(hr) && (Id() == already);
const auto bad1 = !good1 && (appIdPropVar.vt != VT_EMPTY);
PropVariantClear(&appIdPropVar);
@ -294,10 +307,10 @@ bool validateShortcutAt(const QString &path) {
return false;
}
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
if (!SUCCEEDED(hr)) return false;
hr = propertyStore->SetValue(getKey(), appIdPropVar);
hr = propertyStore->SetValue(Key(), appIdPropVar);
PropVariantClear(&appIdPropVar);
if (!SUCCEEDED(hr)) return false;
@ -316,7 +329,7 @@ bool validateShortcutAt(const QString &path) {
if (!SUCCEEDED(hr)) return false;
if (persistFile->IsDirty() == S_OK) {
hr = persistFile->Save(p.c_str(), TRUE);
hr = persistFile->Save(native.c_str(), TRUE);
if (!SUCCEEDED(hr)) return false;
}
@ -338,7 +351,7 @@ bool checkInstalled(QString path = {}) {
|| validateShortcutAt(path + old);
}
bool validateShortcut() {
bool ValidateShortcut() {
QString path = systemShortcutPath();
if (path.isEmpty() || cExeName().isEmpty()) {
return false;
@ -360,88 +373,109 @@ bool validateShortcut() {
}
}
ComPtr<IShellLink> shellLink;
HRESULT hr = CoCreateInstance(
CLSID_ShellLink,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&shellLink));
if (!SUCCEEDED(hr)) return false;
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
CLSID_ShellLink);
if (!shellLink) {
return false;
}
hr = shellLink->SetPath(
QDir::toNativeSeparators(
cExeDir() + cExeName()).toStdWString().c_str());
if (!SUCCEEDED(hr)) return false;
auto hr = shellLink->SetPath(MyExecutablePath().c_str());
if (!SUCCEEDED(hr)) {
return false;
}
hr = shellLink->SetArguments(L"");
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
hr = shellLink->SetWorkingDirectory(
QDir::toNativeSeparators(
QDir(cWorkingDir()).absolutePath()).toStdWString().c_str());
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
ComPtr<IPropertyStore> propertyStore;
hr = shellLink.As(&propertyStore);
if (!SUCCEEDED(hr)) return false;
auto propertyStore = shellLink.try_as<IPropertyStore>();
if (!propertyStore) {
return false;
}
PROPVARIANT appIdPropVar;
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
if (!SUCCEEDED(hr)) return false;
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
if (!SUCCEEDED(hr)) {
return false;
}
hr = propertyStore->SetValue(getKey(), appIdPropVar);
hr = propertyStore->SetValue(Key(), appIdPropVar);
PropVariantClear(&appIdPropVar);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
PROPVARIANT startPinPropVar;
hr = InitPropVariantFromUInt32(
APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL,
&startPinPropVar);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
hr = propertyStore->SetValue(
pkey_AppUserModel_StartPinOption,
startPinPropVar);
PropVariantClear(&startPinPropVar);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
PROPVARIANT toastActivatorPropVar{};
hr = InitPropVariantFromCLSID(
__uuidof(ToastActivator),
&toastActivatorPropVar);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
hr = propertyStore->SetValue(
pkey_AppUserModel_ToastActivator,
toastActivatorPropVar);
PropVariantClear(&toastActivatorPropVar);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
hr = propertyStore->Commit();
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
ComPtr<IPersistFile> persistFile;
hr = shellLink.As(&persistFile);
if (!SUCCEEDED(hr)) return false;
auto persistFile = shellLink.try_as<IPersistFile>();
if (!persistFile) {
return false;
}
hr = persistFile->Save(
QDir::toNativeSeparators(path).toStdWString().c_str(),
TRUE);
if (!SUCCEEDED(hr)) return false;
if (!SUCCEEDED(hr)) {
return false;
}
LOG(("App Info: Shortcut created and validated at \"%1\"").arg(path));
return true;
}
const std::wstring &getId() {
static const std::wstring BaseId(cAlphaVersion()
? AppUserModelIdAlpha
: AppUserModelIdRelease);
const std::wstring &Id() {
static const auto BaseId = std::wstring(AppUserModelIdBase);
static auto CheckingInstalled = false;
if (CheckingInstalled) {
return BaseId;
}
static const auto Installed = [] {
#ifdef OS_WIN_STORE
return true;
#else // OS_WIN_STORE
CheckingInstalled = true;
const auto guard = gsl::finally([] {
CheckingInstalled = false;
@ -453,6 +487,7 @@ const std::wstring &getId() {
CoUninitialize();
});
return checkInstalled();
#endif
}();
if (Installed) {
return BaseId;
@ -471,7 +506,7 @@ const std::wstring &getId() {
return PortableId;
}
const PROPERTYKEY &getKey() {
const PROPERTYKEY &Key() {
return pkey_AppUserModel_ID;
}

View File

@ -12,13 +12,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Platform {
namespace AppUserModelId {
void cleanupShortcut();
void checkPinned();
void CleanupShortcut();
void CheckPinned();
const std::wstring &getId();
bool validateShortcut();
[[nodiscard]] const std::wstring &Id();
bool ValidateShortcut();
const PROPERTYKEY &getKey();
[[nodiscard]] const PROPERTYKEY &Key();
[[nodiscard]] const std::wstring &MyExecutablePath();
struct UniqueFileId {
std::uint64_t part1 = 0;
std::uint64_t part2 = 0;
[[nodiscard]] bool valid() const {
return part1 || part2;
}
[[nodiscard]] explicit operator bool() const {
return valid();
}
[[nodiscard]] friend inline auto operator<=>(
UniqueFileId a,
UniqueFileId b) = default;
[[nodiscard]] friend inline bool operator==(
UniqueFileId a,
UniqueFileId b) = default;
};
[[nodiscard]] UniqueFileId GetUniqueFileId(LPCWSTR path);
[[nodiscard]] UniqueFileId MyExecutablePathId();
} // namespace AppUserModelId
} // namespace Platform