Environment variable not recognized [not available] for [Run] programs in Inno Setup
The processes created for executing entries from the [Run]
section inherits the environment block of its parent process, which is the installer itself. So you have to set the environment variable to the installer and let it inherit to your executed application. How to do that is shown in the below script:
[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;
Previous answer for notifying rest of the system about variable change:
As @Jerry pointed out in his comment, a notification about the environment changes is performed after the [Run]
section is processed. Actually, it is one of the last things executed by the installer.
So, to notify the system about environment changes before processing the [Run]
section, you'll need to have a workaround. I rewrote the RefreshEnvironment
procedure from Inno Setup code to script. It's the same function as it's executed if you have ChangesEnvironment
directive set to yes
.
In the following script I have removed the ChangesEnvironment
directive and added execution of the RefreshEnvironment
procedure from the AfterInstall
parameter function of your registry entry:
[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 '[email protected] stdcall';
procedure RefreshEnvironment;
var
S: AnsiString;
MsgResult: DWORD;
begin
S := 'Environment';
SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
PAnsiChar(S), SMTO_ABORTIFHUNG, 5000, MsgResult);
end;
The solution with SetEnvironmentVariable
in TLama's answer is correct for many situations.
But it won't work for [Run]
tasks with runasoriginaluser
flag (what is implied by postinstall
flag). I.e. the variable won't be propagated to an application run with common "Run My Program" check box on the "Finished" page.
The reason is that the tasks with runasoriginaluser
are executed by a un-elevated hidden parent process of the Inno Setup installer. The SetEnvironmentVariable
will change environment for the installer, but not for its parent process. Unfortunately, the parent process of the installer cannot be controlled (imo).
As a workaround, to set the variable for the runasoriginaluser
tasks, you have to inject an intermediate process between the installer parent process and the task, and have the intermediate process set the variable.
Such an intermediate process can easily be the cmd.exe
with its set
command:
[Run]
Filename: "{cmd}"; Parameters: "/C set PATH=%PATH%;{app} & ""{app}\MyProg.exe"""; \
Description: "Run My Program"; Flags: postinstall runhidden
The runhidden
flag hides the cmd.exe
console window, not the application (assuming it's a GUI application). If it's a console application and you want the output to be visible, remove the runhidden
flag. Alternatively, you can use start
command to start the application in its own console window.