Estoy usando Inno Setup para crear un instalador.
Quiero que el instalador desinstale automáticamente la versión instalada anterior, en lugar de sobrescribirla. ¿Cómo puedo hacer eso?
Estoy usando Inno Setup para crear un instalador.
Quiero que el instalador desinstale automáticamente la versión instalada anterior, en lugar de sobrescribirla. ¿Cómo puedo hacer eso?
Respuestas:
Debería poder leer la cadena de desinstalación del registro, dado el AppId (es decir, el valor que utilizó AppID
en la [Setup]
sección-). Se puede encontrar en Software\Microsoft\Windows\CurrentVersion\Uninstall\{AppId}\
(podría ser HKLM
o HKCU
, por lo que es mejor marcar ambos) donde {AppId}
debe sustituirse por el valor real que utilizó. Busque los valores UninstallString
o QuietUninstallString
y use la Exec
función para ejecutarlo desde su InitializeSetup()
función de evento.
Actualización: se eliminó la solución alternativa que no funciona usando una [Run]
entrada de sección con {uninstallexe}
- ¡gracias a todos los comentaristas que señalaron esto!
[Run]
solución de la sección funcione, porque se ejecuta demasiado tarde en el proceso de instalación. Del manual Inno Setup: La sección [Ejecutar] es opcional y especifica cualquier número de programas para ejecutar después de que el programa se haya instalado correctamente, pero antes de que el programa de instalación muestre el cuadro de diálogo final.
He usado lo siguiente. No estoy seguro de que sea la forma más sencilla de hacerlo, pero funciona.
Este utiliza {#emit SetupSetting("AppId")}
que se basa en el preprocesador de configuración Inno. Si no lo usa, corte y pegue su ID de aplicación directamente.
[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;
Alternativas
Consulte también esta publicación de blog "Ejemplo de secuencia de comandos de configuración de Inno para la comparación de versiones", que va un paso más allá, lee el número de versión de cualquier versión instalada previamente y compara ese número de versión con el del paquete de instalación actual.
... 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;
Si "solo desea eliminar los íconos antiguos" (porque los suyos han cambiado / actualizado), puede usar esto:
; attempt to remove previous versions' icons
[InstallDelete]
Type: filesandordirs; Name: {group}\*;
Esto se ejecuta "al comienzo de la instalación", por lo que básicamente elimina los iconos antiguos, y los nuevos seguirán instalados allí después de que esto esté completamente hecho.
Solo hago esto con cada instalación "en caso de que algo haya cambiado" en cuanto a iconos (todo se reinstala de todos modos).
Al usar Inno Setup, no hay razón para desinstalar una versión anterior a menos que esa versión haya sido instalada por un programa de instalación diferente. De lo contrario, las actualizaciones se gestionan automáticamente.
[InstallDelete]
sección para eliminar archivos / directorios antiguos. Los nuevos archivos se colocarán en las ubicaciones correctas durante la instalación.
La respuesta proporcionada por Craig McQueen es totalmente viable. Aunque, agregaría esos comentarios:
{#emit SetupSetting("AppId")}
código no me funciona, así que solo agrego mi ID de aplicación.Entonces, con respecto al código de Craig McQueen, los cambios son:
InstallLocation
llave en lugar de la UninstallString
llave.DelTree
función en lugar de laExec(sUnInstallString, ...)
Para cualquier persona que use lo GetUninstallString()
sugerido anteriormente para forzar una desinstalación interna CurStepChanged()
y tenga problemas de almacenamiento en caché de disco, consulte a continuación una solución relacionada que en realidad espera un tiempo después de la desinstalación para que se elimine el desinstalador exe.
¿Problema de almacenamiento en caché de disco con inno-setup?
Puede ejecutar un desinstalador en la sección [código]. Tienes que averiguar cómo obtener la ruta al desinstalador existente. Para simplificar, cuando instalo mis aplicaciones, agrego un valor de cadena de registro que apunta a la carpeta que contiene el desinstalador, y simplemente ejecuto el desinstalador en la devolución de llamada de InitializeWizard.
Tenga en cuenta que los nombres del desinstalador de instalación de Inno tienen el formato uninsnnn.exe, debe tenerlo en cuenta en su código.
Me editaron el código de @Crain Mc-Queen, creo que este código es mejor porque no es necesario modificarlo en un proyecto diferente:
[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;
Debo estar perdiendo algo. Los nuevos archivos se copian en el directorio de destino antes de que se elimine la instalación anterior. Luego viene el desinstalador los borra y elimina el directorio.
No utilice la sección [Ejecutar], sino [UninstallRun]. De hecho, el programa en [Ejecutar] se ejecuta después de la instalación, lo que provoca la desinstalación del programa inmediatamente después de la instalación: - | En su lugar, la sección [UninstallRun] se evalúa antes de la instalación.
[UninstallRun]
no es una solución para la pregunta.
Siga este enlace: http://news.jrsoftware.org/news/innosetup/msg55323.html
En la función InitializeSetup (), puede llamar a "MSIEXEC / x {su ID de programa}" después de que el usuario le pida que desinstale la versión anterior.