mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-28 08:52:19 -07:00
Compare commits
4 commits
561cadd217
...
97c0de876d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97c0de876d | ||
|
|
de47ddfcae | ||
|
|
1b7f9c0de4 | ||
|
|
6d06ae2bcf |
2 changed files with 212 additions and 1 deletions
|
|
@ -131,6 +131,13 @@ ${EndIf}
|
|||
; Now that $PortableMode reflects reality, commit InstDir into the correct slot
|
||||
Call SetModeDestinationFromInstdir
|
||||
|
||||
; Make sure no application instance is still running (and holding file locks)
|
||||
; before the previous version is uninstalled or new files are installed.
|
||||
; On a silent update (/R /S) running processes are asked to close gracefully
|
||||
; and waited for, then force-closed only on timeout. On interactive installs
|
||||
; the user is prompted to close them instead.
|
||||
Call EnsureAppsNotRunning
|
||||
|
||||
${If} $ReinstallMode = 1
|
||||
${AndIf} $PortableMode = 0
|
||||
Call AutoUninstallIfNeeded
|
||||
|
|
@ -144,6 +151,9 @@ ${If} ${NSIS_IS_64_BIT} == 1
|
|||
SetRegView 64
|
||||
${EndIf}
|
||||
|
||||
; Ensure no application instance is still running before removing files.
|
||||
Call un.EnsureAppsNotRunning
|
||||
|
||||
FunctionEnd
|
||||
|
||||
Function RequireAdmin
|
||||
|
|
@ -199,6 +209,170 @@ ${EndIf}
|
|||
|
||||
FunctionEnd
|
||||
|
||||
; --- Running instance handling ---
|
||||
; Cockatrice, Oracle and Servatrice must not be running while files are
|
||||
; replaced or deleted. A still-running process holds locks on its .exe and
|
||||
; Qt runtime DLLs, so a silent upgrade could otherwise end up with a mix of
|
||||
; old and new Qt DLLs next to the new executable, failing with
|
||||
; "The procedure entry point X could not be located in the dynamic link
|
||||
; library ...Qt6Network.dll" on the next start.
|
||||
;
|
||||
; Processes are matched by image name AND by their executable path living
|
||||
; under $INSTDIR, so unrelated processes that merely share an image name
|
||||
; (e.g. the Oracle DB instance "oracle.exe") are never touched.
|
||||
|
||||
; usage: set $R2 to the base image name (without extension, e.g. "cockatrice",
|
||||
; as accepted by Get-Process -Name), call this, result in $R0
|
||||
; (1 = running from $INSTDIR, 0 = not running)
|
||||
Function IsAppRunning
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | Select-Object -First 1"'
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
StrCpy $R0 1
|
||||
${Else}
|
||||
StrCpy $R0 0
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function CloseMatchingApps
|
||||
; gracefully ask every matching instance to close (sends WM_CLOSE)
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | ForEach-Object { $$null = $$_.CloseMainWindow() }"'
|
||||
Pop $R3
|
||||
FunctionEnd
|
||||
|
||||
Function ForceCloseMatchingApps
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | Stop-Process -Force -ErrorAction SilentlyContinue"'
|
||||
Pop $R3
|
||||
FunctionEnd
|
||||
|
||||
Function WaitForAppToClose
|
||||
; usage: set $R1 to the display name (e.g. "cockatrice.exe") and $R2 to the
|
||||
; base image name (e.g. "cockatrice")
|
||||
Call IsAppRunning
|
||||
${If} $R0 = 0
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
${If} ${Silent}
|
||||
; ask the application to close gracefully (WM_CLOSE), then wait for it to exit
|
||||
DetailPrint "Closing $R1 ..."
|
||||
Call CloseMatchingApps
|
||||
StrCpy $R8 0
|
||||
ck_wait_loop:
|
||||
Sleep 500
|
||||
IntOp $R8 $R8 + 1
|
||||
Call IsAppRunning
|
||||
${If} $R0 = 0
|
||||
DetailPrint "$R1 closed."
|
||||
Return
|
||||
${EndIf}
|
||||
${If} $R8 < 60
|
||||
Goto ck_wait_loop
|
||||
${EndIf}
|
||||
; give up waiting, force close
|
||||
DetailPrint "Force closing $R1 ..."
|
||||
Call ForceCloseMatchingApps
|
||||
Sleep 500
|
||||
${Else}
|
||||
ck_wait_prompt:
|
||||
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON1 \
|
||||
"$R1 is still running.$\r$\n$\r$\nPlease close it, then click Retry.$\r$\nClick Cancel to abort." \
|
||||
IDCANCEL ck_abort_install
|
||||
Call IsAppRunning
|
||||
${If} $R0 = 0
|
||||
Return
|
||||
${EndIf}
|
||||
Goto ck_wait_prompt
|
||||
ck_abort_install:
|
||||
Abort
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function EnsureAppsNotRunning
|
||||
StrCpy $R1 "cockatrice.exe"
|
||||
StrCpy $R2 "cockatrice"
|
||||
Call WaitForAppToClose
|
||||
StrCpy $R1 "oracle.exe"
|
||||
StrCpy $R2 "oracle"
|
||||
Call WaitForAppToClose
|
||||
StrCpy $R1 "servatrice.exe"
|
||||
StrCpy $R2 "servatrice"
|
||||
Call WaitForAppToClose
|
||||
FunctionEnd
|
||||
|
||||
; Uninstaller copies of the same routines (the uninstaller gets its own
|
||||
; function set compiled in, it cannot call the installer functions).
|
||||
Function un.IsAppRunning
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | Select-Object -First 1"'
|
||||
Pop $R0
|
||||
${If} $R0 = 0
|
||||
StrCpy $R0 1
|
||||
${Else}
|
||||
StrCpy $R0 0
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function un.CloseMatchingApps
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | ForEach-Object { $$null = $$_.CloseMainWindow() }"'
|
||||
Pop $R3
|
||||
FunctionEnd
|
||||
|
||||
Function un.ForceCloseMatchingApps
|
||||
nsExec::ExecToLog 'powershell -NoProfile -Command "Get-Process -Name $\'$R2$\' -ErrorAction SilentlyContinue | Where-Object { $$_.Path -like $\'$INSTDIR\*$\' } | Stop-Process -Force -ErrorAction SilentlyContinue"'
|
||||
Pop $R3
|
||||
FunctionEnd
|
||||
|
||||
Function un.WaitForAppToClose
|
||||
Call un.IsAppRunning
|
||||
${If} $R0 = 0
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
${If} ${Silent}
|
||||
DetailPrint "Closing $R1 ..."
|
||||
Call un.CloseMatchingApps
|
||||
StrCpy $R8 0
|
||||
un_ck_wait_loop:
|
||||
Sleep 500
|
||||
IntOp $R8 $R8 + 1
|
||||
Call un.IsAppRunning
|
||||
${If} $R0 = 0
|
||||
DetailPrint "$R1 closed."
|
||||
Return
|
||||
${EndIf}
|
||||
${If} $R8 < 60
|
||||
Goto un_ck_wait_loop
|
||||
${EndIf}
|
||||
DetailPrint "Force closing $R1 ..."
|
||||
Call un.ForceCloseMatchingApps
|
||||
Sleep 500
|
||||
${Else}
|
||||
un_ck_wait_prompt:
|
||||
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON1 \
|
||||
"$R1 is still running.$\r$\n$\r$\nPlease close it, then click Retry.$\r$\nClick Cancel to abort." \
|
||||
IDCANCEL un_ck_abort_install
|
||||
Call un.IsAppRunning
|
||||
${If} $R0 = 0
|
||||
Return
|
||||
${EndIf}
|
||||
Goto un_ck_wait_prompt
|
||||
un_ck_abort_install:
|
||||
Abort
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function un.EnsureAppsNotRunning
|
||||
StrCpy $R1 "cockatrice.exe"
|
||||
StrCpy $R2 "cockatrice"
|
||||
Call un.WaitForAppToClose
|
||||
StrCpy $R1 "oracle.exe"
|
||||
StrCpy $R2 "oracle"
|
||||
Call un.WaitForAppToClose
|
||||
StrCpy $R1 "servatrice.exe"
|
||||
StrCpy $R2 "servatrice"
|
||||
Call un.WaitForAppToClose
|
||||
FunctionEnd
|
||||
|
||||
Function PortableModePageCreate
|
||||
|
||||
${If} $ReinstallMode = 1
|
||||
|
|
@ -318,6 +492,26 @@ ${AndIf} ${FileExists} "$INSTDIR\portable.dat"
|
|||
RMDir "$INSTDIR"
|
||||
${EndIf}
|
||||
|
||||
; Belt and braces: the old uninstaller may have already run in the /R path, so
|
||||
; ensure no application instance is still holding file locks, then remove any
|
||||
; runtime DLLs left over from older versions. A mismatched Qt/OpenSSL set next
|
||||
; to the new executable is what causes "The procedure entry point X could not be
|
||||
; located in the dynamic link library ...Qt6Network.dll" after an update.
|
||||
Call EnsureAppsNotRunning
|
||||
|
||||
${If} $PortableMode = 0
|
||||
${AndIf} ${FileExists} "$INSTDIR\cockatrice.exe"
|
||||
RMDir /r "$INSTDIR\Plugins"
|
||||
Delete "$INSTDIR\Qt*.dll"
|
||||
Delete "$INSTDIR\libcrypto*.dll"
|
||||
Delete "$INSTDIR\libssl*.dll"
|
||||
Delete "$INSTDIR\zlib*.dll"
|
||||
Delete "$INSTDIR\libmysql.dll"
|
||||
Delete "$INSTDIR\icu*.dll"
|
||||
Delete "$INSTDIR\libeay32.dll"
|
||||
Delete "$INSTDIR\ssleay32.dll"
|
||||
${EndIf}
|
||||
|
||||
@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
|
||||
@CPACK_NSIS_FULL_INSTALL@
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
#include "../client/network/update/client/release_channel.h"
|
||||
#include "../interface/window_main.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressBar>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtNetwork>
|
||||
#include <version_string.h>
|
||||
|
|
@ -240,8 +242,23 @@ void DlgUpdate::downloadSuccessful(const QUrl &filepath)
|
|||
|
||||
// Try to open the installer. If it opens, quit Cockatrice
|
||||
if (process.startDetached()) {
|
||||
QMetaObject::invokeMethod(static_cast<MainWindow *>(parent()), "close", Qt::QueuedConnection);
|
||||
qCInfo(DlgUpdateLog) << "Opened downloaded update file successfully - closing Cockatrice";
|
||||
// Close the main window synchronously so file locks are released before the NSIS installer
|
||||
// (already launched) starts replacing files. This also flushes settings and shuts down the
|
||||
// tabs, but only when the close is actually accepted: MainWindow may veto it for a running
|
||||
// card DB update, an open game, or an unsaved deck. In that case keep running so the user
|
||||
// can resolve the blocker, and tell them the installer is already waiting.
|
||||
if (auto *window = qobject_cast<MainWindow *>(parent())) {
|
||||
if (window->close()) {
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Update"),
|
||||
tr("The update installer is already running and will finish the update once "
|
||||
"Cockatrice closes. Cockatrice is still busy, so it stays open for now."));
|
||||
}
|
||||
} else {
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
close();
|
||||
} else {
|
||||
setLabel(tr("Error"));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue