簡體   English   中英

Inno Setup 中的 [Run] 程序無法識別環境變量 [不可用]

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM