mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
* [Installer] Abort instead of installing over leftover runtime files
The silent upgrade could leave a mix of old and new Qt DLLs next to the new
executables, which is what makes the next start fail with "The procedure entry
point X could not be located in the dynamic link library ...Qt6QuickWidgets.dll"
or "The code execution cannot proceed because Qt6Multimedia.dll was not found".
The check that was supposed to catch this probed only Qt6Core.dll and
Qt6Network.dll, so it was blind to the two files the reports name. It also only
warned and then installed anyway, so a caught problem was still compounded.
- Scan every file the purge targets with FindFirst, which takes the same
wildcards the Delete/RMDir calls use, instead of two hardcoded names
- Widen IsExistingCockatriceInstall from Qt6Core.dll to Qt6*.dll so a directory
left holding only some Qt modules is still recognised as an install
- Gate the scan on that, so a first-time install into a directory that happens to
hold unrelated Qt5 DLLs is not turned into an abort
- Abort with a non-zero exit code instead of warning, so the new payload is
never written next to files of the previous version
- Skip the message box on an unattended /S install, which would block on it
forever, matching the two existing abort sites
* [Installer] Cancel a silent upgrade when the running-instance guard fails
The running instance guard is what stands between a locked install directory
and the mixed Qt DLL set that breaks the next start, but it failed open in two
places and let the install carry on anyway:
- powershell.exe could not be started: the check warned and returned
- the process lookup answered "could not determine": WaitForAppToClose returned
on $R0 != 1, so "unknown" was treated exactly like "not running"
On a silent upgrade there is nobody at the keyboard to close the applications in
response to that warning, which is precisely the state in which the launcher was
still holding its Qt DLLs mapped.
- Treat "could not determine" as its own state rather than folding it into "not
running", in all three places WaitForAppToClose inspects the result
- Cancel a silent upgrade in both cases; keep an interactive install on the
existing warn-and-continue path, since refusing there would leave an installer
that can never complete and the stale-runtime check still applies
- Route every abort through one AbortInstall so the dialog-vs-silent decision
lives in a single place, and stop the two pre-existing warning dialogs that a
/S install without /R would have blocked on forever
* [Installer] Wait on the process that launched the update installer
The in-app updater starts the installer and only then quits itself, so the
installer has to decide whether the launching process is still alive while it is
running. It did that by polling powershell.exe for an image name under the
install directory, which is a proxy for the real question - is the process that
started me still holding its Qt DLLs mapped - and a proxy that can answer "not
running" or "could not determine" while the process is very much alive. Either
answer let the install carry on into the mixed Qt DLL set.
Take /PID= from the command line and wait on that process handle directly:
- OpenProcess with PROCESS_SYNCHRONIZE only, which is all that is needed to wait
and the least likely to be refused for an unrelated reason
- WaitForSingleObject for the same 60 s the name based check allows, so a client
slow to flush its card database is not squeezed
- Treat an unopenable handle as "already exited", which is what it means for a
dead process
- Cancel the upgrade if the launcher has not exited, rather than replacing files
it is still using
Run it before EnsureAppsNotRunning, not after: it needs no powershell.exe, so it
is the one check that still works on a machine where the process lookup cannot
run, and it is what lets that case keep upgrading instead of being cancelled by
what was only ever a proxy for it. Keep an older client, which passes no /PID=,
on the existing path.
An older installer ignores /PID=, and /D= stays the last parameter either way.
* [Client] Pass our process id to the update installer
The updater starts the installer and only then quits itself, so the installer
begins replacing files while this process still has every Qt runtime DLL mapped,
and a mapped DLL cannot be deleted. It has to work out that it must wait, and
until now all it had was its own image name to go on.
Pass /PID= so it can wait on this process directly instead of guessing, and
cancel the update rather than replace files this process is still using. /D=
stays the last parameter, which NSIS requires.
* [CI] Fail the build when the installer is missing a Qt runtime DLL
The Windows payload is assembled by globbing every *.dll out of the build output
directories, so nothing but luck decides whether a module the client links
statically - Qt6Multimedia.dll, Qt6QuickWidgets.dll - reaches the installer at
all. A module that is left out is invisible until a user installs an update and
the client then refuses to start, with "The code execution cannot proceed because
Qt6Multimedia.dll was not found" or a missing procedure entry point in a
Qt6QuickWidgets.dll carried over from the previous version.
Derive the required list from SERVATRICE_QT_MODULES, COCKATRICE_QT_MODULES and
ORACLE_QT_MODULES, the same module lists the targets are actually built against,
so it cannot drift from what the binaries need, and write it next to the CMake
cache as required-qt-runtime.txt. Add the platform plugin, without which the
client cannot start at all.
Assert it in the existing 7-Zip pass that already rejects build-tree artifacts,
comparing exact relative paths so a same-named file in the wrong directory does
not satisfy a requirement, and normalizing the archive's own separators so it
does not matter which one NSIS chose. Missing manifest, missing entry or missing
7-Zip-independent failures all stop the build rather than warn, which is the
whole point: the previous check already failed hard for artifacts, and a warning
here is what let a broken package ship.
* [Client] Point the Windows qt.conf translations path at the real one
The Windows qt.conf carried Translations = Resources/translations, copied from
the macOS bundle block, but the Windows install has no Resources directory: the
.qm files are installed to COCKATRICE_WIN32_QM_INSTALL_DIR, which is
translations, and main.cpp looks for them at applicationDirPath() +
"/translations". Leave the macOS value alone, which is correct for it.
* [Installer] Close the /? help string so the installer compiles again
The last line of the continued MessageBox string ended in $\n\" instead of $\n".
NSIS reads \" as an escaped quote, so the string never terminated and makensis
rejected the script, which took the CPack packaging step down with it. The
Windows build failed on "Problem running NSIS command" before ever reaching the
new required-runtime check.
* [Installer] Give FindFirst the two arguments it takes
FindFirst takes the pattern and the output variable and leaves the search
handle in $0. There is no handle argument, and FindNext taking only a variable
is the giveaway: the handle has to live somewhere implicit, and it is $0.
The call passed three arguments, so makensis rejected the script and the CPack
packaging step failed with "Problem running NSIS command" before ever reaching
the required-runtime check.
This was not only a compile error. The handle variable was never populated, so
the stale-runtime check that commit
|
||
|---|---|---|
| .. | ||
| dlg_connect.cpp | ||
| dlg_connect.h | ||
| dlg_convert_deck_to_cod_format.cpp | ||
| dlg_convert_deck_to_cod_format.h | ||
| dlg_create_game.cpp | ||
| dlg_create_game.h | ||
| dlg_default_tags_editor.cpp | ||
| dlg_default_tags_editor.h | ||
| dlg_edit_avatar.cpp | ||
| dlg_edit_avatar.h | ||
| dlg_edit_password.cpp | ||
| dlg_edit_password.h | ||
| dlg_edit_tokens.cpp | ||
| dlg_edit_tokens.h | ||
| dlg_edit_user.cpp | ||
| dlg_edit_user.h | ||
| dlg_filter_games.cpp | ||
| dlg_filter_games.h | ||
| dlg_forgot_password_challenge.cpp | ||
| dlg_forgot_password_challenge.h | ||
| dlg_forgot_password_request.cpp | ||
| dlg_forgot_password_request.h | ||
| dlg_forgot_password_reset.cpp | ||
| dlg_forgot_password_reset.h | ||
| dlg_invite_to_game.cpp | ||
| dlg_invite_to_game.h | ||
| dlg_load_deck.cpp | ||
| dlg_load_deck.h | ||
| dlg_load_deck_from_clipboard.cpp | ||
| dlg_load_deck_from_clipboard.h | ||
| dlg_load_deck_from_website.cpp | ||
| dlg_load_deck_from_website.h | ||
| dlg_load_remote_deck.cpp | ||
| dlg_load_remote_deck.h | ||
| dlg_local_game_options.cpp | ||
| dlg_local_game_options.h | ||
| dlg_login_prompt.cpp | ||
| dlg_login_prompt.h | ||
| dlg_manage_sets.cpp | ||
| dlg_manage_sets.h | ||
| dlg_my_reports.cpp | ||
| dlg_my_reports.h | ||
| dlg_register.cpp | ||
| dlg_register.h | ||
| dlg_report_user.cpp | ||
| dlg_report_user.h | ||
| dlg_select_set_for_cards.cpp | ||
| dlg_select_set_for_cards.h | ||
| dlg_settings.cpp | ||
| dlg_settings.h | ||
| dlg_share_deck.cpp | ||
| dlg_share_deck.h | ||
| dlg_shared_decks_preview.cpp | ||
| dlg_shared_decks_preview.h | ||
| dlg_startup_card_check.cpp | ||
| dlg_startup_card_check.h | ||
| dlg_tip_of_the_day.cpp | ||
| dlg_tip_of_the_day.h | ||
| dlg_update.cpp | ||
| dlg_update.h | ||
| dlg_view_log.cpp | ||
| dlg_view_log.h | ||
| override_printing_warning.cpp | ||
| override_printing_warning.h | ||
| tip_of_the_day.cpp | ||
| tip_of_the_day.h | ||