Stop Telegram before Windows uninstallation

This commit is contained in:
John Preston
2026-07-20 22:48:15 +04:00
parent 5d96c8eedb
commit 62da586201
9 changed files with 83 additions and 5 deletions
+2
View File
@@ -555,6 +555,7 @@ void Launcher::processArguments() {
{ "-autostart" , KeyFormat::NoValues },
{ "-fixprevious" , KeyFormat::NoValues },
{ "-cleanup" , KeyFormat::NoValues },
{ "-uninstall" , KeyFormat::NoValues },
{ "-noupdate" , KeyFormat::NoValues },
{ "-tosettings" , KeyFormat::NoValues },
{ "-startintray" , KeyFormat::NoValues },
@@ -603,6 +604,7 @@ void Launcher::processArguments() {
gLaunchMode = parseResult.contains("-autostart") ? LaunchModeAutoStart
: parseResult.contains("-fixprevious") ? LaunchModeFixPrevious
: parseResult.contains("-cleanup") ? LaunchModeCleanup
: parseResult.contains("-uninstall") ? LaunchModeUninstall
: LaunchModeNormal;
gNoStartUpdate = parseResult.contains("-noupdate");
gStartToSettings = parseResult.contains("-tosettings");
+56 -4
View File
@@ -49,6 +49,9 @@ base::options::toggle OptionDeadlockDetector({
.description = "Check once every 30 seconds that main thread is still responsive.",
});
constexpr auto kUninstallIpcTimeout = 10 * crl::time(1000);
constexpr auto kUninstallQuitTimeout = 30 * crl::time(1000);
} // namespace
const char kOptionDeadlockDetector[] = "deadlock-detector";
@@ -65,10 +68,6 @@ Sandbox::Sandbox(int &argc, char **argv)
}
int Sandbox::start() {
if (!Core::UpdaterDisabled()) {
_updateChecker = std::make_unique<Core::UpdateChecker>();
}
{
const auto d = QFile::encodeName(QDir(cWorkingDir()).absolutePath());
char h[33] = { 0 };
@@ -76,6 +75,17 @@ int Sandbox::start() {
_localServerName = Platform::SingleInstanceLocalServerName(h);
}
if (cLaunchMode() == LaunchModeUninstall) {
const auto result = stopRunningInstance();
psCleanup();
closeApplication();
return result;
}
if (!Core::UpdaterDisabled()) {
_updateChecker = std::make_unique<Core::UpdateChecker>();
}
{
const auto d = QFile::encodeName(cExeDir() + cExeName());
QByteArray h;
@@ -171,6 +181,48 @@ int Sandbox::start() {
return exec();
}
int Sandbox::stopRunningInstance() {
LOG(("Uninstall: connecting to %1...").arg(_localServerName));
_localSocket.connectToServer(_localServerName);
if (!_localSocket.waitForConnected(int(kUninstallIpcTimeout))) {
if (_localSocket.error() == QLocalSocket::ServerNotFoundError) {
LOG(("Uninstall: no running instance found."));
return 0;
}
LOG(("Uninstall: connect error %1.").arg(_localSocket.error()));
return 1;
}
_localSocket.write("CMD:quit;");
if (!_localSocket.waitForBytesWritten(int(kUninstallIpcTimeout))) {
LOG(("Uninstall: could not send the quit command."));
return 1;
}
auto response = QByteArray();
const auto deadline = crl::now() + kUninstallIpcTimeout;
while (!response.contains(';')) {
const auto timeout = deadline - crl::now();
if (timeout <= 0 || !_localSocket.waitForReadyRead(int(timeout))) {
LOG(("Uninstall: no response to the quit command."));
return 1;
}
response.append(_localSocket.readAll());
}
const auto match = QRegularExpression(u"RES:(\\d+)_(\\d+);"_q).match(
QString::fromLatin1(response));
if (!match.hasMatch()) {
LOG(("Uninstall: bad response to the quit command."));
return 1;
}
const auto processId = match.capturedView(1).toULongLong();
LOG(("Uninstall: waiting for process %1 to quit...").arg(processId));
if (!Platform::WaitForProcessExit(processId, kUninstallQuitTimeout)) {
LOG(("Uninstall: the process did not quit in time."));
return 1;
}
LOG(("Uninstall: the running instance quit."));
return 0;
}
void Sandbox::NotifySystemShuttingDown() {
SystemShuttingDown = true;
}
+1
View File
@@ -103,6 +103,7 @@ private:
void socketWritten(qint64 bytes);
void socketReading();
void newInstanceConnected();
int stopRunningInstance();
void readClients();
void removeClients();
@@ -34,6 +34,10 @@ inline uint64 ActivationWindowId(not_null<QWidget*> window) {
inline void ActivateOtherProcess(uint64 processId, uint64 windowId) {
}
inline bool WaitForProcessExit(uint64 processId, crl::time timeout) {
return true;
}
} // namespace Platform
inline void psCheckLocalSocket(const QString &serverName) {
@@ -36,6 +36,10 @@ inline uint64 ActivationWindowId(not_null<QWidget*> window) {
inline void ActivateOtherProcess(uint64 processId, uint64 windowId) {
}
inline bool WaitForProcessExit(uint64 processId, crl::time timeout) {
return true;
}
inline QString ApplicationIconName() {
return {};
}
@@ -540,6 +540,18 @@ void ActivateOtherProcess(uint64 processId, uint64 windowId) {
}
}
bool WaitForProcessExit(uint64 processId, crl::time timeout) {
const auto process = ::OpenProcess(
SYNCHRONIZE,
FALSE,
DWORD(processId));
if (!process) {
return (::GetLastError() == ERROR_INVALID_PARAMETER);
}
const auto guard = gsl::finally([&] { ::CloseHandle(process); });
return (::WaitForSingleObject(process, DWORD(timeout)) == WAIT_OBJECT_0);
}
} // namespace Platform
namespace {
@@ -39,6 +39,8 @@ void SetWindowPriority(not_null<QWidget*> window, uint32 priority);
// Activate window with windowId (if found) or the largest priority.
void ActivateOtherProcess(uint64 processId, uint64 windowId);
[[nodiscard]] bool WaitForProcessExit(uint64 processId, crl::time timeout);
inline QString ApplicationIconName() {
return {};
}
+1
View File
@@ -44,6 +44,7 @@ enum LaunchMode {
LaunchModeAutoStart,
LaunchModeFixPrevious,
LaunchModeCleanup,
LaunchModeUninstall,
};
DeclareReadSetting(LaunchMode, LaunchMode);
DeclareSetting(QString, WorkingDir);
+1 -1
View File
@@ -113,7 +113,7 @@ var ResultCode: Integer;
begin
if CurUninstallStep = usUninstall then
begin
ShellExec('', ExpandConstant('{app}\{#MyAppExeName}'), '-cleanup', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
Exec(ExpandConstant('{app}\{#MyAppExeName}'), '-uninstall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
end;