Как изменить переменную среды PATH при запуске Inno Setup Installer?
Программа Inno Setup позволяет вам устанавливать переменные среды через разделы [Registry] (путем установки раздела реестра, соответствующего переменной среды)
Однако иногда вы не просто хотите задать переменную среды. Часто вы хотите изменить его. Например: при установке можно добавить/удалить каталог в/из переменной среды PATH.
Как изменить переменную среды PATH из InnoSetup?
Ответы
Ответ 1
Путь в указанном вами ключе реестра - это значение типа REG_EXPAND_SZ
. Поскольку в документации по Inno Setup для раздела [Registry] говорится, что есть способ добавить к ним элементы:
В значении типа string
, expandsz
или multisz
вы можете использовать специальную константу с именем {olddata}
в этом параметре. {olddata}
заменяется предыдущими данными значения реестра. Константа {olddata}
может быть полезна, если вам нужно добавить строку к существующему значению, например, {olddata};{app}
. Если значение не существует или существующее значение не является строковым типом, константа {olddata}
молча удаляется.
Итак, чтобы добавить к пути, можно использовать раздел реестра, подобный этому:
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\foo"
который добавит каталог "C:\foo" в путь.
К сожалению, это будет повторяться при установке второго раза, что также должно быть исправлено. Параметр Check
с функцией, закодированной в Pascal script, может использоваться для проверки того, действительно ли путь необходимо развернуть:
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\foo"; \
Check: NeedsAddPath('C:\foo')
Эта функция считывает исходное значение пути и проверяет, содержит ли данный каталог в нем. Для этого он добавляет и добавляет символы с запятой, которые используются для разделения каталогов в пути. Чтобы учесть тот факт, что искомый каталог может быть первым или последним символом точки с запятой, добавляется и добавляется к исходному значению:
[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;
Обратите внимание, что вам может потребоваться развернуть константы, прежде чем передавать их в качестве параметра функции проверки. Подробнее см. в документации.
Удаление этого каталога из пути во время удаления может быть выполнено аналогичным образом и оставлено как упражнение для читателя.
Ответ 2
Вы можете использовать Legroom.net modpath.iss script в файле InnoSetup script:
#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"
Ответ 3
У меня была та же проблема, но, несмотря на ответы выше, я нашел нестандартное решение и хотел бы поделиться им с вами.
Прежде всего, я создал файл environment.iss
с двумя методами - один для добавления пути к переменной пути среды, а второй для его удаления:
[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;
Ссылка: RegQueryStringValue
, RegWriteStringValue
Теперь в основной файл .iss я мог бы включить этот файл и прослушать 2 события (подробнее о событиях вы можете узнать в разделе Функции событий в документации), CurStepChanged
добавить путь после установки и CurUninstallStepChanged
чтобы удалить его, когда пользователь удаляет приложение. В приведенном ниже примере сценария добавьте/удалите каталог bin
(относительно каталога установки):
#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;
Ссылка: ExpandConstant
Примечание № 1: шаг установки добавить путь только один раз (обеспечивает повторяемость установки).
Примечание № 2: шаг удаления удаляет только одно вхождение пути из переменной.
Бонус: шаг установки с флажком "Добавить в переменную PATH".
![Inno Setup - Add to PATH variable]()
Чтобы добавить шаг установки с флажком "Добавить в переменную PATH", определите новую задачу в разделе [Tasks]
(по умолчанию установлено):
[Tasks]
Name: envPath; Description: "Add to PATH variable"
Затем вы можете проверить это в событии CurStepChanged
:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep = ssPostInstall) and IsTaskSelected('envPath')
then EnvAddPath(ExpandConstant('{app}') +'\bin');
end;
Ответ 4
NeedsAddPath
в ответ от @mghie не проверяет завершающий \
и буквенный регистр. Исправьте его.
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;
Ответ 5
Вот полное решение проблемы, которая игнорирует оболочку, проверяет существование пути, заканчивающегося на \
, а также расширяет константы в param:
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;