web-dev-qa-db-fra.com

Inno Setup: Comment désinstaller automatiquement la version installée précédente?

J'utilise Inno Setup pour créer un programme d'installation.

Je souhaite que le programme d'installation désinstalle automatiquement la version installée précédente, au lieu de la remplacer. Comment puis je faire ça?

81
Vimvq1987

Vous devriez pouvoir lire la chaîne de désinstallation à partir du registre, étant donné l'AppId (c'est-à-dire la valeur que vous avez utilisée pour AppID dans la section [Setup]). Il peut être trouvé sous Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\ (Peut être HKLM ou HKCU, donc mieux vérifier les deux) où {AppId} Doit être remplacé par la valeur réelle que vous avez utilisée . Recherchez les valeurs UninstallString ou QuietUninstallString et utilisez la fonction Exec pour l'exécuter à partir de votre fonction d'événement InitializeSetup().

Mise à jour: a supprimé la solution alternative qui ne fonctionnait pas en utilisant une entrée de section [Run] Avec {uninstallexe} - merci à tous les commentateurs qui l'ont signalé!

25
Oliver Giesen

J'ai utilisé ce qui suit. Je ne suis pas sûr que ce soit la façon la plus simple de le faire, mais cela fonctionne.

Cela utilise {#emit SetupSetting("AppId")} qui repose sur le préprocesseur Inno Setup. Si vous ne l'utilisez pas, copiez-collez directement votre ID d'application.

[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;

Alternatives

Voir aussi cet article de blog "Exemple de script de configuration Inno pour comparaison de versions" qui va plus loin et lit le numéro de version de toute version précédemment installée et compare ce numéro de version avec celui du package d'installation actuel .

103
Craig McQueen

Lorsque vous utilisez Inno Setup, il n'y a aucune raison de désinstaller une version précédente à moins que cette version n'ait été installée par un programme d'installation différent. Sinon, les mises à niveau sont gérées automatiquement.

7
mlaan

Si vous "voulez simplement supprimer les anciennes icônes" (parce que les vôtres ont changé/mis à jour), vous pouvez utiliser ceci:

; attempt to remove previous versions' icons
[InstallDelete]
Type: filesandordirs; Name: {group}\*;

Ceci est exécuté "au début de l'installation", donc supprime fondamentalement les anciennes icônes, et vos nouvelles y seront toujours installées une fois que cela sera complètement fait.

Je fais juste cela avec chaque installation "au cas où quelque chose a changé" au niveau des icônes (tout est réinstallé de toute façon).

6
rogerdpack

La réponse fournie par Craig McQueen est totalement viable. Cependant, j'ajouterais ces commentaires:

  • Le code {#emit SetupSetting("AppId")} ne fonctionne pas pour moi, donc j'ajoute simplement mon ID d'application.
  • Je ne voulais pas exécuter mon programme de désinstallation, car j'ai un fichier de configuration INI stocké dans le dossier AppData/qui est supprimé par le programme de désinstallation) et je ne souhaite pas qu'il soit effacé. lors de l'installation d'une nouvelle version. J'ai donc modifié un peu le code fourni par Craig McQueen pour supprimer le répertoire où est installé le programme, après avoir récupéré son chemin.

Donc, concernant le code de Craig McQueen, les changements sont:

  • Récupérez la clé InstallLocation au lieu de la clé UninstallString.
  • Utilisez la fonction DelTree au lieu de la fonction Exec(sUnInstallString, ...)
2
user650022

Pour toute personne qui utilise la GetUninstallString() suggérée ci-dessus pour forcer une désinstallation à l'intérieur de CurStepChanged() et qui a des problèmes de mise en cache de disque, voir ci-dessous pour une solution connexe qui attend réellement un certain temps après la désinstallation pour l'exe du programme de désinstallation de être supprimé!

Problème de mise en cache du disque avec inno-setup?

1
fubar

Vous pouvez exécuter un programme de désinstallation dans la section [code]. Vous devez comprendre comment obtenir le chemin d'accès au programme de désinstallation existant. Pour plus de simplicité lorsque j'installe mes applications, j'ajoute une valeur de chaîne de registre qui pointe vers le dossier contenant le programme de désinstallation, et j'exécute simplement le programme de désinstallation dans le rappel InitializeWizard.

Gardez à l'esprit que les noms du programme de désinstallation d'Inno sont tous sous la forme uninsnnn.exe, vous devez en tenir compte dans votre code.

0
Jim In Texas

j'ai édité le code @Crain Mc-Queen, je pense que ce code est meilleur car il n'est pas nécessaire de le modifier dans un projet différent:

[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;
0
MohsenB