如何在运行Inno Setup Installer时修改PATH环境variables?

Inno Setup允许您通过[Registry]部分设置环境variables(通过设置对应于环境variables的registry项)

但是,有时你不只是想设置一个环境variables。 通常情况下,你想修改它。 例如:安装时,可能需要向/从PATH环境variables添加/删除目录。

如何从InnoSetup中修改PATH环境variables?

您提供的registry项中的path是REG_EXPAND_SZtypes的值。 正如[registry]部分的Inno安装文档所述,有一种将元素附加到这些文件的方法:

对于stringexpandszmultisztypes的值,可以在此参数中使用一个名为{olddata}的特殊常量。 {olddata}被replace为registry值的以前的数据。 如果您需要将string附加到现有值(例如{olddata};{app}{olddata}常量可能会很有用。 如果该值不存在或者现有值不是stringtypes,则会默认删除{olddata}常量。

所以要追加到path可能会使用类似于此的registry部分:

 [Registry] Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\foo" 

这会将“C:\ foo”目录追加到path中。

不幸的是,当你第二次安装的时候会重复这个问题,这个问题也应该修复。 带有用Pascal脚本编码的函数的Check参数可用于检查path确实是否需要展开:

 [Registry] Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\foo"; \ Check: NeedsAddPath('C:\foo') 

该函数读取原始path值并检查给定目录是否已包含在其中。 要这样做,它前缀和附加分号字符是用来分隔path中的目录。 为了说明search的目录可能是第一个或最后一个元素,事实上分号字符被预置并附加到原始值:

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

请注意,在将它们作为parameter passing给检查函数之前,您可能需要扩展常量,请参阅文档以获取详细信息。

在卸载过程中从path中删除这个目录可以以类似的方式完成,并作为读者的练习。

您可以在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" 

NeedsAddPath 的答案中的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; 

我有同样的问题,但尽pipe上面的答案,我已经结束了一个自定义的解决scheme,我想分享给你。

首先我创build了两个方法的environment.iss文件 – 一个用于添加path到环境的Pathvariables,第二个删除它:

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

参考: RegQueryStringValueRegWriteStringValue

现在在主.iss文件中,我可以包含这个文件,并监听2个事件(更多关于事件可以在文档中的事件函数部分学习), CurStepChanged在安装后添加path, 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 :安装步骤添加path只有一次(确保安装的可重复性)。

注#2 :卸载步骤只从variables中删除一个path。

奖励 :安装步骤checkbox“添加到PATHvariables”

Inno Setup  - 添加到PATH变量

添加安装步骤checkbox“添加到PATHvariables”[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; 

这是一个完全解决问题的方法,忽略大小写,检查是否存在以\结尾的path,还扩展了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;