运行Inno Setup Installer时如何修改PATH环境变量?

ban*_*ana 60 inno-setup environment-variables

Inno Setup允许您通过[Registry]部分设置环境变量(通过设置对应于环境变量的注册表项)

但是,有时您不只是想设置一个环境变量.通常,你想修改它.例如:安装时,可能需要在PATH环境变量中添加/删除目录.

如何从InnoSetup中修改PATH环境变量?

mgh*_*hie 77

您提供的注册表项中的路径是类型的值REG_EXPAND_SZ.正如[Registry]部分的Inno Setup文档所述,有一种方法可以将元素附加到这些:

在a string,expandszmultisz类型值上,您可以使用{olddata}此参数中调用的特殊常量.{olddata}被替换为注册表值的先前数据.的{olddata},如果你需要一个字符串添加到现有的价值,例如常可能是有用的,{olddata};{app}.如果该值不存在或现有值不是字符串类型,{olddata}则会以静默方式删除该常量.

因此,要附加到路径,可以使用与此类似的注册表部分:

[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
    ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\foo"
Run Code Online (Sandbox Code Playgroud)

将"C:\ foo"目录附加到路径.

不幸的是,当你第二次安装时会重复这个,也应该修复.Check具有以Pascal脚本编码的函数的参数可用于检查路径是否确实需要扩展:

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

此函数读取原始路径值并检查给定目录是否已包含在其中.为此,它会预先添加并附加分号字符,用于分隔路径中的目录.为了解释搜索到的目录可能是第一个或最后一个元素的事实,分号字符前缀并附加到原始值:

[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;
Run Code Online (Sandbox Code Playgroud)

请注意,在将它们作为参数传递给check函数之前,可能需要扩展常量,有关详细信息,请参阅文档.

在卸载过程中从路径中删除此目录可以以类似的方式完成,并留给读者练习.

  • 在`[Setup]`中设置`ChangesEnvironment = yes`,你可以删除重启的要求.[来源](http://stackoverflow.com/questions/10687188/inno-setup-setting-java-environment-variable#comment13898613_10687487) (4认同)
  • 另一件事是路径可能在那里,但使用不同的字符大小写(通过使用`UpperCase`或某些功能很容易修复),或者更糟糕的是,使用8.3路径名(例如"C:\ Progra~1\MyProg")或环境变量(例如"%programfiles%\ MyProg").检测这些也是一场噩梦... (3认同)
  • 我不得不说你用'Pos()`的方式相当巧妙.我会把半冒号的字符串拆分成一个数组,并循环遍历每个字符串.我认为我不会想到这种方法. (3认同)
  • @vee:您是否在参数上尝试过“ExpandConstant()”函数? (3认同)
  • NeedsAddPath 似乎不起作用。它总是添加路径。根:HKLM;子项:“SYSTEM\CurrentControlSet\Control\Session Manager\Environment”;值类型:expandsz;值名称:“路径”;ValueData: "{olddata};{驱动器:c:\}\{#WwwRoot}\php\php5.5"; 检查:NeedsAddPath('{drive:c:\}\{#WwwRoot}\php\php5.5'); 标志:保留字符串类型; (2认同)

ecl*_*cle 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"
Run Code Online (Sandbox Code Playgroud)


小智 12

我有同样的问题,但尽管上面的答案,我最终得到了一个自定义解决方案,我想与你分享.

首先,我environment.iss用2个方法创建了文件 - 一个用于添加环境路径变量的路径,另一个用于删除它:

[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;
Run Code Online (Sandbox Code Playgroud)

参考: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;
Run Code Online (Sandbox Code Playgroud)

参考: ExpandConstant

注意#1:仅安装步骤添加路径一次(确保安装的可重复性).

注意#2:卸载步骤仅从变量中删除一次路径.

奖励:安装步骤,复选框"添加到PATH变量".

Inno设置 - 添加到PATH变量

要添加带有复选框"添加到PATH变量"的安装步骤,请在[Tasks]部分中定义新任务(默认选中):

[Tasks]
Name: envPath; Description: "Add to PATH variable" 
Run Code Online (Sandbox Code Playgroud)

然后你可以在CurStepChanged事件中检查它:

procedure CurStepChanged(CurStep: TSetupStep);
begin
    if (CurStep = ssPostInstall) and IsTaskSelected('envPath')
    then EnvAddPath(ExpandConstant('{app}') +'\bin');
end;
Run Code Online (Sandbox Code Playgroud)


Hel*_*ova 7

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;
Run Code Online (Sandbox Code Playgroud)

  • 如何使用变量而不是'C:\ foo'?我尝试了NeedsAddPath('{app}'),但它不起作用 - 只是连接路径,虽然它已经退出了.你能建议吗? (3认同)

小智 6

我要感谢大家对这个问题的贡献。我已将 Wojciech Mleczek 发布的大约 95% 的代码合并到我的应用程序的安装程序中。我确实对该代码进行了一些更正,可能对其他人有用。我的改变:

  • 将正式参数重命名PathinstlPath. 减少代码中“路径”的多次使用(更易于阅读,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;
Run Code Online (Sandbox Code Playgroud)

以及更新版本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;
Run Code Online (Sandbox Code Playgroud)