Inno Setup允许您通过[Registry]部分设置环境变量(通过设置对应于环境变量的注册表项)
但是,有时您不只是想设置一个环境变量。通常,你想修改它。例如:安装时,可能需要在PATH环境变量中添加/删除目录。
如何从InnoSetup中修改PATH环境变量?
答案 0 :(得分:77)
您提供的注册表项中的路径是类型REG_EXPAND_SZ
的值。正如 [Registry] 部分的Inno Setup文档所述,有一种方法可以将元素附加到这些文档:
在
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”目录附加到路径。
不幸的是,当您再次安装时会重复此操作,也应该修复。带有用Pascal脚本编码的函数的Check
参数可用于检查路径是否确实需要扩展:
[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;
请注意,在将它们作为参数传递给check函数之前,可能需要扩展常量,有关详细信息,请参阅文档。
在卸载过程中从路径中删除此目录可以以类似的方式完成,并留给读者练习。
答案 1 :(得分:17)
您可以在InnoSetup脚本文件中使用LegRoom.net的modpath.iss脚本:
#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"
答案 2 :(得分:9)
我遇到了同样的问题,但尽管有上述答案,我最终得到了一个自定义解决方案,我想与您分享。
首先,我使用2种方法创建了environment.iss
文件 - 一种用于添加环境路径&#39> 路径变量,另一种用于删除它:< / p>
[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个事件(更多关于您可以在文档中的Event Functions部分中学习的事件),CurStepChanged
以在安装后添加路径{ {1}}在用户卸载应用程序时将其删除。在下面的示例脚本中添加/删除CurUninstallStepChanged
目录(相对于安装目录):
bin
注意#1 :仅安装步骤添加路径一次(确保安装的可重复性)。
注意#2 :卸载步骤只从变量中删除一次路径。
奖金:安装步骤,复选框&#34;添加到PATH变量&#34; 。
使用复选框添加安装步骤&#34;添加到PATH变量&#34; 在#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;
部分中定义新任务(默认选中):
[Tasks]
然后你可以在[Tasks]
Name: envPath; Description: "Add to PATH variable"
事件中查看它:
CurStepChanged
答案 3 :(得分:7)
the answer by @mghie中的NeedsAddPath
不检查尾随\
和字母大小写。解决它。
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;
答案 4 :(得分:2)
这是一个完全解决问题的方法,它忽略了大小写,检查是否存在以\
结尾的路径,并且还扩展了参数中的常量:
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;
答案 5 :(得分:2)
我要感谢大家对这个问题的贡献。我已经将Wojciech Mleczek发布的代码的95%合并到了我的应用的安装程序中。我确实对该代码做了一些更正,可能对其他人有用。我的更改:
将形式参数Path
重命名为instlPath
。减少代码中“路径”的多次使用(更易于阅读,IMO)。
在安装/卸载时,添加以instlPath
结尾的\;
的存在检查。
在安装过程中,请勿在当前;
中将%PATH%
加倍。
在安装过程中句柄丢失或为空%PATH%
。
在卸载期间,请确保未将起始索引0传递给Delete()
。
这是我的EnvAddPath()
的更新版本:
const EnvironmentKey = 'Environment';
procedure EnvAddPath(instlPath: string);
var
Paths: string;
begin
{ Retrieve current path (use empty string if entry not exists) }
if not RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', Paths) then
Paths := '';
if Paths = '' then
Paths := instlPath + ';'
else
begin
{ Skip if string already found in path }
if Pos(';' + Uppercase(instlPath) + ';', ';' + Uppercase(Paths) + ';') > 0 then exit;
if Pos(';' + Uppercase(instlPath) + '\;', ';' + Uppercase(Paths) + ';') > 0 then exit;
{ Append App Install Path to the end of the path variable }
Log(Format('Right(Paths, 1): [%s]', [Paths[length(Paths)]]));
if Paths[length(Paths)] = ';' then
Paths := Paths + instlPath + ';' { don't double up ';' in env(PATH) }
else
Paths := Paths + ';' + instlPath + ';' ;
end;
{ Overwrite (or create if missing) path environment variable }
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', Paths)
then Log(Format('The [%s] added to PATH: [%s]', [instlPath, Paths]))
else Log(Format('Error while adding the [%s] to PATH: [%s]', [instlPath, Paths]));
end;
以及EnvRemovePath()
的更新版本:
procedure EnvRemovePath(instlPath: string);
var
Paths: string;
P, Offset, DelimLen: Integer;
begin
{ Skip if registry entry not exists }
if not RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', Paths) then
exit;
{ Skip if string not found in path }
DelimLen := 1; { Length(';') }
P := Pos(';' + Uppercase(instlPath) + ';', ';' + Uppercase(Paths) + ';');
if P = 0 then
begin
{ perhaps instlPath lives in Paths, but terminated by '\;' }
DelimLen := 2; { Length('\;') }
P := Pos(';' + Uppercase(instlPath) + '\;', ';' + Uppercase(Paths) + ';');
if P = 0 then exit;
end;
{ Decide where to start string subset in Delete() operation. }
if P = 1 then
Offset := 0
else
Offset := 1;
{ Update path variable }
Delete(Paths, P - Offset, Length(instlPath) + DelimLen);
{ Overwrite path environment variable }
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', Paths)
then Log(Format('The [%s] removed from PATH: [%s]', [instlPath, Paths]))
else Log(Format('Error while removing the [%s] from PATH: [%s]', [instlPath, Paths]));
end;
答案 6 :(得分:0)
如果您可以使用外部 DLL,PathMgr.dll 也可以是一个选项。
有一个 sample .iss script 演示了如何在 Inno Setup 6 或更高版本中使用 DLL。
PathMgr.dll 受 LPGL 许可保护。