Check AppUserModelId better.
This commit is contained in:
parent
63a753d35c
commit
c6c06c149d
|
@ -118,7 +118,7 @@ bool init() {
|
||||||
LOG(("App Error: Object registration failed."));
|
LOG(("App Error: Object registration failed."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!AppUserModelId::validateShortcut()) {
|
if (!AppUserModelId::ValidateShortcut()) {
|
||||||
LOG(("App Error: Shortcut validation failed."));
|
LOG(("App Error: Shortcut validation failed."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ bool init() {
|
||||||
CoTaskMemFree(appUserModelId);
|
CoTaskMemFree(appUserModelId);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (AppUserModelId::getId() != appUserModelId) {
|
if (AppUserModelId::Id() != appUserModelId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -308,7 +308,7 @@ void QueryFocusAssist() {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto appUserModelId = AppUserModelId::getId();
|
const auto appUserModelId = AppUserModelId::Id();
|
||||||
auto blocked = true;
|
auto blocked = true;
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
if (FocusAssistBlocks != blocked) {
|
if (FocusAssistBlocks != blocked) {
|
||||||
|
@ -500,7 +500,7 @@ Manager::Private::Private(Manager *instance)
|
||||||
bool Manager::Private::init() {
|
bool Manager::Private::init() {
|
||||||
return base::WinRT::Try([&] {
|
return base::WinRT::Try([&] {
|
||||||
_notifier = ToastNotificationManager::CreateToastNotifier(
|
_notifier = ToastNotificationManager::CreateToastNotifier(
|
||||||
AppUserModelId::getId());
|
AppUserModelId::Id());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,9 +209,9 @@ bool ManageAppLink(
|
||||||
|
|
||||||
if (const auto propertyStore = shellLink.try_as<IPropertyStore>()) {
|
if (const auto propertyStore = shellLink.try_as<IPropertyStore>()) {
|
||||||
PROPVARIANT appIdPropVar;
|
PROPVARIANT appIdPropVar;
|
||||||
hr = InitPropVariantFromString(AppUserModelId::getId().c_str(), &appIdPropVar);
|
hr = InitPropVariantFromString(AppUserModelId::Id().c_str(), &appIdPropVar);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
hr = propertyStore->SetValue(AppUserModelId::getKey(), appIdPropVar);
|
hr = propertyStore->SetValue(AppUserModelId::Key(), appIdPropVar);
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
hr = propertyStore->Commit();
|
hr = propertyStore->Commit();
|
||||||
|
@ -262,7 +262,7 @@ void psDoCleanup() {
|
||||||
try {
|
try {
|
||||||
Platform::AutostartToggle(false);
|
Platform::AutostartToggle(false);
|
||||||
psSendToMenu(false, true);
|
psSendToMenu(false, true);
|
||||||
AppUserModelId::cleanupShortcut();
|
AppUserModelId::CleanupShortcut();
|
||||||
DeleteMyModules();
|
DeleteMyModules();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
@ -371,7 +371,7 @@ void start() {
|
||||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale#utf-8-support
|
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale#utf-8-support
|
||||||
setlocale(LC_ALL, ".UTF8");
|
setlocale(LC_ALL, ".UTF8");
|
||||||
|
|
||||||
const auto appUserModelId = AppUserModelId::getId();
|
const auto appUserModelId = AppUserModelId::Id();
|
||||||
SetCurrentProcessExplicitAppUserModelID(appUserModelId.c_str());
|
SetCurrentProcessExplicitAppUserModelID(appUserModelId.c_str());
|
||||||
LOG(("AppUserModelID: %1").arg(appUserModelId));
|
LOG(("AppUserModelID: %1").arg(appUserModelId));
|
||||||
}
|
}
|
||||||
|
@ -643,7 +643,7 @@ bool OpenSystemSettings(SystemSettingsType type) {
|
||||||
|
|
||||||
void NewVersionLaunched(int oldVersion) {
|
void NewVersionLaunched(int oldVersion) {
|
||||||
if (oldVersion <= 4009009) {
|
if (oldVersion <= 4009009) {
|
||||||
AppUserModelId::checkPinned();
|
AppUserModelId::CheckPinned();
|
||||||
}
|
}
|
||||||
if (oldVersion > 0 && oldVersion < 2008012) {
|
if (oldVersion > 0 && oldVersion < 2008012) {
|
||||||
// Reset icons cache, because we've changed the application icon.
|
// 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_dlls.h"
|
||||||
#include "platform/win/windows_toast_activator.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 "core/launcher.h"
|
||||||
|
|
||||||
#include <propvarutil.h>
|
#include <propvarutil.h>
|
||||||
#include <propkey.h>
|
#include <propkey.h>
|
||||||
|
|
||||||
using namespace Microsoft::WRL;
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace AppUserModelId {
|
namespace AppUserModelId {
|
||||||
namespace {
|
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_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_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 };
|
const PROPERTYKEY pkey_AppUserModel_ToastActivator = { { 0x9F4C2855, 0x9F79, 0x4B39, { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 26 };
|
||||||
|
|
||||||
#ifdef OS_WIN_STORE
|
#ifdef OS_WIN_STORE
|
||||||
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop.Store";
|
const WCHAR AppUserModelIdBase[] = L"Telegram.TelegramDesktop.Store";
|
||||||
#else // OS_WIN_STORE
|
#else // OS_WIN_STORE
|
||||||
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop";
|
const WCHAR AppUserModelIdBase[] = L"Telegram.TelegramDesktop";
|
||||||
#endif // OS_WIN_STORE
|
#endif // OS_WIN_STORE
|
||||||
const WCHAR AppUserModelIdAlpha[] = L"Telegram.TelegramDesktop.Alpha";
|
|
||||||
|
|
||||||
} // namespace
|
[[nodiscard]] QString PinnedIconsPath() {
|
||||||
|
WCHAR wstrPath[kMaxFileLen] = {};
|
||||||
QString pinnedPath() {
|
if (GetEnvironmentVariable(L"APPDATA", wstrPath, kMaxFileLen)) {
|
||||||
static const int maxFileLen = MAX_PATH * 10;
|
|
||||||
WCHAR wstrPath[maxFileLen];
|
|
||||||
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
|
|
||||||
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
||||||
return appData.absolutePath()
|
return appData.absolutePath()
|
||||||
+ u"/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/"_q;
|
+ u"/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/"_q;
|
||||||
|
@ -45,34 +41,74 @@ QString pinnedPath() {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkPinned() {
|
} // namespace
|
||||||
static const int maxFileLen = MAX_PATH * 10;
|
|
||||||
|
|
||||||
HRESULT hr = CoInitialize(0);
|
const std::wstring &MyExecutablePath() {
|
||||||
if (!SUCCEEDED(hr)) return;
|
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();
|
UniqueFileId MyExecutablePathId() {
|
||||||
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
return GetUniqueFileId(MyExecutablePath().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
WCHAR src[MAX_PATH];
|
UniqueFileId GetUniqueFileId(LPCWSTR path) {
|
||||||
GetModuleFileName(GetModuleHandle(0), src, MAX_PATH);
|
auto info = BY_HANDLE_FILE_INFORMATION{};
|
||||||
BY_HANDLE_FILE_INFORMATION srcinfo = { 0 };
|
const auto file = CreateFile(
|
||||||
HANDLE srcfile = CreateFile(
|
path,
|
||||||
src,
|
0,
|
||||||
0x00,
|
0,
|
||||||
0x00,
|
nullptr,
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
NULL);
|
nullptr);
|
||||||
if (srcfile == INVALID_HANDLE_VALUE) return;
|
if (file == INVALID_HANDLE_VALUE) {
|
||||||
BOOL srcres = GetFileInformationByHandle(srcfile, &srcinfo);
|
return {};
|
||||||
CloseHandle(srcfile);
|
}
|
||||||
if (!srcres) 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..."));
|
LOG(("Checking..."));
|
||||||
WIN32_FIND_DATA findData;
|
WIN32_FIND_DATA findData;
|
||||||
HANDLE findHandle = FindFirstFileEx(
|
HANDLE findHandle = FindFirstFileEx(
|
||||||
(p + L"*").c_str(),
|
(native + L"*").c_str(),
|
||||||
FindExInfoStandard,
|
FindExInfoStandard,
|
||||||
&findData,
|
&findData,
|
||||||
FindExSearchNameMatch,
|
FindExSearchNameMatch,
|
||||||
|
@ -83,62 +119,48 @@ void checkPinned() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
std::wstring fname = p + findData.cFileName;
|
std::wstring fname = native + findData.cFileName;
|
||||||
LOG(("Checking %1").arg(QString::fromStdWString(fname)));
|
LOG(("Checking %1").arg(QString::fromStdWString(fname)));
|
||||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
DWORD attributes = GetFileAttributes(fname.c_str());
|
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;
|
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
HRESULT hr = CoCreateInstance(
|
CLSID_ShellLink);
|
||||||
CLSID_ShellLink,
|
if (!shellLink) {
|
||||||
nullptr,
|
continue;
|
||||||
CLSCTX_INPROC_SERVER,
|
}
|
||||||
IID_PPV_ARGS(&shellLink));
|
|
||||||
|
auto persistFile = shellLink.try_as<IPersistFile>();
|
||||||
|
if (!persistFile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hr = persistFile->Load(fname.c_str(), STGM_READWRITE);
|
||||||
if (!SUCCEEDED(hr)) continue;
|
if (!SUCCEEDED(hr)) continue;
|
||||||
|
|
||||||
ComPtr<IPersistFile> persistFile;
|
WCHAR dst[MAX_PATH] = { 0 };
|
||||||
hr = shellLink.As(&persistFile);
|
hr = shellLink->GetPath(dst, MAX_PATH, nullptr, 0);
|
||||||
if (!SUCCEEDED(hr)) continue;
|
if (!SUCCEEDED(hr)) continue;
|
||||||
|
|
||||||
hr = persistFile->Load(fname.c_str(), STGM_READWRITE);
|
if (GetUniqueFileId(dst) == srcid) {
|
||||||
if (!SUCCEEDED(hr)) continue;
|
auto propertyStore = shellLink.try_as<IPropertyStore>();
|
||||||
|
if (!propertyStore) {
|
||||||
WCHAR dst[MAX_PATH];
|
return;
|
||||||
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;
|
|
||||||
|
|
||||||
PROPVARIANT appIdPropVar;
|
PROPVARIANT appIdPropVar;
|
||||||
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
|
hr = propertyStore->GetValue(Key(), &appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return;
|
if (!SUCCEEDED(hr)) return;
|
||||||
LOG(("Reading..."));
|
LOG(("Reading..."));
|
||||||
WCHAR already[MAX_PATH];
|
WCHAR already[MAX_PATH];
|
||||||
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
|
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
if (getId() == already) {
|
if (Id() == already) {
|
||||||
LOG(("Already!"));
|
LOG(("Already!"));
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
return;
|
return;
|
||||||
|
@ -150,10 +172,10 @@ void checkPinned() {
|
||||||
}
|
}
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
|
|
||||||
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
|
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return;
|
if (!SUCCEEDED(hr)) return;
|
||||||
|
|
||||||
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
hr = propertyStore->SetValue(Key(), appIdPropVar);
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return;
|
if (!SUCCEEDED(hr)) return;
|
||||||
|
|
||||||
|
@ -176,9 +198,8 @@ void checkPinned() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString systemShortcutPath() {
|
QString systemShortcutPath() {
|
||||||
static const int maxFileLen = MAX_PATH * 10;
|
WCHAR wstrPath[kMaxFileLen] = {};
|
||||||
WCHAR wstrPath[maxFileLen];
|
if (GetEnvironmentVariable(L"APPDATA", wstrPath, kMaxFileLen)) {
|
||||||
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
|
|
||||||
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
||||||
const auto path = appData.absolutePath();
|
const auto path = appData.absolutePath();
|
||||||
return path + u"/Microsoft/Windows/Start Menu/Programs/"_q;
|
return path + u"/Microsoft/Windows/Start Menu/Programs/"_q;
|
||||||
|
@ -186,8 +207,11 @@ QString systemShortcutPath() {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanupShortcut() {
|
void CleanupShortcut() {
|
||||||
static const int maxFileLen = MAX_PATH * 10;
|
const auto myid = MyExecutablePathId();
|
||||||
|
if (!myid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString path = systemShortcutPath() + u"Telegram.lnk"_q;
|
QString path = systemShortcutPath() + u"Telegram.lnk"_q;
|
||||||
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
||||||
|
@ -195,80 +219,69 @@ void cleanupShortcut() {
|
||||||
DWORD attributes = GetFileAttributes(p.c_str());
|
DWORD attributes = GetFileAttributes(p.c_str());
|
||||||
if (attributes >= 0xFFFFFFF) return; // file does not exist
|
if (attributes >= 0xFFFFFFF) return; // file does not exist
|
||||||
|
|
||||||
ComPtr<IShellLink> shellLink;
|
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
HRESULT hr = CoCreateInstance(
|
CLSID_ShellLink);
|
||||||
CLSID_ShellLink,
|
if (!shellLink) {
|
||||||
nullptr,
|
return;
|
||||||
CLSCTX_INPROC_SERVER,
|
}
|
||||||
IID_PPV_ARGS(&shellLink));
|
|
||||||
if (!SUCCEEDED(hr)) return;
|
|
||||||
|
|
||||||
ComPtr<IPersistFile> persistFile;
|
auto persistFile = shellLink.try_as<IPersistFile>();
|
||||||
hr = shellLink.As(&persistFile);
|
if (!persistFile) {
|
||||||
if (!SUCCEEDED(hr)) return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
hr = persistFile->Load(p.c_str(), STGM_READWRITE);
|
auto hr = persistFile->Load(p.c_str(), STGM_READWRITE);
|
||||||
if (!SUCCEEDED(hr)) return;
|
if (!SUCCEEDED(hr)) return;
|
||||||
|
|
||||||
WCHAR szGotPath[MAX_PATH];
|
WCHAR szGotPath[MAX_PATH];
|
||||||
WIN32_FIND_DATA wfd;
|
hr = shellLink->GetPath(szGotPath, MAX_PATH, nullptr, 0);
|
||||||
hr = shellLink->GetPath(
|
|
||||||
szGotPath,
|
|
||||||
MAX_PATH,
|
|
||||||
(WIN32_FIND_DATA*)&wfd,
|
|
||||||
SLGP_SHORTPATH);
|
|
||||||
if (!SUCCEEDED(hr)) return;
|
if (!SUCCEEDED(hr)) return;
|
||||||
|
|
||||||
const auto full = cExeDir() + cExeName();
|
if (GetUniqueFileId(szGotPath) == myid) {
|
||||||
if (QDir::toNativeSeparators(full).toStdWString() == szGotPath) {
|
|
||||||
QFile().remove(path);
|
QFile().remove(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateShortcutAt(const QString &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());
|
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
if (attributes >= 0xFFFFFFF) return false; // file does not exist
|
CLSID_ShellLink);
|
||||||
|
if (!shellLink) {
|
||||||
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) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<IPropertyStore> propertyStore;
|
auto persistFile = shellLink.try_as<IPersistFile>();
|
||||||
hr = shellLink.As(&propertyStore);
|
if (!persistFile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hr = persistFile->Load(native.c_str(), STGM_READWRITE);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
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 appIdPropVar;
|
||||||
PROPVARIANT toastActivatorPropVar;
|
PROPVARIANT toastActivatorPropVar;
|
||||||
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
|
hr = propertyStore->GetValue(Key(), &appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
hr = propertyStore->GetValue(
|
hr = propertyStore->GetValue(
|
||||||
|
@ -278,7 +291,7 @@ bool validateShortcutAt(const QString &path) {
|
||||||
|
|
||||||
WCHAR already[MAX_PATH];
|
WCHAR already[MAX_PATH];
|
||||||
hr = PropVariantToString(appIdPropVar, 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);
|
const auto bad1 = !good1 && (appIdPropVar.vt != VT_EMPTY);
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
|
|
||||||
|
@ -294,10 +307,10 @@ bool validateShortcutAt(const QString &path) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
|
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
hr = propertyStore->SetValue(Key(), appIdPropVar);
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
|
@ -316,7 +329,7 @@ bool validateShortcutAt(const QString &path) {
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
if (persistFile->IsDirty() == S_OK) {
|
if (persistFile->IsDirty() == S_OK) {
|
||||||
hr = persistFile->Save(p.c_str(), TRUE);
|
hr = persistFile->Save(native.c_str(), TRUE);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +351,7 @@ bool checkInstalled(QString path = {}) {
|
||||||
|| validateShortcutAt(path + old);
|
|| validateShortcutAt(path + old);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateShortcut() {
|
bool ValidateShortcut() {
|
||||||
QString path = systemShortcutPath();
|
QString path = systemShortcutPath();
|
||||||
if (path.isEmpty() || cExeName().isEmpty()) {
|
if (path.isEmpty() || cExeName().isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -360,88 +373,109 @@ bool validateShortcut() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<IShellLink> shellLink;
|
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
HRESULT hr = CoCreateInstance(
|
CLSID_ShellLink);
|
||||||
CLSID_ShellLink,
|
if (!shellLink) {
|
||||||
nullptr,
|
return false;
|
||||||
CLSCTX_INPROC_SERVER,
|
}
|
||||||
IID_PPV_ARGS(&shellLink));
|
|
||||||
if (!SUCCEEDED(hr)) return false;
|
|
||||||
|
|
||||||
hr = shellLink->SetPath(
|
auto hr = shellLink->SetPath(MyExecutablePath().c_str());
|
||||||
QDir::toNativeSeparators(
|
if (!SUCCEEDED(hr)) {
|
||||||
cExeDir() + cExeName()).toStdWString().c_str());
|
return false;
|
||||||
if (!SUCCEEDED(hr)) return false;
|
}
|
||||||
|
|
||||||
hr = shellLink->SetArguments(L"");
|
hr = shellLink->SetArguments(L"");
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = shellLink->SetWorkingDirectory(
|
hr = shellLink->SetWorkingDirectory(
|
||||||
QDir::toNativeSeparators(
|
QDir::toNativeSeparators(
|
||||||
QDir(cWorkingDir()).absolutePath()).toStdWString().c_str());
|
QDir(cWorkingDir()).absolutePath()).toStdWString().c_str());
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ComPtr<IPropertyStore> propertyStore;
|
auto propertyStore = shellLink.try_as<IPropertyStore>();
|
||||||
hr = shellLink.As(&propertyStore);
|
if (!propertyStore) {
|
||||||
if (!SUCCEEDED(hr)) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PROPVARIANT appIdPropVar;
|
PROPVARIANT appIdPropVar;
|
||||||
hr = InitPropVariantFromString(getId().c_str(), &appIdPropVar);
|
hr = InitPropVariantFromString(Id().c_str(), &appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
hr = propertyStore->SetValue(Key(), appIdPropVar);
|
||||||
PropVariantClear(&appIdPropVar);
|
PropVariantClear(&appIdPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PROPVARIANT startPinPropVar;
|
PROPVARIANT startPinPropVar;
|
||||||
hr = InitPropVariantFromUInt32(
|
hr = InitPropVariantFromUInt32(
|
||||||
APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL,
|
APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL,
|
||||||
&startPinPropVar);
|
&startPinPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = propertyStore->SetValue(
|
hr = propertyStore->SetValue(
|
||||||
pkey_AppUserModel_StartPinOption,
|
pkey_AppUserModel_StartPinOption,
|
||||||
startPinPropVar);
|
startPinPropVar);
|
||||||
PropVariantClear(&startPinPropVar);
|
PropVariantClear(&startPinPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PROPVARIANT toastActivatorPropVar{};
|
PROPVARIANT toastActivatorPropVar{};
|
||||||
hr = InitPropVariantFromCLSID(
|
hr = InitPropVariantFromCLSID(
|
||||||
__uuidof(ToastActivator),
|
__uuidof(ToastActivator),
|
||||||
&toastActivatorPropVar);
|
&toastActivatorPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = propertyStore->SetValue(
|
hr = propertyStore->SetValue(
|
||||||
pkey_AppUserModel_ToastActivator,
|
pkey_AppUserModel_ToastActivator,
|
||||||
toastActivatorPropVar);
|
toastActivatorPropVar);
|
||||||
PropVariantClear(&toastActivatorPropVar);
|
PropVariantClear(&toastActivatorPropVar);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = propertyStore->Commit();
|
hr = propertyStore->Commit();
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ComPtr<IPersistFile> persistFile;
|
auto persistFile = shellLink.try_as<IPersistFile>();
|
||||||
hr = shellLink.As(&persistFile);
|
if (!persistFile) {
|
||||||
if (!SUCCEEDED(hr)) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
hr = persistFile->Save(
|
hr = persistFile->Save(
|
||||||
QDir::toNativeSeparators(path).toStdWString().c_str(),
|
QDir::toNativeSeparators(path).toStdWString().c_str(),
|
||||||
TRUE);
|
TRUE);
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LOG(("App Info: Shortcut created and validated at \"%1\"").arg(path));
|
LOG(("App Info: Shortcut created and validated at \"%1\"").arg(path));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::wstring &getId() {
|
const std::wstring &Id() {
|
||||||
static const std::wstring BaseId(cAlphaVersion()
|
static const auto BaseId = std::wstring(AppUserModelIdBase);
|
||||||
? AppUserModelIdAlpha
|
|
||||||
: AppUserModelIdRelease);
|
|
||||||
static auto CheckingInstalled = false;
|
static auto CheckingInstalled = false;
|
||||||
if (CheckingInstalled) {
|
if (CheckingInstalled) {
|
||||||
return BaseId;
|
return BaseId;
|
||||||
}
|
}
|
||||||
static const auto Installed = [] {
|
static const auto Installed = [] {
|
||||||
|
#ifdef OS_WIN_STORE
|
||||||
|
return true;
|
||||||
|
#else // OS_WIN_STORE
|
||||||
CheckingInstalled = true;
|
CheckingInstalled = true;
|
||||||
const auto guard = gsl::finally([] {
|
const auto guard = gsl::finally([] {
|
||||||
CheckingInstalled = false;
|
CheckingInstalled = false;
|
||||||
|
@ -453,6 +487,7 @@ const std::wstring &getId() {
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
});
|
});
|
||||||
return checkInstalled();
|
return checkInstalled();
|
||||||
|
#endif
|
||||||
}();
|
}();
|
||||||
if (Installed) {
|
if (Installed) {
|
||||||
return BaseId;
|
return BaseId;
|
||||||
|
@ -471,7 +506,7 @@ const std::wstring &getId() {
|
||||||
return PortableId;
|
return PortableId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROPERTYKEY &getKey() {
|
const PROPERTYKEY &Key() {
|
||||||
return pkey_AppUserModel_ID;
|
return pkey_AppUserModel_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace AppUserModelId {
|
namespace AppUserModelId {
|
||||||
|
|
||||||
void cleanupShortcut();
|
void CleanupShortcut();
|
||||||
void checkPinned();
|
void CheckPinned();
|
||||||
|
|
||||||
const std::wstring &getId();
|
[[nodiscard]] const std::wstring &Id();
|
||||||
bool validateShortcut();
|
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 AppUserModelId
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
Loading…
Reference in New Issue