Search code examples
javajarenvironment-variablesregistryinno-setup

Inno Setup Compiler create Environment and Use it to run .exe (jar)


I'm trying to make a setup for a little app written in Java. I need to create a Environment Variable (in this case YCS_JAVA) that points to a .dll from jdk-17. I've tried everything that I've found online and nothing works (error: Failed to find JAVA VM). It's an exe made with WinRun4J with a JAR inside. The solution with CMD works but doesn't work as it should. I have another txt file which i read with the jar but the CMD doesn't find it xD The function SetEnvironmentVariable doesn't do anything. The function SetEnvPath creates the Variable but still doesn't work with error "Failed to find Java VM". But if i try to run it manually it works... (with just a double click)

;[Registry]
;Root: HKCU; Subkey: "Environment"; ValueType: string; ValueName: "YCS_JAVA"; ValueData: "C:\Program Files\Java\jdk-17\bin\server\jvm.dll"
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "YCS_JAVA"; ValueData: "C:\Program Files\Java\jdk-17\bin\server\jvm.dll"; AfterInstall: RefreshEnvironment;

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; BeforeInstall: SetEnvPath; Flags: postinstall; 

[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('YCS_JAVA', 'C:\Program Files\Java\jdk-17\bin\server\jvm.dll') then
    MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;

[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;

This is because (I think) the setup execution frame isn't aware of the new Environment Variable. I've tried with [Registry] and with [Code] but I can't make it work. The SetEnvPath function doesn't even create the ENV Variable, idk why. Please help :'(


Solution

  • FINALLY a fix that works:

    Filename: "{cmd}"; Parameters: "/C setx YCS_JAVA ""C:\Program Files\Java\jdk-17\bin\server\jvm.dll"" && set YCS_JAVA=C:\Program Files\Java\jdk-17\bin\server\jvm.dll && START """" ""{app}\{#MyAppExeName}"" & EXIT 1"; \
      Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: postinstall runhidden
    

    I've used setx to save the Env Variable and set for the terminal to know about the new Env Variable and now it finally works!

    EDIT: The exe wasn't able to see other files in the folder that was installed so I've found another way:

    Filename: "{cmd}"; Parameters: "/C setx YCS_JAVA ""C:\Program Files\Java\jdk-17\bin\server\jvm.dll"" && set YCS_JAVA=C:\Program Files\Java\jdk-17\bin\server\jvm.dll && cd {app} & START """" ""{#MyAppExeName}"""; \
      Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: postinstall runhidden