Sto usando Inno Setup per creare un programma di installazione.
Voglio che il programma di installazione disinstalli automaticamente la versione installata precedente, invece di sovrascriverla. Come posso fare ciò?
Sto usando Inno Setup per creare un programma di installazione.
Voglio che il programma di installazione disinstalli automaticamente la versione installata precedente, invece di sovrascriverla. Come posso fare ciò?
Risposte:
Dovresti essere in grado di leggere la stringa di disinstallazione dal registro, dato l'AppId (ovvero il valore utilizzato AppID
nella [Setup]
sezione-). Potrebbe essere trovato sotto Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\
(potrebbe essere HKLM
o HKCU
, quindi è meglio controllare entrambi) dove {AppId}
dovrebbe essere sostituito con il valore effettivo che hai usato. Cerca i valori UninstallString
o QuietUninstallString
e utilizza la Exec
funzione per eseguirlo dalla InitializeSetup()
funzione evento.
Aggiornamento: rimossa la soluzione alternativa non funzionante utilizzando una [Run]
voce di sezione con {uninstallexe}
- grazie a tutti i commentatori che lo hanno segnalato!
[Run]
soluzione della sezione funzionerà, perché viene eseguita troppo tardi nel processo di installazione. Dal manuale di Inno Setup: La sezione [Esegui] è opzionale e specifica un numero qualsiasi di programmi da eseguire dopo che il programma è stato installato con successo, ma prima che il programma di installazione visualizzi la finestra di dialogo finale.
Ho usato quanto segue. Non sono sicuro che sia il modo più semplice per farlo, ma funziona.
Questo utilizza {#emit SetupSetting("AppId")}
che si basa sul Preprocessore Inno Setup. Se non lo usi, copia e incolla direttamente il tuo ID app.
[Code]
{ ///////////////////////////////////////////////////////////////////// }
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
{ ///////////////////////////////////////////////////////////////////// }
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
{ ///////////////////////////////////////////////////////////////////// }
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
{ Return Values: }
{ 1 - uninstall string is empty }
{ 2 - error executing the UnInstallString }
{ 3 - successfully executed the UnInstallString }
{ default return value }
Result := 0;
{ get the uninstall string of the old app }
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
{ ///////////////////////////////////////////////////////////////////// }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
end;
Alternative
Vedi anche questo post del blog "Inno Setup Script Sample for Version Comparison" che fa un ulteriore passo avanti e legge il numero di versione di qualsiasi versione precedentemente installata e confronta quel numero di versione con quello del pacchetto di installazione corrente.
... UserSIDs: TArrayOfString; I: Integer; ... if not RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString) then if isAdminLoggedOn() and RegGetSubkeyNames( HKEY_USERS, '', UserSIDs ) then for I := 0 to GetArrayLength( UserSIDs ) - 1 do begin if RegQueryStringValue( HKEY_USERS, UserSIDs[I] + '\' + sUnInstPath, 'UninstallString', sUnInstallString ) then break; end;
Se "vuoi solo rimuovere le vecchie icone" (perché le tue sono cambiate / aggiornate) puoi usare questo:
; attempt to remove previous versions' icons
[InstallDelete]
Type: filesandordirs; Name: {group}\*;
Viene eseguito "all'inizio dell'installazione", quindi in pratica rimuove le vecchie icone e quelle nuove saranno ancora installate lì dopo che questo è stato completamente fatto.
Lo faccio con ogni installazione "nel caso in cui qualcosa sia cambiato" per quanto riguarda l'icona (tutto viene reinstallato comunque).
Quando si utilizza Inno Setup, non c'è motivo di disinstallare una versione precedente a meno che quella versione non sia stata installata da un programma di installazione diverso. In caso contrario, gli aggiornamenti vengono gestiti automaticamente.
[InstallDelete]
sezione per rimuovere vecchi file / directory. I nuovi file verranno quindi inseriti nelle posizioni corrette durante l'installazione.
La risposta fornita da Craig McQueen è totalmente fattibile. Tuttavia, aggiungerei questi commenti:
{#emit SetupSetting("AppId")}
codice non funziona per me, quindi aggiungo semplicemente il mio ID app.Quindi, per quanto riguarda il codice di Craig McQueen, le modifiche sono:
InstallLocation
chiave invece della UninstallString
chiave.DelTree
funzione invece diExec(sUnInstallString, ...)
Per chiunque utilizzi quanto GetUninstallString()
suggerito sopra per forzare una disinstallazione interna CurStepChanged()
e ha problemi di cache del disco, vedere di seguito una soluzione correlata che in realtà attende un po 'dopo la disinstallazione per l'eliminazione dell'exe del programma di disinstallazione!
Puoi eseguire un programma di disinstallazione nella sezione [codice]. Devi capire come ottenere il percorso del programma di disinstallazione esistente. Per semplicità quando installo le mie app aggiungo un valore di stringa di registro che punta alla cartella contenente il programma di disinstallazione ed eseguo semplicemente il programma di disinstallazione nel callback InitializeWizard.
Tieni presente che i nomi del programma di disinstallazione di Inno Setup sono tutti nella forma uninsnnn.exe, devi tenerne conto nel tuo codice.
ho modificato il codice @Crain Mc-Queen, penso che questo codice sia migliore perché non è necessario modificarlo in un progetto diverso:
[Code]
function GetNumber(var temp: String): Integer;
var
part: String;
pos1: Integer;
begin
if Length(temp) = 0 then
begin
Result := -1;
Exit;
end;
pos1 := Pos('.', temp);
if (pos1 = 0) then
begin
Result := StrToInt(temp);
temp := '';
end
else
begin
part := Copy(temp, 1, pos1 - 1);
temp := Copy(temp, pos1 + 1, Length(temp));
Result := StrToInt(part);
end;
end;
function CompareInner(var temp1, temp2: String): Integer;
var
num1, num2: Integer;
begin
num1 := GetNumber(temp1);
num2 := GetNumber(temp2);
if (num1 = -1) or (num2 = -1) then
begin
Result := 0;
Exit;
end;
if (num1 > num2) then
begin
Result := 1;
end
else if (num1 < num2) then
begin
Result := -1;
end
else
begin
Result := CompareInner(temp1, temp2);
end;
end;
function CompareVersion(str1, str2: String): Integer;
var
temp1, temp2: String;
begin
temp1 := str1;
temp2 := str2;
Result := CompareInner(temp1, temp2);
end;
function InitializeSetup(): Boolean;
var
oldVersion: String;
uninstaller: String;
ErrorCode: Integer;
vCurID :String;
vCurAppName :String;
begin
vCurID:= '{#SetupSetting("AppId")}';
vCurAppName:= '{#SetupSetting("AppName")}';
//remove first "{" of ID
vCurID:= Copy(vCurID, 2, Length(vCurID) - 1);
//
if RegKeyExists(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1') then
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1',
'DisplayVersion', oldVersion);
if (CompareVersion(oldVersion, '{#SetupSetting("AppVersion")}') < 0) then
begin
if MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. Continue to use this old version?',
mbConfirmation, MB_YESNO) = IDYES then
begin
Result := False;
end
else
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + vCurID + '_is1',
'UninstallString', uninstaller);
ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
Result := True;
end;
end
else
begin
MsgBox('Version ' + oldVersion + ' of ' + vCurAppName + ' is already installed. This installer will exit.',
mbInformation, MB_OK);
Result := False;
end;
end
else
begin
Result := True;
end;
end;
Devo essermi perso qualcosa. I nuovi file vengono copiati nella directory di destinazione prima che si verifichi la rimozione della vecchia installazione. Quindi arriva il programma di disinstallazione che li elimina e rimuove la directory.
Non utilizzare la sezione [Esegui], ma [UninstallRun]. Infatti, i programmi sotto [Esegui] vengono eseguiti dopo l'installazione, provocando la disinstallazione del programma immediatamente dopo l'installazione: - | La sezione [UninstallRun] viene invece valutata prima dell'installazione.
[UninstallRun]
non è una soluzione per la domanda.
Segui questo link: http://news.jrsoftware.org/news/innosetup/msg55323.html
Nella funzione InitializeSetup (), puoi chiamare "MSIEXEC / x {your program ID}" dopo che l'utente ha chiesto di disinstallare la vecchia versione precedente