environment variables - ¿Cómo modifico la variable de entorno PATH cuando ejecuto un instalador Inno Setup?
environment-variables inno-setup (5)
Inno Setup le permite configurar variables de entorno a través de las secciones [Registro] (configurando la clave de registro que corresponde a la variable de entorno)
Sin embargo, a veces no solo quieres establecer una variable de entorno. A menudo, quieres modificarlo. Por ejemplo: después de la instalación, uno puede desear agregar / eliminar un directorio a / desde la variable de entorno PATH.
¿Cómo puedo modificar la variable de entorno PATH desde InnoSetup?
Aquí hay una solución completa al problema que ignora la carcasa, verifica la existencia de una ruta que termine con /
y también expande las constantes en el parámetro:
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
ParamExpanded: string;
begin
//expand the setup constants like {app} from Param
ParamExpanded := ExpandConstant(Param);
if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
''SYSTEM/CurrentControlSet/Control/Session Manager/Environment'',
''Path'', OrigPath)
then begin
Result := True;
exit;
end;
// look for the path with leading and trailing semicolon and with or without / ending
// Pos() returns 0 if not found
Result := Pos('';'' + UpperCase(ParamExpanded) + '';'', '';'' + UpperCase(OrigPath) + '';'') = 0;
if Result = True then
Result := Pos('';'' + UpperCase(ParamExpanded) + ''/;'', '';'' + UpperCase(OrigPath) + '';'') = 0;
end;
El NeedsAddPath
en la respuesta por @mghie no comprueba el caso de /
y la letra de seguimiento. Arreglalo.
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
begin
if not RegQueryStringValue(
HKEY_LOCAL_MACHINE,
''SYSTEM/CurrentControlSet/Control/Session Manager/Environment'',
''Path'', OrigPath)
then begin
Result := True;
exit;
end;
{ look for the path with leading and trailing semicolon }
{ Pos() returns 0 if not found }
Result :=
(Pos('';'' + UpperCase(Param) + '';'', '';'' + UpperCase(OrigPath) + '';'') = 0) and
(Pos('';'' + UpperCase(Param) + ''/;'', '';'' + UpperCase(OrigPath) + '';'') = 0);
end;
Puede usar el script modpath.iss de modpath.iss en su archivo de script InnoSetup:
#define MyTitleName "MyApp"
[Setup]
ChangesEnvironment=yes
[CustomMessages]
AppAddPath=Add application directory to your environmental path (required)
[Files]
Source: "install/*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
[Icons]
Name: "{group}/{cm:UninstallProgram,{#MyTitleName}}"; Filename: "{uninstallexe}"; Comment: "Uninstalls {#MyTitleName}"
Name: "{group}/{#MyTitleName}"; Filename: "{app}/{#MyTitleName}.EXE"; WorkingDir: "{app}"; AppUserModelID: "{#MyTitleName}"; Comment: "Runs {#MyTitleName}"
Name: "{commondesktop}/{#MyTitleName}"; Filename: "{app}/{#MyTitleName}.EXE"; WorkingDir: "{app}"; AppUserModelID: "{#MyTitleName}"; Comment: "Runs {#MyTitleName}"
[Registry]
Root: HKLM; Subkey: "SYSTEM/CurrentControlSet/Control/Session Manager/Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"
[Tasks]
Name: modifypath; Description:{cm:AppAddPath};
[Code]
const
ModPathName = ''modifypath'';
ModPathType = ''system'';
function ModPathDir(): TArrayOfString;
begin
setArrayLength(Result, 1)
Result[0] := ExpandConstant(''{app}'');
end;
#include "modpath.iss"
Tuve el mismo problema, pero a pesar de las respuestas anteriores, terminé con una solución personalizada y me gustaría compartirla con usted.
En primer lugar, he creado el archivo environment.iss
con 2 métodos, uno para agregar la ruta a la variable Path del entorno y el segundo para eliminarlo:
[Code]
const EnvironmentKey = ''SYSTEM/CurrentControlSet/Control/Session Manager/Environment'';
procedure EnvAddPath(Path: string);
var
Paths: string;
begin
{ Retrieve current path (use empty string if entry not exists) }
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, ''Path'', Paths)
then Paths := '''';
{ Skip if string already found in path }
if Pos('';'' + Uppercase(Path) + '';'', '';'' + Uppercase(Paths) + '';'') > 0 then exit;
{ App string to the end of the path variable }
Paths := Paths + '';''+ Path +'';''
{ Overwrite (or create if missing) path environment variable }
if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, ''Path'', Paths)
then Log(Format(''The [%s] added to PATH: [%s]'', [Path, Paths]))
else Log(Format(''Error while adding the [%s] to PATH: [%s]'', [Path, Paths]));
end;
procedure EnvRemovePath(Path: string);
var
Paths: string;
P: Integer;
begin
{ Skip if registry entry not exists }
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, ''Path'', Paths) then
exit;
{ Skip if string not found in path }
P := Pos('';'' + Uppercase(Path) + '';'', '';'' + Uppercase(Paths) + '';'');
if P = 0 then exit;
{ Update path variable }
Delete(Paths, P - 1, Length(Path) + 1);
{ Overwrite path environment variable }
if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, ''Path'', Paths)
then Log(Format(''The [%s] removed from PATH: [%s]'', [Path, Paths]))
else Log(Format(''Error while removing the [%s] from PATH: [%s]'', [Path, Paths]));
end;
Referencia: RegQueryStringValue
, RegWriteStringValue
Ahora, en el archivo .iss principal, podría incluir este archivo y escuchar los 2 eventos (más sobre eventos que puede aprender en la sección Funciones de eventos en la documentación), CurStepChanged
para agregar una ruta después de la instalación y CurUninstallStepChanged
para eliminarla cuando el usuario desinstala una aplicación. En el siguiente script de ejemplo, agregue / elimine el directorio bin
(relativo al directorio de instalación):
#include "environment.iss"
[Setup]
ChangesEnvironment=true
; More options in setup section as well as other sections like Files, Components, Tasks...
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall
then EnvAddPath(ExpandConstant(''{app}'') +''/bin'');
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall
then EnvRemovePath(ExpandConstant(''{app}'') +''/bin'');
end;
Referencia: ExpandConstant
Nota n. ° 1 : Instale el paso agregar ruta una sola vez (garantiza la repetibilidad de la instalación).
Nota # 2 : el paso de desinstalación elimina solo una aparición de la ruta de la variable.
Bonus : Paso de instalación con la casilla de verificación "Agregar a variable PATH" .
Para agregar el paso de instalación con la casilla de verificación "Agregar a variable PATH", defina una nueva tarea en la sección [Tasks]
(marcada de forma predeterminada):
[Tasks]
Name: envPath; Description: "Add to PATH variable"
Entonces puedes comprobarlo en el evento CurStepChanged
:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep = ssPostInstall) and IsTaskSelected(''envPath'')
then EnvAddPath(ExpandConstant(''{app}'') +''/bin'');
end;
La ruta en la clave de registro que dio es un valor de tipo REG_EXPAND_SZ
. Como la documentación de Inno Setup para la sección [Registro] indica que hay una manera de agregar elementos a esos:
En una
string
,expandsz
o valor de tipomultisz
, puede usar una constante especial llamada{olddata}
en este parámetro.{olddata}
se reemplaza con los datos anteriores del valor de registro. La constante{olddata}
puede ser útil si necesita agregar una cadena a un valor existente, por ejemplo,{olddata};{app}
. Si el valor no existe o el valor existente no es un tipo de cadena, la constante{olddata}
se elimina silenciosamente.
Entonces, para agregar a la ruta se puede usar una sección de registro similar a esta:
[Registry]
Root: HKLM; Subkey: "SYSTEM/CurrentControlSet/Control/Session Manager/Environment"; /
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:/foo"
que agregaría el directorio "C: / foo" a la ruta.
Lamentablemente, esto se repetirá cuando instale una segunda vez, lo que también debería solucionarse. Se puede usar un parámetro de Check
con una función codificada en el script de Pascal para verificar si la ruta realmente necesita expandirse:
[Registry]
Root: HKLM; Subkey: "SYSTEM/CurrentControlSet/Control/Session Manager/Environment"; /
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:/foo"; /
Check: NeedsAddPath(''C:/foo'')
Esta función lee el valor de la ruta original y comprueba si el directorio dado ya está contenido en ella. Para ello, se antepone y agrega caracteres de punto y coma que se utilizan para separar directorios en la ruta. Para tener en cuenta el hecho de que el directorio buscado puede ser el primer o último elemento, los caracteres de punto y coma se añaden y se agregan al valor original también:
[Code]
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
begin
if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
''SYSTEM/CurrentControlSet/Control/Session Manager/Environment'',
''Path'', OrigPath)
then begin
Result := True;
exit;
end;
{ look for the path with leading and trailing semicolon }
{ Pos() returns 0 if not found }
Result := Pos('';'' + Param + '';'', '';'' + OrigPath + '';'') = 0;
end;
Tenga en cuenta que es posible que necesite expandir las constantes antes de pasarlas como parámetro a la función de verificación; consulte la documentación para obtener más detalles.
La eliminación de este directorio de la ruta durante la desinstalación se puede realizar de manera similar y se deja como un ejercicio para el lector.