From 03c8de619575731e5088821030e7b63790003aaa Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 2 Dec 2014 19:25:17 +0300 Subject: [PATCH] made Updater work in windows for UAC-protected locations of Telegram.exe --- Telegram/SourceFiles/_other/updater.cpp | 86 +++++++++++++++++++++--- Telegram/SourceFiles/boxes/aboutbox.cpp | 2 +- Telegram/SourceFiles/config.h | 2 +- Telegram/SourceFiles/pspecific_wnd.cpp | 17 +++-- Telegram/SourceFiles/settings.cpp | 2 +- Telegram/SourceFiles/settings.h | 1 + Telegram/Updater.rc | Bin 4370 -> 4370 bytes 7 files changed, 93 insertions(+), 17 deletions(-) diff --git a/Telegram/SourceFiles/_other/updater.cpp b/Telegram/SourceFiles/_other/updater.cpp index 30c461450..1289d20a3 100644 --- a/Telegram/SourceFiles/_other/updater.cpp +++ b/Telegram/SourceFiles/_other/updater.cpp @@ -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(); diff --git a/Telegram/SourceFiles/boxes/aboutbox.cpp b/Telegram/SourceFiles/boxes/aboutbox.cpp index 402d85d9b..9f955330b 100644 --- a/Telegram/SourceFiles/boxes/aboutbox.cpp +++ b/Telegram/SourceFiles/boxes/aboutbox.cpp @@ -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) { diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 0f53de8d3..8797cfc91 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -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" diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 63a225427..8a9ae53f2 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -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"); diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index b121bbb35..d7f4dcb91 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -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; diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h index 140e15cd6..9b6f287a0 100644 --- a/Telegram/SourceFiles/settings.h +++ b/Telegram/SourceFiles/settings.h @@ -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); diff --git a/Telegram/Updater.rc b/Telegram/Updater.rc index 9dc4f2064450eccdc683401298ea91c6c96be787..0dc8c281514209a76ea6b1d1184990208dd7c037 100644 GIT binary patch delta 50 zcmbQFG)ZYg9S5V?*yb19Y>YtJ_dLoh E0G$~R)&Kwi delta 62 zcmbQFG)ZYg9S5WF Q*yb19Y>Ysa?|GD205^0I`2YX_