mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 cover (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Desktop / Prune caches (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [Installer] End a launcher that has no window to ask instead of prompting The in-app updater starts this installer detached and then closes itself. A client that accepts that close hides its window before it exits, and if it then hangs in shutdown there is nothing left to ask: the holder probe deliberately never posts WM_CLOSE to an instance it cannot see a window for, so the "ask it to close again" answer only repeated itself until the user picked Cancel and the installation aborted (Sentry COCKATRICE-DESKTOP-J). The launcher wait now asks the launcher itself before asking the user. A new probe mode, --close-launcher, answers whether that one process has a window a close could reach at all; it is limited to a pid that still runs from the directory being replaced, so a reused process id cannot be hit. When there is no window, the installer gives the shutdown it already started one full grace and then ends it through the handle it waited on, which is what the dialog's Yes answer did. The prompt remains for the case it exists for: a window is up, the instance may be waiting on its own question, and No now means only "keep waiting". The client is left alone: an already-installed version runs the installer during its own update, so a change there cannot reach the run that aborts. * [libcockatrice_rng] Include immintrin.h for AVX2 builds in SFMT --------- Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
103 lines
5.1 KiB
C++
103 lines
5.1 KiB
C++
#ifndef CLOSE_HOLDERS_H
|
|
#define CLOSE_HOLDERS_H
|
|
|
|
#include "holder_line.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
/**
|
|
* @brief What asking the holders to close did, in the form the installer logs.
|
|
*
|
|
* @c report is one line naming every holder, including the ones this deliberately
|
|
* leaves alone, because the installer repeats it in its log and in the second prompt.
|
|
* @c withoutWindow counts the holders that had no visible window a user could answer: they
|
|
* were named and left alone, and the launcher mode reads that count as "nothing to ask"
|
|
* rather than as a window the user still has to answer.
|
|
*/
|
|
struct CloseHoldersResult
|
|
{
|
|
unsigned int askedToClose = 0; ///< holders a WM_CLOSE was posted to
|
|
unsigned int withoutWindow = 0; ///< holders with no visible window a user could answer
|
|
std::wstring report; ///< one line, narrowed to ASCII when written
|
|
};
|
|
|
|
/**
|
|
* @brief Whether @p imageName is the client the update belongs to, matched without case.
|
|
*
|
|
* The close mode asks only this image to close, and the launcher mode is only allowed to
|
|
* report it as safe to end, so both read the answer from here.
|
|
*
|
|
* @param imageName the file name of a process image, empty when it could not be read
|
|
*/
|
|
bool isCockatriceImage(const std::wstring &imageName);
|
|
|
|
/**
|
|
* @brief Brings every running Cockatrice holding an installer file forward and asks it
|
|
* to close.
|
|
*
|
|
* The set is the Restart Manager answer, so it is exactly the processes holding a file of
|
|
* the previous version: nothing here has to guess at an executable path, and an
|
|
* application that merely shares the image name is never touched. Only cockatrice.exe is
|
|
* asked to close. Oracle and Servatrice are left to the user - Oracle writes the card
|
|
* database in place - and so is every service.
|
|
*
|
|
* One thing happens per instance: its main window is brought to the foreground, because
|
|
* Cockatrice may answer the close with a confirmation of its own that would otherwise open
|
|
* behind the installer's prompt. Then WM_CLOSE is posted to the main window, the same
|
|
* request as clicking its close button - unless the instance is asking a question of its
|
|
* own, which disables that window: posting the close then only hides the question, so it is
|
|
* brought forward and left to the user. An instance with no window a user could answer -
|
|
* one hidden in the notification area, say - is named and left to the user as well; showing
|
|
* its windows from here does not help, because the application would still believe they are
|
|
* hidden and never paint them. Stopping the process is never attempted.
|
|
*
|
|
* Once the requests are out, this waits up to @c waitMilliseconds for the processes to
|
|
* exit, so the caller can measure the purge immediately afterwards instead of sleeping
|
|
* for a fixed time or re-asking a question this call already answered. A process that is
|
|
* still running is described further: whether its window is gone, still open, hidden
|
|
* again, and whether it answers at all, so the log can tell an instance that refused the
|
|
* close from one that never received it.
|
|
*
|
|
* @param holders the Restart Manager answer, one entry per application or service
|
|
* @param waitMilliseconds how long to wait for the asked instances to exit, 0 to not wait
|
|
*/
|
|
CloseHoldersResult closeCockatriceHolders(const std::vector<Holder> &holders, unsigned long waitMilliseconds);
|
|
|
|
/**
|
|
* @brief What ending the holders did, in the form the installer logs.
|
|
*
|
|
* @c report is one line naming every holder, including the ones this deliberately leaves
|
|
* alone, because the installer repeats it in its log.
|
|
*/
|
|
struct EndHoldersResult
|
|
{
|
|
unsigned int ended = 0; ///< holders TerminateProcess was accepted for
|
|
std::wstring report; ///< one line, narrowed to ASCII when written
|
|
};
|
|
|
|
/**
|
|
* @brief Ends every running Cockatrice, Oracle and Servatrice the probe named.
|
|
*
|
|
* This is the last resort behind the installer's "end it now" answer, never a first move: a
|
|
* client that is still running may have an unsaved deck, an open game or a settings write in
|
|
* flight, Oracle may be part-way through writing the card database, and Servatrice may be
|
|
* serving a game, so the caller only gets here after the user picked it from a prompt that
|
|
* says so.
|
|
*
|
|
* Every program the payload installs is ended, services included. A service is terminated
|
|
* like a process rather than stopped through the Service Control Manager: the installer has
|
|
* asked the user first, and the SCM notices the process exit and marks the service stopped
|
|
* afterwards, so it can be started again normally. Anything else the Restart Manager named -
|
|
* a scanner holding a DLL, a program the user keeps in the install directory - is left to
|
|
* the user, because ending it would destroy something this installer does not own.
|
|
*
|
|
* Waits up to @c waitMilliseconds for what it ended to be gone, so the caller can measure the
|
|
* purge immediately afterwards instead of racing a process that is still exiting.
|
|
*
|
|
* @param holders what the probe named, one entry per application or service
|
|
* @param waitMilliseconds how long to wait for the ended instances to be gone, 0 to not wait
|
|
*/
|
|
EndHoldersResult endHolders(const std::vector<Holder> &holders, unsigned long waitMilliseconds);
|
|
|
|
#endif
|