From c6c06c149d07f382c93d0efdd68833a74b15f3b1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 22 Sep 2023 11:50:41 +0400 Subject: [PATCH] Check AppUserModelId better. --- .../win/notifications_manager_win.cpp | 8 +- .../SourceFiles/platform/win/specific_win.cpp | 10 +- .../win/windows_app_user_model_id.cpp | 375 ++++++++++-------- .../platform/win/windows_app_user_model_id.h | 34 +- 4 files changed, 243 insertions(+), 184 deletions(-) diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index 8782aeb116..41bf5f786a 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -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()); }); } diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index 290f444952..3f504357d6 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -209,9 +209,9 @@ bool ManageAppLink( if (const auto propertyStore = shellLink.try_as()) { 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. diff --git a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp index e6a6c92041..d18e3f9904 100644 --- a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp +++ b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.cpp @@ -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 #include -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 shellLink; - HRESULT hr = CoCreateInstance( - CLSID_ShellLink, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&shellLink)); + auto shellLink = base::WinRT::TryCreateInstance( + CLSID_ShellLink); + if (!shellLink) { + continue; + } + + auto persistFile = shellLink.try_as(); + if (!persistFile) { + continue; + } + + auto hr = persistFile->Load(fname.c_str(), STGM_READWRITE); if (!SUCCEEDED(hr)) continue; - ComPtr 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 propertyStore; - hr = shellLink.As(&propertyStore); - if (!SUCCEEDED(hr)) return; + if (GetUniqueFileId(dst) == srcid) { + auto propertyStore = shellLink.try_as(); + 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 shellLink; - HRESULT hr = CoCreateInstance( - CLSID_ShellLink, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&shellLink)); - if (!SUCCEEDED(hr)) return; + auto shellLink = base::WinRT::TryCreateInstance( + CLSID_ShellLink); + if (!shellLink) { + return; + } - ComPtr persistFile; - hr = shellLink.As(&persistFile); - if (!SUCCEEDED(hr)) return; + auto persistFile = shellLink.try_as(); + 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 shellLink; - HRESULT hr = CoCreateInstance( - CLSID_ShellLink, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&shellLink)); - if (!SUCCEEDED(hr)) return false; - - ComPtr 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( + CLSID_ShellLink); + if (!shellLink) { return false; } - ComPtr propertyStore; - hr = shellLink.As(&propertyStore); + auto persistFile = shellLink.try_as(); + 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(); + 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 shellLink; - HRESULT hr = CoCreateInstance( - CLSID_ShellLink, - nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&shellLink)); - if (!SUCCEEDED(hr)) return false; + auto shellLink = base::WinRT::TryCreateInstance( + 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 propertyStore; - hr = shellLink.As(&propertyStore); - if (!SUCCEEDED(hr)) return false; + auto propertyStore = shellLink.try_as(); + 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 persistFile; - hr = shellLink.As(&persistFile); - if (!SUCCEEDED(hr)) return false; + auto persistFile = shellLink.try_as(); + 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; } diff --git a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h index 5be435cb95..92d6c2b7d1 100644 --- a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h +++ b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h @@ -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