[英]Environment variable not recognized [not available] for [Run] programs in Inno Setup
我有一個 license.exe 文件,最后在我的安裝代碼中調用,
代碼需要設置環境變量才能正常工作,
代碼如下:
[Registry]
; set PATH
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes
[Run]
Filename: "{app}\temp\installation_files\license.exe";
代碼在這里執行,但沒有找到正確的路徑。
當我檢查系統環境變量時,它設置正確,
當我之后手動運行license.exe
代碼時,它可以正常工作並看到環境變量。
有人可以告訴我如何解決這個問題嗎?
或者如何延遲[Run]
部分直到系統識別環境變量?
為執行[Run]
部分中的條目而創建的進程繼承其父進程的環境塊,即安裝程序本身。 因此,您必須為安裝程序設置環境變量,並讓它繼承到您執行的應用程序。 下面的腳本顯示了如何做到這一點:
[Run]
Filename: "{app}\temp\installation_files\license.exe"; BeforeInstall: SetEnvPath
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
external 'SetEnvironmentVariable{#AW}@kernel32.dll stdcall';
procedure SetEnvPath;
begin
if not SetEnvironmentVariable('PATH', ExpandConstant('{app}')) then
MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;
通知系統其余部分有關變量更改的先前答案:
正如@Jerry 在他的評論中指出的那樣,在處理[Run]
部分后會執行有關環境更改的通知。 實際上,這是安裝程序執行的最后一件事。
因此,要在處理[Run]
部分之前通知系統有關環境更改的信息,您需要有一個解決方法。 我將RefreshEnvironment
過程從 Inno Setup 代碼重寫為腳本。 如果您將ChangesEnvironment
指令設置為yes
,則它與執行的功能相同。
在以下腳本中,我刪除了ChangesEnvironment
指令,並從注冊表項的AfterInstall
參數函數中添加了RefreshEnvironment
過程的執行:
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: string; ValueName: "PATH"; ValueData: "{app}"; \
AfterInstall: RefreshEnvironment;
[Run]
Filename: "{app}\temp\installation_files\license.exe";
[Code]
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
WM_SETTINGCHANGE = WM_WININICHANGE;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA@user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
TLama 的答案中帶有SetEnvironmentVariable
的解決方案在許多情況下都是正確的。
但它不適用於帶有runasoriginaluser
標志的[Run]
任務( postinstall
flag所暗示的內容)。 即該變量不會傳播到使用“已完成”頁面上常見的“運行我的程序”復選框運行的應用程序。
原因是runasoriginaluser
的任務由 Inno Setup 安裝程序的未提升的隱藏父進程執行。 SetEnvironmentVariable
將更改安裝程序的環境,但不會更改其父進程。 不幸的是,安裝程序的父進程無法控制(imo)。
作為一種解決方法,要為runasoriginaluser
任務設置變量,您必須在安裝程序父進程和任務之間注入一個中間進程,並讓中間進程設置變量。
這樣的中間過程可以很容易地成為cmd.exe
及其set
命令:
[Run]
Filename: "{cmd}"; Parameters: "/C set PATH=%PATH%;{app} & ""{app}\MyProg.exe"""; \
Description: "Run My Program"; Flags: postinstall runhidden
runhidden
標志隱藏cmd.exe
控制台窗口,而不是應用程序(假設它是一個 GUI 應用程序)。 如果它是一個控制台應用程序並且您希望輸出可見,請刪除runhidden
標志。 或者,您可以使用start
命令在其自己的控制台窗口中啟動應用程序。
經過下面的一些修改,完美運行:
[Run]
Filename: "{app}\{#MyAppExeName}"; BeforeInstall: AppendToPathAndRefresh;Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}";Flags: nowait postinstall shellexec skipifsilent
[Code]
////////////////////////////////////////////////////////////
const
SMTO_ABORTIFHUNG = 2;
WM_WININICHANGE = $001A;
type
WPARAM = UINT_PTR;
LPARAM = INT_PTR;
LRESULT = INT_PTR;
function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: PAnsiChar; fuFlags: UINT;
uTimeout: UINT; out lpdwResult: DWORD): LRESULT;
external 'SendMessageTimeoutA@user32.dll stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_WININICHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
///PATH ENVINRONMENT//////////////////////////////////////////
function Replace(Dest, SubStr, Str: string): string;
var
Position: Integer;
Ok: Integer;
begin
Ok := 1;
while Ok > 0 do
begin
Position:=Pos(SubStr, Dest);
if Position > 0 then
begin
Delete(Dest, Position, Length(SubStr));
Insert(Str, Dest, Position);
end else
Ok := 0;
end;
Result:=Dest;
end;
procedure AppendToPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\libav');
V := Replace(V, Str, '');
V := V + ';' + Str;
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
// MsgBox(V, mbInformation, MB_OK);
end;
procedure RemoveFromPath();
var
V: string;
Str: string;
begin
RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
Str := ExpandConstant('{app}\dlls');
V := Replace(V, Str, '');
V := Replace(V,';;',';');
RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'Path', V)
//MsgBox(V, mbInformation, MB_OK);
end;
procedure AppendToPathAndRefresh;
begin
AppendToPath;
RefreshEnvironment;
end;
procedure DeinitializeUninstall();
begin
RemoveFromPath();
end;
///END OF PATH ENVIRONMENT ///////////////////////////////////
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.