made Updater work in windows for UAC-protected locations of Telegram.exe

This commit is contained in:
John Preston 2014-12-02 19:25:17 +03:00
parent 7a600e03d0
commit 03c8de6195
7 changed files with 93 additions and 17 deletions

View File

@ -19,7 +19,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
bool _debug = false;
wstring exeName, exeDir;
wstring exeName, exeDir, updateTo;
bool equal(const wstring &a, const wstring &b) {
return !_wcsicmp(a.c_str(), b.c_str());
@ -133,7 +133,7 @@ bool update() {
wstring dir = dirs.front();
dirs.pop_front();
wstring toDir = exeDir;
wstring toDir = updateTo;
if (dir.size() > updDir.size() + 1) {
toDir += (dir.substr(updDir.size() + 1) + L"\\");
forcedirs.push_back(toDir);
@ -161,7 +161,7 @@ bool update() {
}
} else {
wstring fname = dir + L"\\" + findData.cFileName;
wstring tofname = exeDir + fname.substr(updDir.size() + 1);
wstring tofname = updateTo + fname.substr(updDir.size() + 1);
if (equal(tofname, exeName)) { // bad update - has Updater.exe - delete all dir
writeLog(L"Error: bad update, has Updater.exe! '" + tofname + L"' equal '" + exeName + L"'");
delFolder();
@ -230,10 +230,9 @@ bool update() {
}
void updateRegistry() {
writeLog(L"Updating registry..");
HANDLE versionFile = CreateFile(L"tdata\\version", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
HANDLE versionFile = CreateFile((updateTo + L"tdata\\version").c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (versionFile != INVALID_HANDLE_VALUE) {
writeLog(L"Updating registry..");
DWORD versionNum = 0, versionLen = 0, readLen = 0;
WCHAR versionStr[32];
if (ReadFile(versionFile, &versionNum, sizeof(DWORD), &readLen, NULL) != TRUE || readLen != sizeof(DWORD)) {
@ -284,7 +283,7 @@ void updateRegistry() {
wsprintf(dateStr, L"%04d%02d%02d", stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay);
RegSetValueEx(rkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (wcslen(dateStr) + 1) * sizeof(WCHAR));
WCHAR *appURL = L"https://tdesktop.com";
WCHAR *appURL = L"https://desktop.telegram.org";
RegSetValueEx(rkey, L"HelpLink", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLInfoAbout", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
RegSetValueEx(rkey, L"URLUpdateInfo", 0, REG_SZ, (BYTE*)appURL, (wcslen(appURL) + 1) * sizeof(WCHAR));
@ -296,6 +295,8 @@ void updateRegistry() {
RegCloseKey(rkey);
}
}
} else {
writeLog(L"Could not open version file to update registry :(");
}
}
@ -313,7 +314,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParama
LPWSTR *args;
int argsCount;
bool needupdate = false, autostart = false, debug = false;
bool needupdate = false, autostart = false, debug = false, writeprotected = false;
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
if (args) {
for (int i = 1; i < argsCount; ++i) {
@ -324,10 +325,19 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParama
} else if (equal(args[i], L"-debug")) {
debug = _debug = true;
openLog();
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
writeprotected = true;
updateTo = args[i];
for (int i = 0, l = updateTo.size(); i < l; ++i) {
if (updateTo[i] == L'/') {
updateTo[i] = L'\\';
}
}
}
}
if (needupdate) writeLog(L"Need to update!");
if (autostart) writeLog(L"From autostart!");
if (writeprotected) writeLog(L"Write Protected folder!");
exeName = args[0];
writeLog(L"Exe name is: " + exeName);
@ -335,9 +345,20 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParama
if (equal(exeName.substr(exeName.size() - 11), L"Updater.exe")) {
exeDir = exeName.substr(0, exeName.size() - 11);
writeLog(L"Exe dir is: " + exeDir);
if (!writeprotected) {
updateTo = exeDir;
}
writeLog(L"Update to: " + updateTo);
if (needupdate && update()) {
updateRegistry();
}
if (writeprotected) { // if we can't clear all tupdates\ready (Updater.exe is there) - clear only version
if (DeleteFile(L"tupdates\\ready\\tdata\\version")) {
writeLog(L"Version file deleted!");
} else {
writeLog(L"Error: could not delete version file");
}
}
} else {
writeLog(L"Error: bad exe name!");
}
@ -349,11 +370,56 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParama
writeLog(L"Error: No command line arguments!");
}
wstring targs = L"-noupdate";
wstring targs;
if (autostart) targs += L" -autostart";
if (debug) targs += L" -debug";
ShellExecute(0, 0, (exeDir + L"Telegram.exe").c_str(), targs.c_str(), 0, SW_SHOWNORMAL);
bool executed = false;
if (writeprotected) { // run un-elevated
writeLog(L"Trying to run un-elevated by temp.lnk");
HRESULT hres = CoInitialize(0);
if (SUCCEEDED(hres)) {
wstring lnk = L"tupdates\\ready\\temp.lnk";
IShellLink* psl;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
wstring exe = updateTo + L"Telegram.exe", dir = updateTo;
psl->SetArguments((targs.size() ? targs.substr(1) : targs).c_str());
psl->SetPath(exe.c_str());
psl->SetWorkingDirectory(dir.c_str());
psl->SetDescription(L"");
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres)) {
hres = ppf->Save(lnk.c_str(), TRUE);
ppf->Release();
if (SUCCEEDED(hres)) {
writeLog(L"Executing un-elevated through link..");
ShellExecute(0, 0, L"explorer.exe", lnk.c_str(), 0, SW_SHOWNORMAL);
executed = true;
} else {
writeLog(L"Error: ppf->Save failed");
}
} else {
writeLog(L"Error: Could not create interface IID_IPersistFile");
}
psl->Release();
} else {
writeLog(L"Error: could not create instance of IID_IShellLink");
}
CoUninitialize();
} else {
writeLog(L"Error: Could not initialize COM");
}
}
if (!executed) {
ShellExecute(0, 0, (updateTo + L"Telegram.exe").c_str(), (L"-noupdate" + targs).c_str(), 0, SW_SHOWNORMAL);
}
writeLog(L"Executed Telegram.exe, closing log and quiting..");
closeLog();

View File

@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
AboutBox::AboutBox() :
_done(this, lang(lng_about_done), st::aboutCloseButton),
_version(this, qsl("[a href=\"https://tdesktop.com/#version_history\"]") + textClean(lang(lng_about_version).replace(qsl("{version}"), QString::fromWCharArray(AppVersionStr))) + qsl("[/a]"), st::aboutVersion, st::defaultTextStyle),
_version(this, qsl("[a href=\"https://desktop.telegram.org/#changelog\"]") + textClean(lang(lng_about_version).replace(qsl("{version}"), QString::fromWCharArray(AppVersionStr))) + qsl("[/a]"), st::aboutVersion, st::defaultTextStyle),
_text(this, lang(lng_about_text), st::aboutLabel, st::aboutTextStyle),
_hiding(false), a_opacity(0, 1) {

View File

@ -23,7 +23,7 @@ static const wchar_t *AppVersionStr = L"0.6.15";
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";
static const wchar_t *AppId = L"{53F49750-6209-4FBF-9CA8-7A333C87D1ED}";
static const wchar_t *AppId = L"{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"; // used in updater.cpp and Setup.iss for Windows
static const wchar_t *AppFile = L"Telegram";
#include "settings.h"

View File

@ -2105,8 +2105,14 @@ bool psCheckReadyUpdate() {
}
}
if (CopyFile(updater.absoluteFilePath().toStdWString().c_str(), curUpdater.toStdWString().c_str(), FALSE) == FALSE) {
PsUpdateDownloader::clearAll();
return false;
DWORD errorCode = GetLastError();
if (errorCode == ERROR_ACCESS_DENIED) { // we are in write-protected dir, like Program Files
cSetWriteProtected(true);
return true;
} else {
PsUpdateDownloader::clearAll();
return false;
}
}
if (DeleteFile(updater.absoluteFilePath().toStdWString().c_str()) == FALSE) {
PsUpdateDownloader::clearAll();
@ -2166,11 +2172,14 @@ void psExecUpdater() {
QString targs = qsl("-update");
if (cFromAutoStart()) targs += qsl(" -autostart");
if (cDebug()) targs += qsl(" -debug");
if (cWriteProtected()) targs += qsl(" -writeprotected \"") + cExeDir() + '"';
QString updater(QDir::toNativeSeparators(cExeDir() + "Updater.exe")), wdir(QDir::toNativeSeparators(cWorkingDir()));
QString updaterPath = cWriteProtected() ? (cWorkingDir() + qsl("tupdates/ready/Updater.exe")) : (cExeDir() + qsl("Updater.exe"));
QString updater(QDir::toNativeSeparators(updaterPath)), wdir(QDir::toNativeSeparators(cWorkingDir()));
DEBUG_LOG(("Application Info: executing %1 %2").arg(cExeDir() + "Updater.exe").arg(targs));
HINSTANCE r = ShellExecute(0, 0, updater.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL);
HINSTANCE r = ShellExecute(0, cWriteProtected() ? L"runas" : 0, updater.toStdWString().c_str(), targs.toStdWString().c_str(), wdir.isEmpty() ? 0 : wdir.toStdWString().c_str(), SW_SHOWNORMAL);
if (long(r) < 32) {
DEBUG_LOG(("Application Error: failed to execute %1, working directory: '%2', result: %3").arg(updater).arg(wdir).arg(long(r)));
QString readyPath = cWorkingDir() + qsl("tupdates/ready");

View File

@ -42,7 +42,7 @@ DBIWorkMode gWorkMode = dbiwmWindowAndTray;
DBIConnectionType gConnectionType = dbictAuto;
ConnectionProxy gConnectionProxy;
bool gSeenTrayTooltip = false;
bool gRestartingUpdate = false, gRestarting = false;
bool gRestartingUpdate = false, gRestarting = false, gWriteProtected = false;
int32 gLastUpdateCheck = 0;
bool gNoStartUpdate = false;
bool gStartToSettings = false;

View File

@ -91,6 +91,7 @@ DeclareSetting(ConnectionProxy, ConnectionProxy);
DeclareSetting(bool, SeenTrayTooltip);
DeclareSetting(bool, RestartingUpdate);
DeclareSetting(bool, Restarting);
DeclareSetting(bool, WriteProtected);
DeclareSetting(int32, LastUpdateCheck);
DeclareSetting(bool, NoStartUpdate);
DeclareSetting(bool, StartToSettings);

Binary file not shown.