Używam Inno Setup do tworzenia instalatora.
Chcę, aby instalator automatycznie odinstalował poprzednio zainstalowaną wersję, zamiast ją nadpisywać. Jak mogę to zrobić?
Używam Inno Setup do tworzenia instalatora.
Chcę, aby instalator automatycznie odinstalował poprzednio zainstalowaną wersję, zamiast ją nadpisywać. Jak mogę to zrobić?
Odpowiedzi:
Powinno być możliwe odczytanie ciągu dezinstalacji z rejestru, biorąc pod uwagę identyfikator AppId (tj. Wartość użytą AppID
w sekcji [Setup]
). Można go znaleźć pod Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\
(może być albo HKLM
albo HKCU
, więc najlepiej sprawdzić oba), gdzie {AppId}
należy go zastąpić rzeczywistą użytą wartością. Poszukaj wartości UninstallString
lub QuietUninstallString
i użyj Exec
funkcji, aby uruchomić ją z InitializeSetup()
funkcji zdarzenia.
Aktualizacja: usunięto niedziałające alternatywne rozwiązanie z użyciem [Run]
wpisu sekcji z {uninstallexe}
- podziękowania dla wszystkich komentujących, którzy zwrócili na to uwagę!
[Run]
rozwiązanie sekcji działało, ponieważ działa zbyt późno w procesie instalacji. Z podręcznika Inno Setup: Sekcja [Run] jest opcjonalna i określa dowolną liczbę programów do wykonania po pomyślnym zainstalowaniu programu, ale zanim program instalacyjny wyświetli ostatnie okno dialogowe.
Użyłem następujących. Nie jestem pewien, czy to najprostszy sposób, ale działa.
To używa, {#emit SetupSetting("AppId")}
który opiera się na Preprocesorze Inno Setup. Jeśli tego nie używasz, wytnij i wklej swój identyfikator aplikacji bezpośrednio.
[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;
Alternatywy
Zobacz także ten wpis na blogu „Inno Setup Script Sample for Version Porównanie”, który idzie o krok dalej i czyta numer każdej poprzednio zainstalowanej wersji i porównuje ten numer z numerem bieżącego pakietu instalacyjnego.
... 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;
Jeśli chcesz „tylko usunąć stare ikony” (ponieważ Twoje uległy zmianie / aktualizacji), możesz użyć tego:
; attempt to remove previous versions' icons
[InstallDelete]
Type: filesandordirs; Name: {group}\*;
Jest to uruchamiane „na początku instalacji”, więc zasadniczo usuwa stare ikony, a nowe będą nadal tam instalowane po zakończeniu instalacji.
Po prostu robię to przy każdej instalacji "na wypadek, gdyby coś się zmieniło" pod względem ikon (wszystko i tak zostanie ponownie zainstalowane).
Podczas korzystania z Inno Setup nie ma powodu, aby odinstalować poprzednią wersję, chyba że ta wersja została zainstalowana przez inny program instalacyjny. W przeciwnym razie aktualizacje są obsługiwane automatycznie.
[InstallDelete]
sekcji, aby usunąć stare pliki / katalogi. Nowe pliki zostaną następnie umieszczone we właściwych lokalizacjach podczas instalacji.
Odpowiedź udzielona przez Craiga McQueena jest całkowicie realna. Chociaż dodałbym te uwagi:
{#emit SetupSetting("AppId")}
Kod nie działa dla mnie, więc po prostu dodać swój identyfikator aplikacji.Tak więc, jeśli chodzi o kod Craiga McQueena, zmiany są następujące:
InstallLocation
klucz zamiast UninstallString
klucza.DelTree
funkcji zamiastExec(sUnInstallString, ...)
Dla każdego, kto używa GetUninstallString()
sugerowanego powyżej, aby wymusić odinstalowanie wewnątrz CurStepChanged()
i ma problemy z buforowaniem dysku, zobacz poniżej powiązane rozwiązanie, które faktycznie czeka chwilę po odinstalowaniu na usunięcie deinstalatora exe!
Możesz uruchomić deinstalator w sekcji [kod]. Musisz dowiedzieć się, jak uzyskać ścieżkę do istniejącego deinstalatora. Dla uproszczenia podczas instalowania aplikacji dodaję wartość ciągu rejestru wskazującą na folder zawierający dezinstalator i po prostu wykonuję deinstalator w wywołaniu zwrotnym InitializeWizard.
Należy pamiętać, że wszystkie nazwy deinstalatorów instalacji Inno mają postać uninsnnn.exe, należy to uwzględnić w kodzie.
Mam edytowany kod @Crain Mc-Queen, myślę, że ten kod jest lepszy, ponieważ nie trzeba go modyfikować w innym projekcie:
[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;
Muszę czegoś przegapić. Te nowe pliki zostaną skopiowane do katalogu docelowego, zanim nastąpi usunięcie starej instalacji. Następnie deinstalator usuwa je i usuwa katalog.
Nie używaj sekcji [Run], ale [UninstallRun]. W rzeczywistości programy w [Run] są uruchamiane po instalacji, powodując odinstalowanie programu natychmiast po instalacji: - | Zamiast tego sekcja [UninstallRun] jest sprawdzana przed instalacją.
[UninstallRun]
nie jest rozwiązaniem na to pytanie.
Skorzystaj z tego łącza: http://news.jrsoftware.org/news/innosetup/msg55323.html
W funkcji InitializeSetup () możesz wywołać „MSIEXEC / x {identyfikator Twojego programu}” po wyświetleniu monitu użytkownika o odinstalowanie starej wersji