2010-07-21 233 views
54

Inno Setup让您通过[注册表]部分(通过设置与环境变量对应的注册表项)设置环境变量如何在运行Inno Setup Installer时修改PATH环境变量?

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

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

回答

71

您给出的注册表项中的路径是REG_EXPAND_SZ类型的值。至于[注册]部分国家的Inno Setup的文档有附加元素的一种方式:

在一个stringexpandsz,或multisz类型值,你可以使用一个名为{olddata}在特殊常量这个参数。 {olddata}被替换为注册表值的以前的数据。如果需要将字符串附加到现有值,例如{olddata};{app},则{olddata}常数可能很有用。如果该值不存在或者现有值不是字符串类型,则会自动删除{olddata}常量。

所以要追加可使用一个类似的注册表节的路径:

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

这将追加“C:\富”目录的路径。

不幸的是,当你第二次安装时,这将会重复,这也应该被修复。一个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; 

请注意,您可能需要您将它们作为前扩大常数参数的检查功能,请参阅文档的详细信息。

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

+1

如果你能简单地通过'{olddata }'检查函数,所以你不必再次读取代码中的值? (也许你可以 - 我没有尝试过);) – 2011-03-04 13:00:35

+3

另一件事是路径可能在那里,但使用不同的字符大小写(可以使用'UpperCase'或某些函数轻松修复),或者更糟糕的是,使用8.3路径名(例如“C:\ Progra〜1 \ MyProg”)或环境变量(例如“%programfiles%\ MyProg”)。这也是一个噩梦,以及检测到这些... – 2011-03-04 13:03:52

+1

你的程序卸载时怎么办?你将如何从PATH环境变量中删除你的路径? – 2011-12-07 15:42:05

6

NeedsAddPaththe answer by @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; 
+3

如何使用变量而不是'C:\ foo'?我尝试了NeedsAddPath('{app}'),但它不起作用 - 只是连接了路径,尽管它已经退出了。你能建议吗? – 2012-09-21 09:46:14

+1

只是为了回答上述评论,可能对其他人有用:您需要使用'ExpandConstant()'函数。 – Jack 2014-08-01 15:36:14

+0

谢谢杰克。然而,我很想看到一个NeedsAddPath('{app} \ MoreDirectoriesHere')的例子。 – vezenkov 2015-07-30 16:03:06

14

您可以使用LegRoom。净的modpath.iss脚本在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" 
1

这里是忽略外壳,检查与\结束路径存在问题的完整解决方案,并扩大在参数的常量:

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; 
+0

很确定这里有一个问题:只有在找到'''case'的情况下才会检查''\;''case。 – Stewart 2017-08-09 14:48:02

2

我有同样的问题,但尽管上面的答案我已经结束了自定义解决方案,我想与你分享。

所有我创建了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; 

参考:RegQueryStringValueRegWriteStringValue

现在在主.iss文件中,我可以包含此文件并侦听2个事件(有关可在文档中的Event Functions部分中学习的事件的更多信息),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; 
相关问题