2010-07-21 247 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; 
相關問題