mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Check AppUserModelId better.
This commit is contained in:
parent
63a753d35c
commit
c6c06c149d
4 changed files with 243 additions and 184 deletions
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue