2016-06-16 12:59:54 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2016-06-16 12:59:54 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2016-06-16 12:59:54 +00:00
|
|
|
*/
|
|
|
|
#include "platform/win/windows_app_user_model_id.h"
|
|
|
|
|
|
|
|
#include "platform/win/windows_dlls.h"
|
2021-10-05 18:37:34 +00:00
|
|
|
#include "platform/win/windows_toast_activator.h"
|
|
|
|
#include "base/platform/win/base_windows_wrl.h"
|
|
|
|
|
2016-06-16 12:59:54 +00:00
|
|
|
#include <propvarutil.h>
|
|
|
|
#include <propkey.h>
|
|
|
|
|
|
|
|
using namespace Microsoft::WRL;
|
|
|
|
|
|
|
|
namespace Platform {
|
|
|
|
namespace AppUserModelId {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
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 };
|
2021-10-05 18:37:34 +00:00
|
|
|
const PROPERTYKEY pkey_AppUserModel_ToastActivator = { { 0x9F4C2855, 0x9F79, 0x4B39, { 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 26 };
|
2016-06-16 12:59:54 +00:00
|
|
|
|
2017-02-01 10:12:52 +00:00
|
|
|
#ifdef OS_WIN_STORE
|
|
|
|
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop.Store";
|
|
|
|
#else // OS_WIN_STORE
|
2016-06-16 12:59:54 +00:00
|
|
|
const WCHAR AppUserModelIdRelease[] = L"Telegram.TelegramDesktop";
|
2017-02-01 10:12:52 +00:00
|
|
|
#endif // OS_WIN_STORE
|
2018-09-26 14:58:09 +00:00
|
|
|
const WCHAR AppUserModelIdAlpha[] = L"Telegram.TelegramDesktop.Alpha";
|
2016-06-16 12:59:54 +00:00
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
QString pinnedPath() {
|
|
|
|
static const int maxFileLen = MAX_PATH * 10;
|
|
|
|
WCHAR wstrPath[maxFileLen];
|
|
|
|
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
|
2021-10-05 18:37:34 +00:00
|
|
|
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
|
|
|
return appData.absolutePath()
|
|
|
|
+ u"/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar/"_q;
|
2016-06-16 12:59:54 +00:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkPinned() {
|
|
|
|
static const int maxFileLen = MAX_PATH * 10;
|
|
|
|
|
|
|
|
HRESULT hr = CoInitialize(0);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
QString path = pinnedPath();
|
|
|
|
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
|
|
|
|
|
|
|
WCHAR src[MAX_PATH];
|
|
|
|
GetModuleFileName(GetModuleHandle(0), src, MAX_PATH);
|
|
|
|
BY_HANDLE_FILE_INFORMATION srcinfo = { 0 };
|
2021-10-05 18:37:34 +00:00
|
|
|
HANDLE srcfile = CreateFile(
|
|
|
|
src,
|
|
|
|
0x00,
|
|
|
|
0x00,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (srcfile == INVALID_HANDLE_VALUE) return;
|
|
|
|
BOOL srcres = GetFileInformationByHandle(srcfile, &srcinfo);
|
|
|
|
CloseHandle(srcfile);
|
|
|
|
if (!srcres) return;
|
|
|
|
LOG(("Checking..."));
|
|
|
|
WIN32_FIND_DATA findData;
|
2021-10-05 18:37:34 +00:00
|
|
|
HANDLE findHandle = FindFirstFileEx(
|
|
|
|
(p + L"*").c_str(),
|
|
|
|
FindExInfoStandard,
|
|
|
|
&findData,
|
|
|
|
FindExSearchNameMatch,
|
|
|
|
0,
|
|
|
|
0);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (findHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
LOG(("Init Error: could not find files in pinned folder"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
std::wstring fname = p + 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
|
|
|
|
|
|
|
|
ComPtr<IShellLink> shellLink;
|
2021-10-05 18:37:34 +00:00
|
|
|
HRESULT hr = CoCreateInstance(
|
|
|
|
CLSID_ShellLink,
|
|
|
|
nullptr,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
IID_PPV_ARGS(&shellLink));
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) continue;
|
|
|
|
|
|
|
|
ComPtr<IPersistFile> persistFile;
|
|
|
|
hr = shellLink.As(&persistFile);
|
|
|
|
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 };
|
2021-10-05 18:37:34 +00:00
|
|
|
HANDLE dstfile = CreateFile(
|
|
|
|
dst,
|
|
|
|
0x00,
|
|
|
|
0x00,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (dstfile == INVALID_HANDLE_VALUE) continue;
|
|
|
|
BOOL dstres = GetFileInformationByHandle(dstfile, &dstinfo);
|
|
|
|
CloseHandle(dstfile);
|
|
|
|
if (!dstres) continue;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
if (srcinfo.dwVolumeSerialNumber == dstinfo.dwVolumeSerialNumber
|
|
|
|
&& srcinfo.nFileIndexLow == dstinfo.nFileIndexLow
|
|
|
|
&& srcinfo.nFileIndexHigh == dstinfo.nFileIndexHigh) {
|
2016-06-16 12:59:54 +00:00
|
|
|
ComPtr<IPropertyStore> propertyStore;
|
|
|
|
hr = shellLink.As(&propertyStore);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
PROPVARIANT appIdPropVar;
|
|
|
|
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
LOG(("Reading..."));
|
|
|
|
WCHAR already[MAX_PATH];
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
if (std::wstring(getId()) == already) {
|
|
|
|
LOG(("Already!"));
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (appIdPropVar.vt != VT_EMPTY) {
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
|
|
|
|
hr = InitPropVariantFromString(getId(), &appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
hr = propertyStore->Commit();
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
if (persistFile->IsDirty() == S_OK) {
|
|
|
|
persistFile->Save(fname.c_str(), TRUE);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (FindNextFile(findHandle, &findData));
|
|
|
|
DWORD errorCode = GetLastError();
|
2021-10-05 18:37:34 +00:00
|
|
|
if (errorCode && errorCode != ERROR_NO_MORE_FILES) {
|
2016-06-16 12:59:54 +00:00
|
|
|
LOG(("Init Error: could not find some files in pinned folder"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
FindClose(findHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString systemShortcutPath() {
|
|
|
|
static const int maxFileLen = MAX_PATH * 10;
|
|
|
|
WCHAR wstrPath[maxFileLen];
|
|
|
|
if (GetEnvironmentVariable(L"APPDATA", wstrPath, maxFileLen)) {
|
2021-10-05 18:37:34 +00:00
|
|
|
auto appData = QDir(QString::fromStdWString(std::wstring(wstrPath)));
|
|
|
|
const auto path = appData.absolutePath();
|
|
|
|
return path + u"/Microsoft/Windows/Start Menu/Programs/"_q;
|
2016-06-16 12:59:54 +00:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void cleanupShortcut() {
|
|
|
|
static const int maxFileLen = MAX_PATH * 10;
|
|
|
|
|
|
|
|
QString path = systemShortcutPath() + qsl("Telegram.lnk");
|
|
|
|
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
|
|
|
|
|
|
|
DWORD attributes = GetFileAttributes(p.c_str());
|
|
|
|
if (attributes >= 0xFFFFFFF) return; // file does not exist
|
|
|
|
|
|
|
|
ComPtr<IShellLink> shellLink;
|
2021-10-05 18:37:34 +00:00
|
|
|
HRESULT hr = CoCreateInstance(
|
|
|
|
CLSID_ShellLink,
|
|
|
|
nullptr,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
IID_PPV_ARGS(&shellLink));
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
ComPtr<IPersistFile> persistFile;
|
|
|
|
hr = shellLink.As(&persistFile);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
hr = persistFile->Load(p.c_str(), STGM_READWRITE);
|
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
|
|
|
WCHAR szGotPath[MAX_PATH];
|
|
|
|
WIN32_FIND_DATA wfd;
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = shellLink->GetPath(
|
|
|
|
szGotPath,
|
|
|
|
MAX_PATH,
|
|
|
|
(WIN32_FIND_DATA*)&wfd,
|
|
|
|
SLGP_SHORTPATH);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
const auto full = cExeDir() + cExeName();
|
|
|
|
if (QDir::toNativeSeparators(full).toStdWString() == szGotPath) {
|
2016-06-16 12:59:54 +00:00
|
|
|
QFile().remove(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool validateShortcutAt(const QString &path) {
|
|
|
|
static const int maxFileLen = MAX_PATH * 10;
|
|
|
|
|
|
|
|
std::wstring p = QDir::toNativeSeparators(path).toStdWString();
|
|
|
|
|
|
|
|
DWORD attributes = GetFileAttributes(p.c_str());
|
|
|
|
if (attributes >= 0xFFFFFFF) return false; // file does not exist
|
|
|
|
|
|
|
|
ComPtr<IShellLink> shellLink;
|
2021-10-05 18:37:34 +00:00
|
|
|
HRESULT hr = CoCreateInstance(
|
|
|
|
CLSID_ShellLink,
|
|
|
|
nullptr,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
IID_PPV_ARGS(&shellLink));
|
2016-06-16 12:59:54 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
ComPtr<IPropertyStore> propertyStore;
|
|
|
|
hr = shellLink.As(&propertyStore);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
PROPVARIANT appIdPropVar;
|
2021-10-05 18:37:34 +00:00
|
|
|
PROPVARIANT toastActivatorPropVar;
|
2016-06-16 12:59:54 +00:00
|
|
|
hr = propertyStore->GetValue(getKey(), &appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = propertyStore->GetValue(
|
|
|
|
pkey_AppUserModel_ToastActivator,
|
|
|
|
&toastActivatorPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2016-06-16 12:59:54 +00:00
|
|
|
WCHAR already[MAX_PATH];
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = PropVariantToString(appIdPropVar, already, MAX_PATH);
|
|
|
|
const auto good1 = SUCCEEDED(hr) && (std::wstring(getId()) == already);
|
|
|
|
const auto bad1 = !good1 && (appIdPropVar.vt != VT_EMPTY);
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
|
|
|
|
auto clsid = CLSID();
|
|
|
|
hr = PropVariantToCLSID(toastActivatorPropVar, &clsid);
|
|
|
|
const auto good2 = SUCCEEDED(hr) && (clsid == __uuidof(ToastActivator));
|
|
|
|
const auto bad2 = !good2 && (toastActivatorPropVar.vt != VT_EMPTY);
|
|
|
|
PropVariantClear(&toastActivatorPropVar);
|
|
|
|
if (good1 && good2) {
|
2021-10-06 13:36:30 +00:00
|
|
|
LOG(("App Info: Shortcut validated at \"%1\"").arg(path));
|
2021-10-05 18:37:34 +00:00
|
|
|
return true;
|
|
|
|
} else if (bad1 || bad2) {
|
2016-06-16 12:59:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = InitPropVariantFromString(getId(), &appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = InitPropVariantFromCLSID(
|
|
|
|
__uuidof(ToastActivator),
|
|
|
|
&toastActivatorPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
hr = propertyStore->SetValue(
|
|
|
|
pkey_AppUserModel_ToastActivator,
|
|
|
|
toastActivatorPropVar);
|
|
|
|
PropVariantClear(&toastActivatorPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2016-06-16 12:59:54 +00:00
|
|
|
hr = propertyStore->Commit();
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
if (persistFile->IsDirty() == S_OK) {
|
2021-10-06 13:36:30 +00:00
|
|
|
hr = persistFile->Save(p.c_str(), TRUE);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
2016-06-16 12:59:54 +00:00
|
|
|
}
|
|
|
|
|
2021-10-06 13:36:30 +00:00
|
|
|
LOG(("App Info: Shortcut set and validated at \"%1\"").arg(path));
|
2016-06-16 12:59:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool validateShortcut() {
|
|
|
|
QString path = systemShortcutPath();
|
2021-10-05 18:37:34 +00:00
|
|
|
if (path.isEmpty() || cExeName().isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-16 12:59:54 +00:00
|
|
|
|
2018-09-26 14:58:09 +00:00
|
|
|
if (cAlphaVersion()) {
|
2021-10-05 18:37:34 +00:00
|
|
|
path += u"TelegramAlpha.lnk"_q;
|
|
|
|
if (validateShortcutAt(path)) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-06-16 12:59:54 +00:00
|
|
|
} else {
|
2021-10-05 18:37:34 +00:00
|
|
|
const auto installed = u"Telegram Desktop/Telegram.lnk"_q;
|
|
|
|
const auto old = u"Telegram Win (Unofficial)/Telegram.lnk"_q;
|
|
|
|
if (validateShortcutAt(path + installed)
|
|
|
|
|| validateShortcutAt(path + old)) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-06-16 12:59:54 +00:00
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
path += u"Telegram.lnk"_q;
|
|
|
|
if (validateShortcutAt(path)) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-06-16 12:59:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ComPtr<IShellLink> shellLink;
|
2021-10-05 18:37:34 +00:00
|
|
|
HRESULT hr = CoCreateInstance(
|
|
|
|
CLSID_ShellLink,
|
|
|
|
nullptr,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
IID_PPV_ARGS(&shellLink));
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = shellLink->SetPath(
|
|
|
|
QDir::toNativeSeparators(
|
|
|
|
cExeDir() + cExeName()).toStdWString().c_str());
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
hr = shellLink->SetArguments(L"");
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = shellLink->SetWorkingDirectory(
|
|
|
|
QDir::toNativeSeparators(
|
|
|
|
QDir(cWorkingDir()).absolutePath()).toStdWString().c_str());
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
ComPtr<IPropertyStore> propertyStore;
|
|
|
|
hr = shellLink.As(&propertyStore);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
PROPVARIANT appIdPropVar;
|
|
|
|
hr = InitPropVariantFromString(getId(), &appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
hr = propertyStore->SetValue(getKey(), appIdPropVar);
|
|
|
|
PropVariantClear(&appIdPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
PROPVARIANT startPinPropVar;
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = InitPropVariantFromUInt32(
|
|
|
|
APPUSERMODEL_STARTPINOPTION_NOPINONINSTALL,
|
|
|
|
&startPinPropVar);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = propertyStore->SetValue(
|
|
|
|
pkey_AppUserModel_StartPinOption,
|
|
|
|
startPinPropVar);
|
2016-06-16 12:59:54 +00:00
|
|
|
PropVariantClear(&startPinPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
2021-10-05 18:37:34 +00:00
|
|
|
|
|
|
|
PROPVARIANT toastActivatorPropVar{};
|
|
|
|
hr = InitPropVariantFromCLSID(
|
|
|
|
__uuidof(ToastActivator),
|
|
|
|
&toastActivatorPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
hr = propertyStore->SetValue(
|
|
|
|
pkey_AppUserModel_ToastActivator,
|
|
|
|
toastActivatorPropVar);
|
|
|
|
PropVariantClear(&toastActivatorPropVar);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
2016-06-16 12:59:54 +00:00
|
|
|
|
|
|
|
hr = propertyStore->Commit();
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
|
|
|
ComPtr<IPersistFile> persistFile;
|
|
|
|
hr = shellLink.As(&persistFile);
|
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-05 18:37:34 +00:00
|
|
|
hr = persistFile->Save(
|
|
|
|
QDir::toNativeSeparators(path).toStdWString().c_str(),
|
|
|
|
TRUE);
|
2016-06-16 12:59:54 +00:00
|
|
|
if (!SUCCEEDED(hr)) return false;
|
|
|
|
|
2021-10-06 13:36:30 +00:00
|
|
|
LOG(("App Info: Shortcut created and validated at \"%1\"").arg(path));
|
2016-06-16 12:59:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const WCHAR *getId() {
|
2018-09-26 14:58:09 +00:00
|
|
|
return cAlphaVersion() ? AppUserModelIdAlpha : AppUserModelIdRelease;
|
2016-06-16 12:59:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const PROPERTYKEY &getKey() {
|
|
|
|
return pkey_AppUserModel_ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace AppUserModelId
|
|
|
|
} // namespace Platform
|