Fix crash caused by ExpandUNCFileName - fixes #92

Inno Setup version 5 will crash if ExpandUNCFileName is given a path
longer than 259 characters. This has been fixed in Inno 6.

[Code]

{This code section is included into the main script and keeps the
important environment functions separate from it. There should be no need
to change this.}

function ExpandEnvironmentStrings(Src: String; Dst: String; Size: DWord): DWord;
  external 'ExpandEnvironmentStringsW@kernel32.dll stdcall delayload';

function SendMessageTimeout(Hwnd, Msg, WParam: LongInt; LParam: String; Flags, Timeout: LongInt; lpdwResult: DWord): DWord;
  external 'SendMessageTimeoutW@user32.dll stdcall delayload';

function EnvAdd(Hive: Integer; Name, Value: String; Display: Boolean): Integer; forward;
function EnvRemove(Hive: Integer; Name, Value: String; Display: Boolean): Integer; forward;
function AddToPath(Hive: Integer; Value: String): Integer; forward;
function RemoveFromPath(Hive: Integer; Value: String): Integer; forward;
function GetRawPath(Hive: Integer; var Value: String): Boolean; forward;
function SplitPath(Value: String): TArrayOfString; forward;
function GetPathKeyForHive(Hive: Integer): String; forward;
function GetHiveName(Hive: Integer): String; forward;
function GetHiveFriendlyName(Hive: Integer): String; forward;
function NormalizePath(const Value: String): String; forward;
function GetSafePathList(Hive: Integer): TPathList; forward;
function GetSafePath(var PathList: TPathList; Index: Integer): String; forward;
procedure SetPathList(Hive: Integer; const Path: String; var SafeList: TPathList); forward;
function DirectoryInPath(var Directory: String; PathList: TPathList; Hive: Integer): Boolean; forward;
function SearchPath(PathList: TPathList; Hive: Integer; const Cmd: String): String; forward;
function SearchPathEx(PathList: TPathList; Hive: Integer; const Cmd: String; var Index: Integer): String; forward;
procedure DbgEnv(Action, Hive: Integer; Name, Value: String; Display: Boolean); forward;
procedure DbgPath(Action, Hive: Integer; Value: String); forward;
procedure DbgError(Name: String); forward;
procedure NotifyEnvironmentChange; forward;
function NeedsTrailingSeparator: Boolean; forward;

const
  ENV_CHANGED = 0;
  ENV_NONE = 1;
  ENV_FAILED = 2;
  ENV_ADD = 100;
  ENV_REMOVE = 101;

  ENV_KEY_PATH = 'PATH';

function EnvAdd(Hive: Integer; Name, Value: String; Display: Boolean): Integer;
var
  Key: String;
  Existing: String;
  Res: Boolean;

begin

  if CompareText(ENV_KEY_PATH, Name) = 0 then
  begin
    Result := AddToPath(Hive, Value);
    Exit;
  end;

  Key := GetPathKeyForHive(Hive);

  if RegQueryStringValue(Hive, Key, Name, Existing) then
  begin

    if CompareText(Existing, Value) = 0 then
    begin
      Result := ENV_NONE;
      Exit;
    end;
  end;

  DbgEnv(ENV_ADD, Hive, Name, Value, Display);
  Existing := Value;

  {See if we are expandable}
  if StringChangeEx(Existing, '%', '', True) = 2 then
    Res := RegWriteExpandStringValue(Hive, Key, Name, Value)
  else
    Res := RegWriteStringValue(Hive, Key, Name, Value);

  if Res then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(Name);
  end;

end;

function EnvRemove(Hive: Integer; Name, Value: String; Display: Boolean): Integer;
var
  Key: String;

begin

  if CompareText(ENV_KEY_PATH, Name) = 0 then
  begin
    Result := RemoveFromPath(Hive, Value);
    Exit;
  end;

  Key := GetPathKeyForHive(Hive);

  if not RegValueExists(Hive, Key, Name) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  DbgEnv(ENV_REMOVE, Hive, Name, Value, Display);

  if RegDeleteValue(Hive, Key, Name) then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(Name);
  end;

end;

function AddToPath(Hive: Integer; Value: String): Integer;
var
  SafeDirectory: String;
  SafeList: TPathList;
  Key: String;
  Path: String;

begin

  {NormalizePath UNC expands the path and removes any trailing backslash}
  SafeDirectory := NormalizePath(Value);

  {We exit if NormalizePath failed and/or we have no value}
  if SafeDirectory = '' then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Get a list of normalized path entries}
  SafeList := GetSafePathList(Hive);

  {See if our directory is already in the path}
  if DirectoryInPath(SafeDirectory, SafeList, Hive) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  {Get the current path values from registry}
  Key := GetPathKeyForHive(Hive);
  Path := '';
  RegQueryStringValue(Hive, Key, ENV_KEY_PATH, Path);

  DbgPath(ENV_ADD, Hive, SafeDirectory);

  {Add trailing separator to path if required}
  if (Path <> '') and (Path[Length(Path)] <> ';') then
    Path := Path + ';';

  {Add our new value to the path}
  Path := Path + SafeDirectory;

  {Add a trailing separator if required}
  if NeedsTrailingSeparator then
    Path := Path + ';';

  if RegWriteExpandStringValue(Hive, Key, ENV_KEY_PATH, Path) then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(ENV_KEY_PATH);
  end;

end;

function RemoveFromPath(Hive: Integer; Value: String): Integer;
var
  SafeDirectory: String;
  RawList: TArrayOfString;
  Key: String;
  CurrentPath: String;
  NewPath: String;
  I: Integer;
  SafePath: String;
  FoundEntry: Boolean;
  Res: Boolean;

begin

  {NormalizePath UNC expands the path and removes any trailing backslash}
  SafeDirectory := NormalizePath(Value);

  {We exit if NormalizePath failed}
  if SafeDirectory = '' then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Paranoid check to make sure we are not removing a system path - should not happen}
  if Pos(AnsiLowercase(GetSystemDir()), AnsiLowercase(SafeDirectory)) = 1 then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Get the current path values from registry. If we fail, we have not got any}
  Key := GetPathKeyForHive(Hive);
  CurrentPath := '';

  if not GetRawPath(Hive, CurrentPath) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  DbgPath(ENV_REMOVE, Hive, SafeDirectory);

  {Split current path into a list of raw entries}
  RawList := SplitPath(CurrentPath);
  NewPath := '';
  FoundEntry := False;

  for I := 0 to GetArrayLength(RawList) - 1 do
  begin

    {Normalize each raw entry - will be blank if we cannot expand it}
    SafePath := NormalizePath(RawList[I]);

    {Add each raw entry if normalize failed or if it does not match the directory we are removing}
    if (SafePath = '') or (CompareText(SafePath, SafeDirectory) <> 0) then
    begin

      {Add separator if required}
      if NewPath <> '' then
        NewPath := NewPath + ';';

      {Important to add RAW value}
      NewPath := NewPath + RawList[I];

    end
    else
      FoundEntry := True;

  end;

  {See if we found the entry we want to remove}
  if not FoundEntry then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  if (NewPath = '') and (Hive = HKCU) then
    {We have an empty User PATH, so we can delete the subkey}
    Res := RegDeleteValue(Hive, Key, ENV_KEY_PATH)
  else
    {Write the new path (could be empty for HKLM)}
    Res := RegWriteExpandStringValue(Hive, Key, ENV_KEY_PATH, NewPath);

  if Res then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(ENV_KEY_PATH);
  end;

end;

function GetRawPath(Hive: Integer; var Value: String): Boolean;
var
  Key: String;

begin

  Value := '';
  Key := GetPathKeyForHive(Hive);
  Result := RegQueryStringValue(Hive, Key, ENV_KEY_PATH, Value);

end;

function SplitPath(Value: String): TArrayOfString;
var
  Index: Integer;
  Count: Integer;
  Next: Integer;

begin

  Count := 0;
  Next := 0;

  repeat

    Index := Pos(';', Value);

    if Next = Count then
    begin
      Count := Count + 20;
      SetArrayLength(Result, Count);
    end;

    if Index > 0 then
    begin
      Result[Next] := Copy(Value, 1, Index - 1);
      Value := Copy(Value, Index + 1, Length(Value));
    end
    else
    begin
      Result[Next] := Value;
      Value := '';
    end;

    Inc(Next);

  until Length(Value) = 0;

  if Next < Count then
    SetArrayLength(Result, Next);

end;

function GetPathKeyForHive(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
  else
    Result := 'Environment';

end;

function GetHiveName(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'HKLM'
  else
    Result := 'HKCU';

end;

function GetHiveFriendlyName(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'System'
  else
    Result := 'User';

end;

function NormalizePath(const Value: String): String;
var
  Path: String;
  ResSize: DWord;
  Expanded: String;

begin

  Result := '';
  Path := Trim(Value);
  StringChangeEx(Path, '/', '\', True);

  {See if we have any %variables%}
  if Pos('%', Path) <> 0 then
  begin

    Expanded := '';
    ResSize := ExpandEnvironmentStrings(Path, Expanded, 0);

    if ResSize = 0 then
      Exit;

    SetLength(Expanded, ResSize);

    if ExpandEnvironmentStrings(Path, Expanded, ResSize) <> ResSize then
      Exit;

    Path := TrimRight(Expanded);

    {Check for %PATH% or something else that expands to a path-separated list.
    See: https://github.com/composer/windows-setup/issues/92}
    if Pos(';', Path) <> 0 then
      Exit;

  end;

  {Check that we are a suitable path to expand (^[A-Z]:.*), or a UNC name (^\\.*) - not a complete check}
  if (Length(Path) >= 3) and (Path[2] = ':') and (Uppercase(Path[1]) >= 'A') and (Uppercase(Path[1]) <= 'Z') then
  begin
    Path := ExpandUNCFileName(Path);

    {Inno versions < 6 did not handle long paths (> 259 characters) and returned garbage, as per above issue.
    Check any way, otherwise we will crash}
    if Pos(#0, Path) <> 0 then
      Exit;

  end
  else if (Length(Path) < 3) or (Pos('\\', Path) <> 1) then
    Exit;

  Result := RemoveBackslashUnlessRoot(Path);

end;

function GetSafePathList(Hive: Integer): TPathList;
var
  Path: String;

begin

  if not GetRawPath(Hive, Path) then
    Exit;

  SetPathList(Hive, Path, Result);

end;

function GetSafePath(var PathList: TPathList; Index: Integer): String;
begin

  if PathList.Items[Index].Safe then
    Result := PathList.Items[Index].Path
  else
  begin
    Result := NormalizePath(PathList.Items[Index].Path);
    PathList.Items[Index].Safe := True;
  end;

end;

procedure SetPathList(Hive: Integer; const Path: String; var SafeList: TPathList);
var
  RawList: TArrayOfString;
  Next: Integer;
  I: Integer;
  SafePath: String;

begin

  RawList := SplitPath(Path)

  Next := GetArrayLength(SafeList.Items);
  SetArrayLength(SafeList.Items, Next + GetArrayLength(RawList));

  for I := 0 to GetArrayLength(RawList) - 1 do
  begin

    if RawList[I] <> '' then
    begin

      SafePath := NormalizePath(RawList[I]);

      if SafePath <> '' then
      begin
        SafeList.Items[Next].Hive := Hive;
        SafeList.Items[Next].Path := SafePath;
        SafeList.Items[Next].Safe := True;
        Inc(Next);
      end;

    end;

  end;

  SetArrayLength(SafeList.Items, Next);

end;

function DirectoryInPath(var Directory: String; PathList: TPathList; Hive: Integer): Boolean;
var
  I: Integer;
  SafePath: String;

begin

  Result := False;

  Directory := NormalizePath(Directory);

  if Directory = '' then
    Exit;

  for I := 0 to GetArrayLength(PathList.Items) - 1 do
  begin

    if Hive <> PathList.Items[I].Hive then
      Continue;

    SafePath := GetSafePath(PathList, I);

    if (SafePath <> '') and (CompareText(SafePath, Directory) = 0) then
    begin
      Result := True;
      Exit;
    end;

  end;

end;

function SearchPath(PathList: TPathList; Hive: Integer; const Cmd: String): String;
var
  Index: Integer;

begin

  Result := SearchPathEx(PathList, Hive, Cmd, Index);

end;

function SearchPathEx(PathList: TPathList; Hive: Integer; const Cmd: String; var Index: Integer): String;
var
  I: Integer;
  SafePath: String;
  Filename: String;

begin

  Result := '';
  Index := -1;

  for I := 0 to GetArrayLength(PathList.Items) - 1 do
  begin

    if Hive <> PathList.Items[I].Hive then
      Continue;

    SafePath := GetSafePath(PathList, I);

    if SafePath <> '' then
    begin

      Filename := AddBackslash(SafePath) + Cmd;

      if FileExists(Filename) then
      begin
        Result := Filename;
        Index := I;
        Exit;
      end;

    end;

  end;

end;

procedure DbgEnv(Action, Hive: Integer; Name, Value: String; Display: Boolean);
var
  Path: String;
  Prefix: String;

begin

  Path := Format('%s\%s', [GetHiveName(Hive), GetPathKeyForHive(Hive)]);
  Name := Format('%s%s%s', [#39, Name, #39]);

  if Display then
    Value := Format(' with value %s%s%s', [#39, Value, #39])
  else
    Value := '';

  if Action = ENV_ADD then
    Prefix := Format('Adding %s%s to', [Name, Value])
  else
    Prefix := Format('Removing %s%s from', [Name, Value]);

  Debug(Format('%s [%s]', [Prefix, Path]));

end;

procedure DbgError(Name: String);
begin
  Debug(Format('Failed to update %s value', [Name]));
end;

procedure DbgPath(Action, Hive: Integer; Value: String);
var
  Path: String;
  Prefix: String;

begin

  Path := Format('%s\%s\%s', [GetHiveName(Hive), GetPathKeyForHive(Hive), ENV_KEY_PATH]);

  if Action = ENV_ADD then
    Prefix := Format('Adding %s%s%s to', [#39, Value, #39])
  else
    Prefix := Format('Removing %s%s%s from', [#39, Value, #39]);

  Debug(Format('%s [%s]', [Prefix, Path]));

end;

procedure NotifyEnvironmentChange;
var
  Res: DWORD;

begin

  {WM_SETTINGCHANGE = $1A; SMTO_ABORTIFHUNG = $2;}
  SendMessageTimeout(HWND_BROADCAST, $1A, 0, 'Environment', $2, 2000, Res);

end;

{Git for Windows had a bug on versions lower than 1.8.1.0 that only
affects users with cygwin in their path. The code to strip the cygwin
references adds a null-byte to the PATH which means that Posix paths
are inherited by non-msys child processes rather than Windows ones,
and the last path entry becomes unresovable. We can cure the latter
by adding a trailing separator to the path.}
function NeedsTrailingSeparator: Boolean;
var
  Hive: Integer;
  SafeList: TPathList;
  Cmd: String;
  GitExe: String;
  Version: String;

begin

  Result := False;
  Cmd := 'git.exe';

  Hive := HKLM;
  SafeList := GetSafePathList(Hive);
  GitExe := SearchPath(SafeList, Hive, Cmd);

  if GitExe = '' then
  begin
    Hive := HKCU;
    SafeList := GetSafePathList(Hive);
    GitExe := SearchPath(SafeList, Hive, Cmd);
  end;

  if GitExe = '' then
    Exit;

  if StringChangeEx(GitExe, 'cmd', 'bin', True) = 0 then
    Exit;

  if FileExists(GitExe) then
  begin

    Result := True;

    if GetVersionNumbersString(GitExe, Version) then
      Result := CompareStr(Version, '1.8.1.0') < 0;

  end;

end;

[Code]

{This code section is included into the main script and keeps the
important environment functions separate from it. There should be no need
to change this.}

function ExpandEnvironmentStrings(Src: String; Dst: String; Size: DWord): DWord;
  external 'ExpandEnvironmentStringsW@kernel32.dll stdcall delayload';

function SendMessageTimeout(Hwnd, Msg, WParam: LongInt; LParam: String; Flags, Timeout: LongInt; lpdwResult: DWord): DWord;
  external 'SendMessageTimeoutW@user32.dll stdcall delayload';

function EnvAdd(Hive: Integer; Name, Value: String; Display: Boolean): Integer; forward;
function EnvRemove(Hive: Integer; Name, Value: String; Display: Boolean): Integer; forward;
function AddToPath(Hive: Integer; Value: String): Integer; forward;
function RemoveFromPath(Hive: Integer; Value: String): Integer; forward;
function GetRawPath(Hive: Integer; var Value: String): Boolean; forward;
function SplitPath(Value: String): TArrayOfString; forward;
function GetPathKeyForHive(Hive: Integer): String; forward;
function GetHiveName(Hive: Integer): String; forward;
function GetHiveFriendlyName(Hive: Integer): String; forward;
function NormalizePath(const Value: String): String; forward;
function GetSafePathList(Hive: Integer): TPathList; forward;
function GetSafePath(var PathList: TPathList; Index: Integer): String; forward;
procedure SetPathList(Hive: Integer; const Path: String; var SafeList: TPathList); forward;
function DirectoryInPath(var Directory: String; PathList: TPathList; Hive: Integer): Boolean; forward;
function SearchPath(PathList: TPathList; Hive: Integer; const Cmd: String): String; forward;
function SearchPathEx(PathList: TPathList; Hive: Integer; const Cmd: String; var Index: Integer): String; forward;
procedure DbgEnv(Action, Hive: Integer; Name, Value: String; Display: Boolean); forward;
procedure DbgPath(Action, Hive: Integer; Value: String); forward;
procedure DbgError(Name: String); forward;
procedure NotifyEnvironmentChange; forward;
function NeedsTrailingSeparator: Boolean; forward;

const
  ENV_CHANGED = 0;
  ENV_NONE = 1;
  ENV_FAILED = 2;
  ENV_ADD = 100;
  ENV_REMOVE = 101;

  ENV_KEY_PATH = 'PATH';

function EnvAdd(Hive: Integer; Name, Value: String; Display: Boolean): Integer;
var
  Key: String;
  Existing: String;
  Res: Boolean;

begin

  if CompareText(ENV_KEY_PATH, Name) = 0 then
  begin
    Result := AddToPath(Hive, Value);
    Exit;
  end;

  Key := GetPathKeyForHive(Hive);

  if RegQueryStringValue(Hive, Key, Name, Existing) then
  begin

    if CompareText(Existing, Value) = 0 then
    begin
      Result := ENV_NONE;
      Exit;
    end;
  end;

  DbgEnv(ENV_ADD, Hive, Name, Value, Display);
  Existing := Value;

  {See if we are expandable}
  if StringChangeEx(Existing, '%', '', True) = 2 then
    Res := RegWriteExpandStringValue(Hive, Key, Name, Value)
  else
    Res := RegWriteStringValue(Hive, Key, Name, Value);

  if Res then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(Name);
  end;

end;

function EnvRemove(Hive: Integer; Name, Value: String; Display: Boolean): Integer;
var
  Key: String;

begin

  if CompareText(ENV_KEY_PATH, Name) = 0 then
  begin
    Result := RemoveFromPath(Hive, Value);
    Exit;
  end;

  Key := GetPathKeyForHive(Hive);

  if not RegValueExists(Hive, Key, Name) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  DbgEnv(ENV_REMOVE, Hive, Name, Value, Display);

  if RegDeleteValue(Hive, Key, Name) then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(Name);
  end;

end;

function AddToPath(Hive: Integer; Value: String): Integer;
var
  SafeDirectory: String;
  SafeList: TPathList;
  Key: String;
  Path: String;

begin

  {NormalizePath UNC expands the path and removes any trailing backslash}
  SafeDirectory := NormalizePath(Value);

  {We exit if NormalizePath failed and/or we have no value}
  if SafeDirectory = '' then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Get a list of normalized path entries}
  SafeList := GetSafePathList(Hive);

  {See if our directory is already in the path}
  if DirectoryInPath(SafeDirectory, SafeList, Hive) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  {Get the current path values from registry}
  Key := GetPathKeyForHive(Hive);
  Path := '';
  RegQueryStringValue(Hive, Key, ENV_KEY_PATH, Path);

  DbgPath(ENV_ADD, Hive, SafeDirectory);

  {Add trailing separator to path if required}
  if (Path <> '') and (Path[Length(Path)] <> ';') then
    Path := Path + ';';

  {Add our new value to the path}
  Path := Path + SafeDirectory;

  {Add a trailing separator if required}
  if NeedsTrailingSeparator then
    Path := Path + ';';

  if RegWriteExpandStringValue(Hive, Key, ENV_KEY_PATH, Path) then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(ENV_KEY_PATH);
  end;

end;

function RemoveFromPath(Hive: Integer; Value: String): Integer;
var
  SafeDirectory: String;
  RawList: TArrayOfString;
  Key: String;
  CurrentPath: String;
  NewPath: String;
  I: Integer;
  SafePath: String;
  FoundEntry: Boolean;
  Res: Boolean;

begin

  {NormalizePath UNC expands the path and removes any trailing backslash}
  SafeDirectory := NormalizePath(Value);

  {We exit if NormalizePath failed}
  if SafeDirectory = '' then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Paranoid check to make sure we are not removing a system path - should not happen}
  if Pos(AnsiLowercase(GetSystemDir()), AnsiLowercase(SafeDirectory)) = 1 then
  begin
    Result := ENV_FAILED;
    Exit;
  end;

  {Get the current path values from registry. If we fail, we have not got any}
  Key := GetPathKeyForHive(Hive);
  CurrentPath := '';

  if not GetRawPath(Hive, CurrentPath) then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  DbgPath(ENV_REMOVE, Hive, SafeDirectory);

  {Split current path into a list of raw entries}
  RawList := SplitPath(CurrentPath);
  NewPath := '';
  FoundEntry := False;

  for I := 0 to GetArrayLength(RawList) - 1 do
  begin

    {Normalize each raw entry - will be blank if we cannot expand it}
    SafePath := NormalizePath(RawList[I]);

    {Add each raw entry if normalize failed or if it does not match the directory we are removing}
    if (SafePath = '') or (CompareText(SafePath, SafeDirectory) <> 0) then
    begin

      {Add separator if required}
      if NewPath <> '' then
        NewPath := NewPath + ';';

      {Important to add RAW value}
      NewPath := NewPath + RawList[I];

    end
    else
      FoundEntry := True;

  end;

  {See if we found the entry we want to remove}
  if not FoundEntry then
  begin
    Result := ENV_NONE;
    Exit;
  end;

  if (NewPath = '') and (Hive = HKCU) then
    {We have an empty User PATH, so we can delete the subkey}
    Res := RegDeleteValue(Hive, Key, ENV_KEY_PATH)
  else
    {Write the new path (could be empty for HKLM)}
    Res := RegWriteExpandStringValue(Hive, Key, ENV_KEY_PATH, NewPath);

  if Res then
    Result := ENV_CHANGED
  else
  begin
    Result := ENV_FAILED;
    DbgError(ENV_KEY_PATH);
  end;

end;

function GetRawPath(Hive: Integer; var Value: String): Boolean;
var
  Key: String;

begin

  Value := '';
  Key := GetPathKeyForHive(Hive);
  Result := RegQueryStringValue(Hive, Key, ENV_KEY_PATH, Value);

end;

function SplitPath(Value: String): TArrayOfString;
var
  Index: Integer;
  Count: Integer;
  Next: Integer;

begin

  Count := 0;
  Next := 0;

  repeat

    Index := Pos(';', Value);

    if Next = Count then
    begin
      Count := Count + 20;
      SetArrayLength(Result, Count);
    end;

    if Index > 0 then
    begin
      Result[Next] := Copy(Value, 1, Index - 1);
      Value := Copy(Value, Index + 1, Length(Value));
    end
    else
    begin
      Result[Next] := Value;
      Value := '';
    end;

    Inc(Next);

  until Length(Value) = 0;

  if Next < Count then
    SetArrayLength(Result, Next);

end;

function GetPathKeyForHive(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
  else
    Result := 'Environment';

end;

function GetHiveName(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'HKLM'
  else
    Result := 'HKCU';

end;

function GetHiveFriendlyName(Hive: Integer): String;
begin

  if Hive = HKLM then
    Result := 'System'
  else
    Result := 'User';

end;

function NormalizePath(const Value: String): String;
var
  Path: String;
  ResSize: DWord;
  Expanded: String;

begin

  Result := '';
  Path := Trim(Value);
  StringChangeEx(Path, '/', '\', True);

  {See if we have any %variables%}
  if Pos('%', Path) <> 0 then
  begin

    Expanded := '';
    ResSize := ExpandEnvironmentStrings(Path, Expanded, 0);

    if ResSize = 0 then
      Exit;

    SetLength(Expanded, ResSize);

    if ExpandEnvironmentStrings(Path, Expanded, ResSize) = ResSize then
      Path := TrimRight(Expanded)
    else
      Exit;

  end;

  {Check that we are a suitable path to expand, or a UNC name - not a complete check}
  if (Length(Path) >= 3) and (Path[2] = ':') and (Uppercase(Path[1]) >= 'A') and (Uppercase(Path[1]) <= 'Z') then
    Path := ExpandUNCFileName(Path)
  else if (Length(Path) < 3) or (Pos('\\', Path) <> 1) then
    Exit;

  Result := RemoveBackslashUnlessRoot(Path);

end;

function GetSafePathList(Hive: Integer): TPathList;
var
  Path: String;

begin

  if not GetRawPath(Hive, Path) then
    Exit;

  SetPathList(Hive, Path, Result);

end;

function GetSafePath(var PathList: TPathList; Index: Integer): String;
begin

  if PathList.Items[Index].Safe then
    Result := PathList.Items[Index].Path
  else
  begin
    Result := NormalizePath(PathList.Items[Index].Path);
    PathList.Items[Index].Safe := True;
  end;

end;

procedure SetPathList(Hive: Integer; const Path: String; var SafeList: TPathList);
var
  RawList: TArrayOfString;
  Next: Integer;
  I: Integer;
  SafePath: String;

begin

  RawList := SplitPath(Path)

  Next := GetArrayLength(SafeList.Items);
  SetArrayLength(SafeList.Items, Next + GetArrayLength(RawList));

  for I := 0 to GetArrayLength(RawList) - 1 do
  begin

    if RawList[I] <> '' then
    begin

      SafePath := NormalizePath(RawList[I]);

      if SafePath <> '' then
      begin
        SafeList.Items[Next].Hive := Hive;
        SafeList.Items[Next].Path := SafePath;
        SafeList.Items[Next].Safe := True;
        Inc(Next);
      end;

    end;

  end;

  SetArrayLength(SafeList.Items, Next);

end;

function DirectoryInPath(var Directory: String; PathList: TPathList; Hive: Integer): Boolean;
var
  I: Integer;
  SafePath: String;

begin

  Result := False;

  Directory := NormalizePath(Directory);

  if Directory = '' then
    Exit;

  for I := 0 to GetArrayLength(PathList.Items) - 1 do
  begin

    if Hive <> PathList.Items[I].Hive then
      Continue;

    SafePath := GetSafePath(PathList, I);

    if (SafePath <> '') and (CompareText(SafePath, Directory) = 0) then
    begin
      Result := True;
      Exit;
    end;

  end;

end;

function SearchPath(PathList: TPathList; Hive: Integer; const Cmd: String): String;
var
  Index: Integer;

begin

  Result := SearchPathEx(PathList, Hive, Cmd, Index);

end;

function SearchPathEx(PathList: TPathList; Hive: Integer; const Cmd: String; var Index: Integer): String;
var
  I: Integer;
  SafePath: String;
  Filename: String;

begin

  Result := '';
  Index := -1;

  for I := 0 to GetArrayLength(PathList.Items) - 1 do
  begin

    if Hive <> PathList.Items[I].Hive then
      Continue;

    SafePath := GetSafePath(PathList, I);

    if SafePath <> '' then
    begin

      Filename := AddBackslash(SafePath) + Cmd;

      if FileExists(Filename) then
      begin
        Result := Filename;
        Index := I;
        Exit;
      end;

    end;

  end;

end;

procedure DbgEnv(Action, Hive: Integer; Name, Value: String; Display: Boolean);
var
  Path: String;
  Prefix: String;

begin

  Path := Format('%s\%s', [GetHiveName(Hive), GetPathKeyForHive(Hive)]);
  Name := Format('%s%s%s', [#39, Name, #39]);

  if Display then
    Value := Format(' with value %s%s%s', [#39, Value, #39])
  else
    Value := '';

  if Action = ENV_ADD then
    Prefix := Format('Adding %s%s to', [Name, Value])
  else
    Prefix := Format('Removing %s%s from', [Name, Value]);

  Debug(Format('%s [%s]', [Prefix, Path]));

end;

procedure DbgError(Name: String);
begin
  Debug(Format('Failed to update %s value', [Name]));
end;

procedure DbgPath(Action, Hive: Integer; Value: String);
var
  Path: String;
  Prefix: String;

begin

  Path := Format('%s\%s\%s', [GetHiveName(Hive), GetPathKeyForHive(Hive), ENV_KEY_PATH]);

  if Action = ENV_ADD then
    Prefix := Format('Adding %s%s%s to', [#39, Value, #39])
  else
    Prefix := Format('Removing %s%s%s from', [#39, Value, #39]);

  Debug(Format('%s [%s]', [Prefix, Path]));

end;

procedure NotifyEnvironmentChange;
var
  Res: DWORD;

begin

  {WM_SETTINGCHANGE = $1A; SMTO_ABORTIFHUNG = $2;}
  SendMessageTimeout(HWND_BROADCAST, $1A, 0, 'Environment', $2, 2000, Res);

end;

{Git for Windows had a bug on versions lower than 1.8.1.0 that only
affects users with cygwin in their path. The code to strip the cygwin
references adds a null-byte to the PATH which means that Posix paths
are inherited by non-msys child processes rather than Windows ones,
and the last path entry becomes unresovable. We can cure the latter
by adding a trailing separator to the path.}
function NeedsTrailingSeparator: Boolean;
var
  Hive: Integer;
  SafeList: TPathList;
  Cmd: String;
  GitExe: String;
  Version: String;

begin

  Result := False;
  Cmd := 'git.exe';

  Hive := HKLM;
  SafeList := GetSafePathList(Hive);
  GitExe := SearchPath(SafeList, Hive, Cmd);

  if GitExe = '' then
  begin
    Hive := HKCU;
    SafeList := GetSafePathList(Hive);
    GitExe := SearchPath(SafeList, Hive, Cmd);
  end;

  if GitExe = '' then
    Exit;

  if StringChangeEx(GitExe, 'cmd', 'bin', True) = 0 then
    Exit;

  if FileExists(GitExe) then
  begin

    Result := True;

    if GetVersionNumbersString(GitExe, Version) then
      Result := CompareStr(Version, '1.8.1.0') < 0;

  end;

end;


Fix for MW5CORE-202

Fix for MW5CORE-202

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "MapWinGIS"
#define MyAppVersion "4.9.5.0"
#define MyAppPublisher "MapWindow Open Source GIS Community"
#define MyAppURL "http://www.mapwindow.org"
#define SetupLocation "D:\dev\MapwinGIS\GitHub\src\InnoSetup"
#define BinLocation "D:\dev\MapwinGIS\GitHub\src\bin"
;; #define x64BitVersion

#ifdef x64BitVersion
  #define CPU "x64"
  #define vcredist "vcredist_x64_2013.exe"
  #define MySourceDir BinLocation + "\x64\"
  #define SystemFlag "64bit"
#else
  #define CPU "Win32"
  #define vcredist "vcredist_x86-2013.exe"
  #define MySourceDir BinLocation + "\Win32\"
  #define SystemFlag "32bit"
#endif

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{C31CF8C2-B385-460A-9533-5C92B457D4C2}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=C:\dev\{#MyAppName}
DisableProgramGroupPage=yes
DefaultGroupName={#MyAppName}
LicenseFile={#BinLocation}\Licenses\MapWinGISLicense.rtf
InfoBeforeFile={#SetupLocation}\ReleaseNotes.rtf
OutputDir={#SetupLocation}
OutputBaseFilename=MapWinGIS-only-v{#MyAppVersion}-{#CPU}
SetupIconFile={#SetupLocation}\MapWindow.ico
Compression=lzma
SolidCompression=yes
WizardImageFile={#SetupLocation}\WizImage-MW.bmp
WizardSmallImageFile={#SetupLocation}\WizSmallImage-MW.bmp
AppCopyright={#MyAppPublisher}
PrivilegesRequired=admin
MinVersion=0,5.01sp3
ChangesEnvironment=yes
AlwaysShowDirOnReadyPage=True
EnableDirDoesntExistWarning=True
;; UninstallDisplayName=MapWinGIS uninstall
CompressionThreads=2
LZMANumBlockThreads=2
UninstallDisplayIcon={uninstallexe}
AppComments=This package will install {#MyAppName} {#MyAppVersion}
AppContact=Paul Meems (info@mapwindow.nl)
VersionInfoCompany=MapWindow Open Source GIS Team [www.mapwindow.org]
VersionInfoCopyright=Mozilla Public License (MPL) 1.1
VersionInfoDescription=MapWindow Open Source GIS [www.mapwindow.org]
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
#ifdef x64BitVersion
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
#endif

[Files]
Source: "{#MySourceDir}\*.dll"; DestDir: "{app}"; Flags: ignoreversion {#SystemFlag}; Components: MapWinGIS_Core; Excludes: "libecwj2.dll"
Source: "{#MySourceDir}\MapWinGIS.ocx"; DestDir: "{app}"; Flags: ignoreversion {#SystemFlag}; Components: MapWinGIS_Core
;; IntelliSense:
Source: "{#SetupLocation}\AxInterop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#SetupLocation}\Interop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;; Licenses
Source: "{#BinLocation}\Licenses\GDALLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#BinLocation}\Licenses\GISInternalsLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#BinLocation}\Licenses\MapWinGISLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\FileGDBLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\FITSLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\HDF4License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\HDF5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\OCILicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\SZIPLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;; GDAL Plugins:
Source: "{#MySourceDir}\gdalplugins\gdal_ECW_JP2ECW.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion recursesubdirs createallsubdirs {#SystemFlag}; Components: ECW
Source: "{#BinLocation}\Licenses\ECW5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: ECW
Source: "{#MySourceDir}\gdalplugins\gdal_MrSID.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: MrSID
Source: "{#BinLocation}\Licenses\MRSIDLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MrSID
Source: "{#MySourceDir}\gdalplugins\gdal_netCDF.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: NetCDF
Source: "{#BinLocation}\Licenses\NetCDFLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: NetCDF
Source: "{#MySourceDir}\gdalplugins\gdal_HDF5.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF5
Source: "{#MySourceDir}\gdalplugins\gdal_HDF5Image.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF5
Source: "{#BinLocation}\Licenses\HDF5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: HDF5
;;Source: "{#MySourceDir}\gdalplugins\gdal_HDF4.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF4
;;Source: "{#MySourceDir}\gdalplugins\gdal_HDF4Image.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF4
;;Source: "{#BinLocation}\Licenses\HDF4License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: HDF4

;; GDAL data
Source: "{#MySourceDir}\gdal-data\*"; DestDir: "{app}\gdal-data"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MapWinGIS_Core
Source: "{#BinLocation}\PROJ_NAD\*"; DestDir: "{app}\PROJ_NAD"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MapWinGIS_Core

;; To register the ocx:
Source: "{#SetupLocation}\regMapWinGIS.cmd"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#SetupLocation}\unregMapWinGIS.cmd"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;;Source: "{#SetupLocation}\SetEnv.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;; VC++ files
Source: "{#SetupLocation}\{#vcredist}"; DestDir: "{tmp}"; Flags: deleteafterinstall ignoreversion {#SystemFlag};
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Messages]
BeveledLabel=MapWinGIS Open Source ActiveX Map Control

[Components]
Name: "MapWinGIS_Core"; Description: "Core files for MapWinGIS"; Types: full custom compact; Flags: fixed
Name: "NetCDF"; Description: "Add NetCDF support"; Types: full custom
Name: "ECW"; Description: "Add ECW & JPEG2000 support"; Types: full custom
Name: "MrSID"; Description: "Add MrSID support"; Types: full custom
;; Name: "HDF4"; Description: "Add Hierarchical Data Format Release 4 support"; Types: full custom
Name: "HDF5"; Description: "Add Hierarchical Data Format Release 5 support"; Types: full custom

[Run]
; Install VC++ 2012 if needed:
#ifdef x64BitVersion
Filename: "{tmp}\{#vcredist}"; Parameters: "/quiet"; Flags: waituntilterminated; Check: VCRedistNeedsInstall_x64()
#else
Filename: "{tmp}\{#vcredist}"; Parameters: "/quiet"; Flags: waituntilterminated; Check: VCRedistNeedsInstall_x86()
#endif
;Run some command files:
Filename: "{app}\regMapWinGIS.cmd"; WorkingDir: "{app}"; Flags: runhidden
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/getting_started.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGvInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Go to the online documentation"
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/MapWindow49.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Read about the future of MapWinGIS/MapWindow v5"
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/version_history.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Read about the changes in this version"

[UninstallRun]
Filename: "{app}\unregMapWinGIS.cmd"; WorkingDir: "{app}"; Flags: runhidden

[Registry]
;; Add location of MapWinGIS to path, needed for netcdf.dll
;; Root: "HKLM"; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: "expandsz"; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: NeedsAddPath(ExpandConstant('{app}'))

[InstallDelete]
;; Old ECW driver, conflicts with new driver:
Type: files; Name: "{app}\libecwj2.dll"; Components: MapWinGIS_Core

[Code]
#IFDEF UNICODE
  #DEFINE AW "W"
#ELSE
  #DEFINE AW "A"
#ENDIF
type
  INSTALLSTATE = Longint;
const
  INSTALLSTATE_INVALIDARG = -2;  // An invalid parameter was passed to the function.
  INSTALLSTATE_UNKNOWN = -1;     // The product is neither advertised or installed.
  INSTALLSTATE_ADVERTISED = 1;   // The product is advertised but not installed.
  INSTALLSTATE_ABSENT = 2;       // The product is installed for a different user.
  INSTALLSTATE_DEFAULT = 5;      // The product is installed for the current user.

  VC_2008_REDIST_X86 = '{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}';
  VC_2008_REDIST_X64 = '{350AA351-21FA-3270-8B7A-835434E766AD}';
  VC_2008_REDIST_IA64 = '{2B547B43-DB50-3139-9EBE-37D419E0F5FA}';
  VC_2008_SP1_REDIST_X86 = '{9A25302D-30C0-39D9-BD6F-21E6EC160475}';
  VC_2008_SP1_REDIST_X64 = '{8220EEFE-38CD-377E-8595-13398D740ACE}';
  VC_2008_SP1_REDIST_IA64 = '{5827ECE1-AEB0-328E-B813-6FC68622C1F9}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_X86 = '{1F1C2DFC-2D24-3E06-BCB8-725134ADF989}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_X64 = '{4B6C7001-C7D6-3710-913E-5BC23FCE91E6}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_IA64 = '{977AD349-C2A8-39DD-9273-285C08987C7B}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_X86 = '{9BE518E6-ECC6-35A9-88E4-87755C07200F}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_X64 = '{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_IA64 = '{515643D1-4E9E-342F-A75A-D1F16448DC04}';

  VC_2010_REDIST_X86 = '{196BB40D-1578-3D01-B289-BEFC77A11A1E}';
  VC_2010_REDIST_X64 = '{DA5E371C-6333-3D8A-93A4-6FD5B20BCC6E}';
  VC_2010_REDIST_IA64 = '{C1A35166-4301-38E9-BA67-02823AD72A1B}';
  VC_2010_SP1_REDIST_X86 = '{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}';
  VC_2010_SP1_REDIST_X64 = '{1D8E6291-B0D5-35EC-8441-6616F567A0F7}';
  VC_2010_SP1_REDIST_IA64 = '{88C73C1C-2DE5-3B01-AFB8-B46EF4AB41CD}';

  // http://stackoverflow.com/questions/27582762/inno-setup-for-visual-c-redistributable-package-for-visual-studio-2013
  VC_2013_REDIST_X86 = '{13A4EE12-23EA-3371-91EE-EFB36DDFFF3E}'; //Microsoft.VS.VC_RuntimeMinimumVSU_x86,v12
  VC_2013_REDIST_X64 = '{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}'; //Microsoft.VS.VC_RuntimeMinimumVSU_amd64,v12

function MsiQueryProductState(szProduct: string): INSTALLSTATE;
  external 'MsiQueryProductState{#AW}@msi.dll stdcall';

function VCVersionInstalled(const ProductID: string): Boolean;
begin
  Result := MsiQueryProductState(ProductID) = INSTALLSTATE_DEFAULT;
end;

function VCRedistNeedsInstall_x86(): Boolean;
begin
  // here the Result must be True when you need to install your VCRedist
  // or False when you don't need to, so now it's upon you how you build
  // this statement, the following won't install your VC redist only when
  // the Visual C++ 2008 Redist (x86) and Visual C++ 2008 SP1 Redist(x86)
  // are installed for the current user
  Result := not (VCVersionInstalled(VC_2013_REDIST_X86));
end;

function VCRedistNeedsInstall_x64(): Boolean;
begin
  // here the Result must be True when you need to install your VCRedist
  // or False when you don't need to, so now it's upon you how you build
  // this statement, the following won't install your VC redist only when
  // the Visual C++ 2008 Redist (x86) and Visual C++ 2008 SP1 Redist(x86)
  // are installed for the current user
  Result := not (VCVersionInstalled(VC_2013_REDIST_X64));
end;

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;

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "afrikaans"; MessagesFile: "compiler:Languages\Afrikaans.isl"
Name: "albanian"; MessagesFile: "compiler:Languages\Albanian.isl"
Name: "arabic"; MessagesFile: "compiler:Languages\Arabic.isl"
Name: "basque"; MessagesFile: "compiler:Languages\Basque.isl"
Name: "belarusian"; MessagesFile: "compiler:Languages\Belarusian.isl"
Name: "bosnian"; MessagesFile: "compiler:Languages\Bosnian.isl"
Name: "brazilianportuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
Name: "bulgarian"; MessagesFile: "compiler:Languages\Bulgarian.isl"
Name: "catalan"; MessagesFile: "compiler:Languages\Catalan.isl"
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
Name: "chinesetrad"; MessagesFile: "compiler:Languages\ChineseTraditional.isl"
Name: "corsican"; MessagesFile: "compiler:Languages\Corsican.isl"
Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl"
Name: "danish"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "estonian"; MessagesFile: "compiler:Languages\Estonian.isl"
Name: "finnish"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
Name: "galician"; MessagesFile: "compiler:Languages\Galician.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "greek"; MessagesFile: "compiler:Languages\Greek.isl"
Name: "hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl"
Name: "hungarian"; MessagesFile: "compiler:Languages\Hungarian.isl"
Name: "icelandic"; MessagesFile: "compiler:Languages\Icelandic.isl"
Name: "indonesian"; MessagesFile: "compiler:Languages\Indonesian.isl"
Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
Name: "lithuanian"; MessagesFile: "compiler:Languages\Lithuanian.isl"
Name: "luxemburgish"; MessagesFile: "compiler:Languages\Luxemburgish.isl"
Name: "macedonian"; MessagesFile: "compiler:Languages\Macedonian.isl"
Name: "malaysian"; MessagesFile: "compiler:Languages\Malaysian.isl"
;;Name: "nepali"; MessagesFile: "compiler:Languages\Nepali.islu"
Name: "norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl"
Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl"
Name: "romanian"; MessagesFile: "compiler:Languages\Romanian.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "serbiancyrillic"; MessagesFile: "compiler:Languages\SerbianCyrillic.isl"
Name: "serbianlatin"; MessagesFile: "compiler:Languages\SerbianLatin.isl"
Name: "slovak"; MessagesFile: "compiler:Languages\Slovak.isl"
Name: "slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "swedish"; MessagesFile: "compiler:Languages\Swedish.isl"
Name: "tatarish"; MessagesFile: "compiler:Languages\Tatar.isl"
Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl"
Name: "ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl"

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "MapWinGIS"
#define MyAppVersion "4.9.5.0"
#define MyAppPublisher "MapWindow Open Source GIS Community"
#define MyAppURL "http://www.mapwindow.org"
#define SetupLocation "D:\dev\MapwinGIS\GitHub\src\InnoSetup"
#define BinLocation "D:\dev\MapwinGIS\GitHub\src\bin"
#define x64BitVersion

#ifdef x64BitVersion
  #define CPU "x64"
  #define vcredist "vcredist_x64_2013.exe"
  #define MySourceDir BinLocation + "\x64\"
  #define SystemFlag "64bit"
#else
  #define CPU "Win32"
  #define vcredist "vcredist_x86-2013.exe"
  #define MySourceDir BinLocation + "\Win32\"
  #define SystemFlag "32bit"
#endif

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{C31CF8C2-B385-460A-9533-5C92B457D4C2}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=C:\dev\{#MyAppName}
DisableProgramGroupPage=yes
DefaultGroupName={#MyAppName}
LicenseFile={#BinLocation}\Licenses\MapWinGISLicense.rtf
InfoBeforeFile={#SetupLocation}\ReleaseNotes.rtf
OutputDir={#SetupLocation}
OutputBaseFilename=MapWinGIS-only-v{#MyAppVersion}-{#CPU}
SetupIconFile={#SetupLocation}\MapWindow.ico
Compression=lzma
SolidCompression=yes
WizardImageFile={#SetupLocation}\WizImage-MW.bmp
WizardSmallImageFile={#SetupLocation}\WizSmallImage-MW.bmp
AppCopyright={#MyAppPublisher}
PrivilegesRequired=admin
MinVersion=0,5.01sp3
ChangesEnvironment=yes
AlwaysShowDirOnReadyPage=True
EnableDirDoesntExistWarning=True
;; UninstallDisplayName=MapWinGIS uninstall
CompressionThreads=2
LZMANumBlockThreads=2
UninstallDisplayIcon={uninstallexe}
AppComments=This package will install {#MyAppName} {#MyAppVersion}
AppContact=Paul Meems (info@mapwindow.nl)
VersionInfoCompany=MapWindow Open Source GIS Team [www.mapwindow.org]
VersionInfoCopyright=Mozilla Public License (MPL) 1.1
VersionInfoDescription=MapWindow Open Source GIS [www.mapwindow.org]
VersionInfoProductName={#MyAppName}
VersionInfoProductVersion={#MyAppVersion}
#ifdef x64BitVersion
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
#endif

[Files]
Source: "{#MySourceDir}\*.dll"; DestDir: "{app}"; Flags: ignoreversion {#SystemFlag}; Components: MapWinGIS_Core; Excludes: "libecwj2.dll"
Source: "{#MySourceDir}\MapWinGIS.ocx"; DestDir: "{app}"; Flags: ignoreversion {#SystemFlag}; Components: MapWinGIS_Core
;; IntelliSense:
Source: "{#SetupLocation}\AxInterop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#SetupLocation}\Interop.MapWinGIS.XML"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;; Licenses
Source: "{#BinLocation}\Licenses\GDALLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#BinLocation}\Licenses\GISInternalsLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#BinLocation}\Licenses\MapWinGISLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\FileGDBLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\FITSLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\HDF4License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\HDF5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\OCILicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;Source: "Licenses\SZIPLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MapWinGIS_Core
;; GDAL Plugins:
Source: "{#MySourceDir}\gdalplugins\gdal_ECW_JP2ECW.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion recursesubdirs createallsubdirs {#SystemFlag}; Components: ECW
Source: "{#BinLocation}\Licenses\ECW5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: ECW
Source: "{#MySourceDir}\gdalplugins\gdal_MrSID.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: MrSID
Source: "{#BinLocation}\Licenses\MRSIDLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: MrSID
Source: "{#MySourceDir}\gdalplugins\gdal_netCDF.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: NetCDF
Source: "{#BinLocation}\Licenses\NetCDFLicense.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: NetCDF
Source: "{#MySourceDir}\gdalplugins\gdal_HDF5.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF5
Source: "{#MySourceDir}\gdalplugins\gdal_HDF5Image.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF5
Source: "{#BinLocation}\Licenses\HDF5License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: HDF5
;;Source: "{#MySourceDir}\gdalplugins\gdal_HDF4.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF4
;;Source: "{#MySourceDir}\gdalplugins\gdal_HDF4Image.dll"; DestDir: "{app}\gdalplugins\"; Flags: ignoreversion {#SystemFlag}; Components: HDF4
;;Source: "{#BinLocation}\Licenses\HDF4License.rtf"; DestDir: "{app}\Licenses\"; Flags: ignoreversion; Components: HDF4

;; GDAL data
Source: "{#MySourceDir}\gdal-data\*"; DestDir: "{app}\gdal-data"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MapWinGIS_Core
Source: "{#BinLocation}\PROJ_NAD\*"; DestDir: "{app}\PROJ_NAD"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MapWinGIS_Core

;; To register the ocx:
Source: "{#SetupLocation}\regMapWinGIS.cmd"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
Source: "{#SetupLocation}\unregMapWinGIS.cmd"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;;Source: "{#SetupLocation}\SetEnv.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: MapWinGIS_Core
;; VC++ files
Source: "{#SetupLocation}\{#vcredist}"; DestDir: "{tmp}"; Flags: deleteafterinstall ignoreversion {#SystemFlag};
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Messages]
BeveledLabel=MapWinGIS Open Source ActiveX Map Control

[Components]
Name: "MapWinGIS_Core"; Description: "Core files for MapWinGIS"; Types: full custom compact; Flags: fixed
Name: "NetCDF"; Description: "Add NetCDF support"; Types: full custom
Name: "ECW"; Description: "Add ECW & JPEG2000 support"; Types: full custom
Name: "MrSID"; Description: "Add MrSID support"; Types: full custom
;; Name: "HDF4"; Description: "Add Hierarchical Data Format Release 4 support"; Types: full custom
Name: "HDF5"; Description: "Add Hierarchical Data Format Release 5 support"; Types: full custom

[Run]
; Install VC++ 2010 if needed:
#ifdef x64BitVersion
Filename: "{tmp}\{#vcredist}"; Parameters: "/qb"; Flags: waituntilterminated; Check: VCRedistNeedsInstall_x64()
#else
Filename: "{tmp}\{#vcredist}"; Parameters: "/qb"; Flags: waituntilterminated; Check: VCRedistNeedsInstall_x86()
#endif
;Run some command files:
Filename: "{app}\regMapWinGIS.cmd"; WorkingDir: "{app}"; Flags: runhidden
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/getting_started.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGvInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Go to the online documentation"
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/MapWindow49.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Read about the future of MapWinGIS/MapWindow v5"
Filename: "http://www.mapwindow.org/documentation/mapwingis4.9/version_history.html?utm_source=MWv49&utm_medium=cpc&utm_campaign=MWGInstaller-v{#MyAppVersion}"; Flags: shellexec runasoriginaluser postinstall nowait skipifsilent; Description: "Read about the changes in this version"

[UninstallRun]
Filename: "{app}\unregMapWinGIS.cmd"; WorkingDir: "{app}"; Flags: runhidden

[Registry]
;; Add location of MapWinGIS to path, needed for netcdf.dll
;; Root: "HKLM"; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: "expandsz"; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: NeedsAddPath(ExpandConstant('{app}'))

[InstallDelete]
;; Old ECW driver, conflicts with new driver:
Type: files; Name: "{app}\libecwj2.dll"; Components: MapWinGIS_Core

[Code]
#IFDEF UNICODE
  #DEFINE AW "W"
#ELSE
  #DEFINE AW "A"
#ENDIF
type
  INSTALLSTATE = Longint;
const
  INSTALLSTATE_INVALIDARG = -2;  // An invalid parameter was passed to the function.
  INSTALLSTATE_UNKNOWN = -1;     // The product is neither advertised or installed.
  INSTALLSTATE_ADVERTISED = 1;   // The product is advertised but not installed.
  INSTALLSTATE_ABSENT = 2;       // The product is installed for a different user.
  INSTALLSTATE_DEFAULT = 5;      // The product is installed for the current user.

  VC_2008_REDIST_X86 = '{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}';
  VC_2008_REDIST_X64 = '{350AA351-21FA-3270-8B7A-835434E766AD}';
  VC_2008_REDIST_IA64 = '{2B547B43-DB50-3139-9EBE-37D419E0F5FA}';
  VC_2008_SP1_REDIST_X86 = '{9A25302D-30C0-39D9-BD6F-21E6EC160475}';
  VC_2008_SP1_REDIST_X64 = '{8220EEFE-38CD-377E-8595-13398D740ACE}';
  VC_2008_SP1_REDIST_IA64 = '{5827ECE1-AEB0-328E-B813-6FC68622C1F9}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_X86 = '{1F1C2DFC-2D24-3E06-BCB8-725134ADF989}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_X64 = '{4B6C7001-C7D6-3710-913E-5BC23FCE91E6}';
  VC_2008_SP1_ATL_SEC_UPD_REDIST_IA64 = '{977AD349-C2A8-39DD-9273-285C08987C7B}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_X86 = '{9BE518E6-ECC6-35A9-88E4-87755C07200F}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_X64 = '{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}';
  VC_2008_SP1_MFC_SEC_UPD_REDIST_IA64 = '{515643D1-4E9E-342F-A75A-D1F16448DC04}';

  VC_2010_REDIST_X86 = '{196BB40D-1578-3D01-B289-BEFC77A11A1E}';
  VC_2010_REDIST_X64 = '{DA5E371C-6333-3D8A-93A4-6FD5B20BCC6E}';
  VC_2010_REDIST_IA64 = '{C1A35166-4301-38E9-BA67-02823AD72A1B}';
  VC_2010_SP1_REDIST_X86 = '{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}';
  VC_2010_SP1_REDIST_X64 = '{1D8E6291-B0D5-35EC-8441-6616F567A0F7}';
  VC_2010_SP1_REDIST_IA64 = '{88C73C1C-2DE5-3B01-AFB8-B46EF4AB41CD}';

  // http://stackoverflow.com/questions/27582762/inno-setup-for-visual-c-redistributable-package-for-visual-studio-2013
  VC_2013_REDIST_X86 = '{13A4EE12-23EA-3371-91EE-EFB36DDFFF3E}'; //Microsoft.VS.VC_RuntimeMinimumVSU_x86,v12
  VC_2013_REDIST_X64 = '{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}'; //Microsoft.VS.VC_RuntimeMinimumVSU_amd64,v12

function MsiQueryProductState(szProduct: string): INSTALLSTATE;
  external 'MsiQueryProductState{#AW}@msi.dll stdcall';

function VCVersionInstalled(const ProductID: string): Boolean;
begin
  Result := MsiQueryProductState(ProductID) = INSTALLSTATE_DEFAULT;
end;

function VCRedistNeedsInstall_x86(): Boolean;
begin
  // here the Result must be True when you need to install your VCRedist
  // or False when you don't need to, so now it's upon you how you build
  // this statement, the following won't install your VC redist only when
  // the Visual C++ 2008 Redist (x86) and Visual C++ 2008 SP1 Redist(x86)
  // are installed for the current user
  Result := not (VCVersionInstalled(VC_2013_REDIST_X86));
end;

function VCRedistNeedsInstall_x64(): Boolean;
begin
  // here the Result must be True when you need to install your VCRedist
  // or False when you don't need to, so now it's upon you how you build
  // this statement, the following won't install your VC redist only when
  // the Visual C++ 2008 Redist (x86) and Visual C++ 2008 SP1 Redist(x86)
  // are installed for the current user
  Result := not (VCVersionInstalled(VC_2013_REDIST_X64));
end;

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;

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "afrikaans"; MessagesFile: "compiler:Languages\Afrikaans.isl"
Name: "albanian"; MessagesFile: "compiler:Languages\Albanian.isl"
Name: "arabic"; MessagesFile: "compiler:Languages\Arabic.isl"
Name: "basque"; MessagesFile: "compiler:Languages\Basque.isl"
Name: "belarusian"; MessagesFile: "compiler:Languages\Belarusian.isl"
Name: "bosnian"; MessagesFile: "compiler:Languages\Bosnian.isl"
Name: "brazilianportuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
Name: "bulgarian"; MessagesFile: "compiler:Languages\Bulgarian.isl"
Name: "catalan"; MessagesFile: "compiler:Languages\Catalan.isl"
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
Name: "chinesetrad"; MessagesFile: "compiler:Languages\ChineseTraditional.isl"
Name: "corsican"; MessagesFile: "compiler:Languages\Corsican.isl"
Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl"
Name: "danish"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "estonian"; MessagesFile: "compiler:Languages\Estonian.isl"
Name: "finnish"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
Name: "galician"; MessagesFile: "compiler:Languages\Galician.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "greek"; MessagesFile: "compiler:Languages\Greek.isl"
Name: "hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl"
Name: "hungarian"; MessagesFile: "compiler:Languages\Hungarian.isl"
Name: "icelandic"; MessagesFile: "compiler:Languages\Icelandic.isl"
Name: "indonesian"; MessagesFile: "compiler:Languages\Indonesian.isl"
Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
Name: "lithuanian"; MessagesFile: "compiler:Languages\Lithuanian.isl"
Name: "luxemburgish"; MessagesFile: "compiler:Languages\Luxemburgish.isl"
Name: "macedonian"; MessagesFile: "compiler:Languages\Macedonian.isl"
Name: "malaysian"; MessagesFile: "compiler:Languages\Malaysian.isl"
;;Name: "nepali"; MessagesFile: "compiler:Languages\Nepali.islu"
Name: "norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl"
Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl"
Name: "romanian"; MessagesFile: "compiler:Languages\Romanian.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "serbiancyrillic"; MessagesFile: "compiler:Languages\SerbianCyrillic.isl"
Name: "serbianlatin"; MessagesFile: "compiler:Languages\SerbianLatin.isl"
Name: "slovak"; MessagesFile: "compiler:Languages\Slovak.isl"
Name: "slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "swedish"; MessagesFile: "compiler:Languages\Swedish.isl"
Name: "tatarish"; MessagesFile: "compiler:Languages\Tatar.isl"
Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl"
Name: "ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl"


relative paths

relative paths

; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{DCEA27B3-F601-4340-93B3-63DA04613409}
AppName=Cloud-In-One
AppVersion=0.5
;AppVerName=Cloud-In-One 0.5
DefaultDirName={pf}\CLOUD_IN_ONE
DefaultGroupName=CLOUD_IN_ONE
OutputDir=dist
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "dist\cloud-in-one.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "dist\cio-crypt.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "dist\sqlite3.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "dist\msvcr100.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "dist\trusted-certs.crt"; DestDir: "{app}"; Flags: ignoreversion
Source: "dist\config\*"; DestDir: "{app}\config"; Flags: ignoreversion recursesubdirs createallsubdirs  ; BeforeInstall: WriteAppPath
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\Cloud-In-One"; Filename: "{app}\cloud-in-one.exe"
Name: "{group}\{cm:UninstallProgram,Cloud-In-One}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\Cloud-In-One"; Filename: "{app}\cloud-in-one.exe"; Tasks: desktopicon

[Run]
Filename: "{app}\cloud-in-one.exe"; Description: "{cm:LaunchProgram,Cloud-In-One}"; Flags: nowait postinstall skipifsilent;

[Code]
var
  DataDirPage: TInputDirWizardPage;

procedure InitializeWizard;
begin
  { Create the pages }

  DataDirPage := CreateInputDirPage(wpSelectDir,
    'Select Synchronization Directory', 'Where should your data be synced?',
    'Select the folder in which the Application should sync your files, then click Next.',
    False, '');
  DataDirPage.Add('');

  { Set default values, using settings that were stored last time if possible }

  DataDirPage.Values[0] := ExpandConstant('{userdocs}\CLOUD_IN_ONE');
end;

function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo,
  MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
  S: String;
begin
  { Fill the 'Ready Memo' with the normal settings and the custom settings }
  S := 'Sync Folder: ' + DataDirPage.Values[0] + NewLine;

  Result := S;
end;

function GetDataDir(Param: String): String;
var
  S: String;
  S2: String;
begin
  { Return the selected DataDir }
  S := DataDirPage.Values[0];
  StringChangeEx(S, '\', '/', True);
  Result := S
end;

procedure WriteAppPath;
var
    FileData: String;
begin
    LoadStringFromFile(ExpandConstant('{app}\config\config.json'), FileData);
    StringChange(FileData, 'XXXXXMARKERXXXXX', GetDataDir(''));
    SaveStringToFile(ExpandConstant('{app}\config\config.json'), FileData, False);
end;

; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{DCEA27B3-F601-4340-93B3-63DA04613409}
AppName=Cloud-In-One
AppVersion=0.5
;AppVerName=Cloud-In-One 0.5
DefaultDirName={pf}\CLOUDINONE
DefaultGroupName=CLOUD_IN_ONE
OutputDir=C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\cloud-in-one.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\cio-crypt.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\sqlite3.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\msvcr100.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\trusted-certs.crt"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\Vctor\Dropbox\__Universidad\5o\Cloud-In-One\dist\config\*"; DestDir: "{app}\config"; Flags: ignoreversion recursesubdirs createallsubdirs  ; BeforeInstall: WriteAppPath
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\Cloud-In-One"; Filename: "{app}\cloud-in-one.exe"
Name: "{group}\{cm:UninstallProgram,Cloud-In-One}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\Cloud-In-One"; Filename: "{app}\cloud-in-one.exe"; Tasks: desktopicon

[Run]
Filename: "{app}\cloud-in-one.exe"; Description: "{cm:LaunchProgram,Cloud-In-One}"; Flags: nowait postinstall skipifsilent;

[Code]
var
  DataDirPage: TInputDirWizardPage;

procedure InitializeWizard;
begin
  { Create the pages }

  DataDirPage := CreateInputDirPage(wpSelectDir,
    'Select Synchronization Directory', 'Where should your data be synced?',
    'Select the folder in which the Application should sync your files, then click Next.',
    False, '');
  DataDirPage.Add('');

  { Set default values, using settings that were stored last time if possible }

  DataDirPage.Values[0] := ExpandConstant('{userdocs}\CLOUD_IN_ONE');
end;

function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo,
  MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
  S: String;
begin
  { Fill the 'Ready Memo' with the normal settings and the custom settings }
  S := 'Sync Folder: ' + DataDirPage.Values[0] + NewLine;

  Result := S;
end;

function GetDataDir(Param: String): String;
var
  S: String;
  S2: String;
begin
  { Return the selected DataDir }
  S := DataDirPage.Values[0];
  StringChangeEx(S, '\', '/', True);
  Result := S
end;

procedure WriteAppPath;
var
    FileData: String;
begin
    LoadStringFromFile(ExpandConstant('{app}\config\config.json'), FileData);
    StringChange(FileData, 'XXXXXMARKERXXXXX', GetDataDir(''));
    SaveStringToFile(ExpandConstant('{app}\config\config.json'), FileData, False);
end;


Use existing variables instead of static data

#define MyAppName "Gmail Notifier"
#define MyAppVersion "2.4.3.0"
#define MyAppShortVersion "2.4"
#define MyAppYear GetDateTimeString('yyyy', '', '');
#define MyAppPublisher "Xavier Foucrier"
#define MyAppURL "https://github.com/xavierfoucrier/gmail-notifier"
#define MyAppExeName "Gmail notifier.exe"

[Setup]
AppId={{7E60E047-C79B-49A4-8CF6-B33D5565B2E8}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright=Copyright (c) {#MyAppYear} {#MyAppPublisher}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppMutex=gmailnotifier-115e363ecbfefd771e55c6874680bc0a
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
LicenseFile=..\LICENSE.md
OutputDir=..\setup
ArchitecturesInstallIn64BitMode=x64
OutputBaseFilename={#MyAppName} {#MyAppShortVersion}
SetupIconFile=setup.ico
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
VersionInfoVersion={#MyAppVersion}
UninstallDisplayIcon={app}\{#MyAppExeName}

[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
Name: "de"; MessagesFile: "compiler:Languages\German.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "startup"; Description: "{cm:AutoStartProgram,{#MyAppName}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone;

[Files]
Source: "..\code\bin\Release 32 bits (x86)\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "..\code\bin\Release 32 bits (x86)\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: not Is64BitInstallMode
Source: "..\code\bin\Release 64 bits (x64)\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "..\code\bin\Release 64 bits (x64)\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: Is64BitInstallMode

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Parameters: "install {language} {code:autorun}"; Flags: runhidden
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall

[Registry]
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "Gmail notifier"; ValueData: "{app}\{#MyAppExeName}"; Tasks: startup; Flags: uninsdeletevalue;

[Code]
function autorun(Value: string): string;
begin
	if RegValueExists(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Run', 'Gmail notifier') then begin
		Result := 'auto';
	end	else begin
		Result := 'none';
	end;
end;

[UninstallDelete]
Type: filesandordirs; Name: "{localappdata}\{#MyAppName}"

#define MyAppName "Gmail Notifier"
#define MyAppVersion "2.4.3.0"
#define MyAppShortVersion "2.4"
#define MyAppYear GetDateTimeString('yyyy', '', '');
#define MyAppPublisher "Xavier Foucrier"
#define MyAppURL "https://github.com/xavierfoucrier/gmail-notifier"
#define MyAppExeName "Gmail notifier.exe"

[Setup]
AppId={{7E60E047-C79B-49A4-8CF6-B33D5565B2E8}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright=Copyright (c) {#MyAppYear} {#MyAppPublisher}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppMutex=gmailnotifier-115e363ecbfefd771e55c6874680bc0a
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
LicenseFile=..\LICENSE.md
OutputDir=..\setup
ArchitecturesInstallIn64BitMode=x64
OutputBaseFilename={#MyAppName} {#MyAppShortVersion}
SetupIconFile=setup.ico
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
VersionInfoVersion={#MyAppVersion}
UninstallDisplayIcon={app}\{#MyAppExeName}

[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
Name: "de"; MessagesFile: "compiler:Languages\German.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "startup"; Description: "{cm:AutoStartProgram,{#MyAppName}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone;

[Files]
Source: "..\code\bin\Release 32 bits (x86)\Gmail notifier.exe"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "..\code\bin\Release 32 bits (x86)\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: not Is64BitInstallMode
Source: "..\code\bin\Release 64 bits (x64)\Gmail notifier.exe"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "..\code\bin\Release 64 bits (x64)\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: Is64BitInstallMode

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Parameters: "install {language} {code:autorun}"; Flags: runhidden
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall

[Registry]
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "Gmail notifier"; ValueData: "{app}\{#MyAppExeName}"; Tasks: startup; Flags: uninsdeletevalue;

[Code]
function autorun(Value: string): string;
begin
	if RegValueExists(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Run', 'Gmail notifier') then begin
		Result := 'auto';
	end	else begin
		Result := 'none';
	end;
end;

[UninstallDelete]
Type: filesandordirs; Name: "{localappdata}\Gmail Notifier"


remove tools for now install python before libfife install libfife silently into the python folder

;
;          _\|/_
;          (o o)
; +-----oOO-{_}-OOo------------------------------------------------------+
; |                                                                      |
; |  Flexible Isometric Free Engine - Inno Setup Script File             |
; |  -------------------------------------------------------             |
; |                                                                      |
; |  Author:   Jens A. Koch <jakoch@web.de>                              |
; |  License:  MIT                                                       |
; |                                                                      |
; |  For the full copyright and license information, please view         |
; |  the LICENSE file that was distributed with this source code.        |
; |                                                                      |
; |  Note for developers                                                 |
; |  -------------------                                                 |
; |  A good resource for developing and understanding                    |
; |  Inno Setup Script files is the official "Inno Setup Help".          |
; |  Website:  http://jrsoftware.org/ishelp/index.php                    |
; |                                                                      |
; +---------------------------------------------------------------------<3

; version is set here, when the version isn't passed to the compiler on invocation
#ifndef APP_VERSION
#define APP_VERSION          "0.0.1"
#endif

#define APP_NAME             "FifeSDK"
#define APP_COMPILER         "VC14"
#define APP_PUBLISHER        "FIFE Team"
#define APP_URL              "http://fifengine.net/"
#define APP_SUPPORT_URL      "https://github.com/fifengine/fifengine/issues"
#define COPYRIGHT_YEAR        GetDateTimeString('yyyy', '', '');

[Setup]
AppId={{8A27DF0C-689B-4B76-8BFC-AFCDD90C1A31}

; set application meta-data
AppName={#APP_NAME}
AppVerName={#APP_NAME} {#APP_VERSION}
AppVersion={#APP_VERSION}
AppCopyright=© {#APP_PUBLISHER}
AppPublisher={#APP_PUBLISHER}
AppPublisherURL={#APP_URL}
AppSupportURL={#APP_SUPPORT_URL}
AppUpdatesURL={#APP_URL}

; default installation folder is "c:\fife". users might change this via dialog.
DefaultDirName={pf}\FIFE\
DefaultGroupName={#APP_NAME}
DirExistsWarning=No
EnableDirDoesntExistWarning=Yes
AllowNoIcons=yes

; compression
Compression=lzma2/ultra
LZMAUseSeparateProcess=yes
LZMANumBlockThreads=2
InternalCompressLevel=max
SolidCompression=true

; style
WizardImageFile=images\WizardImage.bmp
WizardSmallImageFile=images\WizardSmallImage.bmp
SetupIconFile=images\fife.ico

; this creates the installer executable in the build folder
; for example: "_build\FifeSDK-0.4.0-Setup-VC14-x86.exe"
OutputBaseFilename={#APP_NAME}-{#APP_VERSION}-Setup-{#APP_COMPILER}-x86
OutputDir=..\_build

; disable wizard pages: Welcome (by default), Ready
DisableReadyPage=yes

; enable wizard pages: Select Destination Location
DisableDirPage=no

; Tell Windows Explorer to reload the environment, because Registry change (env PATH change)
ChangesEnvironment=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

; Define the types of installations
; The user gets a drop-down list to select one of these types.
; Selecting a type will selected a set of components.
[Types]
Name: "full";          Description: "Full installation (build-tools, engine, dependencies, demos, tools)"
Name: "build-tools";   Description: "Build-tools only (CMake, Python, Boost, Swig)"
Name: "fife-only";     Description: "Engine only"
;Name: "fife-demos";    Description: "Engine and Demos"
Name: "custom";        Description: "Custom installation"; Flags: iscustom

; Define components to install
[Components]
Name: fifengine;       Description: "[fifengine] Fifengine - Isometric Game Engine";    Types: full fife-only
;Name: fifengine;       Description: "[fifengine] Fifengine - Isometric Game Engine";    Types: full fife-only fife-demos
Name: dependencies;    Description: "[fifengine] Dependencies";                         Types: full;
;Name: demos;           Description: "[fifengine] Demos";                                Types: full fife-demos
Name: cmake;           Description: "[build tools] CMake - build system";               Types: full build-tools
Name: "Python";        Description: "[build tools] Python - programming language";
Name: "Python\py27";   Description: "[build tools] Python v2.7";                        Types: full build-tools; Flags: exclusive
Name: "Python\py35";   Description: "[build tools] Python v3.5";                        Types: full build-tools; Flags: exclusive
Name: swig;            Description: "[build tools] SWIG - interface generator";         Types: full build-tools;

[Files]
Source: "..\repackage\fifengine-includes\*";    DestDir: "{app}\fifengine-includes";    Flags: recursesubdirs ignoreversion; Components: dependencies
Source: "..\repackage\cmake\*";                 DestDir: "{app}\cmake";                 Flags: recursesubdirs ignoreversion; Components: cmake
Source: "..\repackage\swig\*";                  DestDir: "{app}\swig";                  Flags: recursesubdirs ignoreversion; Components: swig
; include Python from Appveyor
; https://www.appveyor.com/docs/installed-software/#python
Source: "C:\Python27\*";                        DestDir: "{app}\python";                Flags: recursesubdirs ignoreversion; Components: "Python\py27"
Source: "C:\Python35\*";                        DestDir: "{app}\python";                Flags: recursesubdirs ignoreversion; Components: "Python\py35"
; Fifengine below Python, because we are installing the python library into the Python installation folder
Source: "..\repackage\libfife.win32-py2.7.msi"; DestDir: "{tmp}";                       Flags: recursesubdirs;               Components: fifengine

; Define items to run automatically on installation...
[Run]
; install "libfife for python2.7" only when "python27" and "fifengine" are selected
; install silently into the target dir
Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\libfife.win32-py2.7.msi"" TARGETDIR=""{app}\python"" /qn"; Components: Python\py27 and fifengine

; Define items to run automatically on un-installation...
[UninstallRun]
; un-install "libfife"
;Filename: "uninstall.exe"; Flags: runascurrentuser runhidden

[Registry]
; A registry change needs the following directive: [SETUP] ChangesEnvironment=yes
; add path to python
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"PATH"; ValueData:"{olddata};{app}\python"; Flags: preservestringtype; Check: NeedsAddPath(ExpandConstant('{app}\python')); Components: Python\py27 or Python\py35;
; add path to libfife
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"PATH"; ValueData:"{olddata};{app}\python\Lib\site-packages\fife"; Flags: preservestringtype; Check: NeedsAddPath(ExpandConstant('{app}\python\Lib\site-packages\fife')); Components: fifengine;

[Code]
// modification and path lookup helper for env PATH
#include "includes\envpath.iss"

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  appDir: string;
begin
  appDir := ExpandConstant('{app}');
  // finally, remove paths from the ENV path
  if (CurUninstallStep = usPostUninstall) then begin
     RemovePathFromEnvironmentPath(appDir + '\python');
     RemovePathFromEnvironmentPath(appDir + '\python\Lib\site-packages\fife');
     RemovePathFromEnvironmentPath(appDir);
  end;
end;

;
;          _\|/_
;          (o o)
; +-----oOO-{_}-OOo------------------------------------------------------+
; |                                                                      |
; |  Flexible Isometric Free Engine - Inno Setup Script File             |
; |  -------------------------------------------------------             |
; |                                                                      |
; |  Author:   Jens A. Koch <jakoch@web.de>                              |
; |  License:  MIT                                                       |
; |                                                                      |
; |  For the full copyright and license information, please view         |
; |  the LICENSE file that was distributed with this source code.        |
; |                                                                      |
; |  Note for developers                                                 |
; |  -------------------                                                 |
; |  A good resource for developing and understanding                    |
; |  Inno Setup Script files is the official "Inno Setup Help".          |
; |  Website:  http://jrsoftware.org/ishelp/index.php                    |
; |                                                                      |
; +---------------------------------------------------------------------<3

; version is set here, when the version isn't passed to the compiler on invocation
#ifndef APP_VERSION
#define APP_VERSION          "0.0.1"
#endif

#define APP_NAME             "FifeSDK"
#define APP_COMPILER         "VC14"
#define APP_PUBLISHER        "FIFE Team"
#define APP_URL              "http://fifengine.net/"
#define APP_SUPPORT_URL      "https://github.com/fifengine/fifengine/issues"
#define COPYRIGHT_YEAR        GetDateTimeString('yyyy', '', '');

[Setup]
AppId={{8A27DF0C-689B-4B76-8BFC-AFCDD90C1A31}

; set application meta-data
AppName={#APP_NAME}
AppVerName={#APP_NAME} {#APP_VERSION}
AppVersion={#APP_VERSION}
AppCopyright=© {#APP_PUBLISHER}
AppPublisher={#APP_PUBLISHER}
AppPublisherURL={#APP_URL}
AppSupportURL={#APP_SUPPORT_URL}
AppUpdatesURL={#APP_URL}

; default installation folder is "c:\fife". users might change this via dialog.
DefaultDirName={pf}\FIFE\
DefaultGroupName={#APP_NAME}
DirExistsWarning=No
EnableDirDoesntExistWarning=Yes
AllowNoIcons=yes

; compression
Compression=lzma2/ultra
LZMAUseSeparateProcess=yes
LZMANumBlockThreads=2
InternalCompressLevel=max
SolidCompression=true

; style
WizardImageFile=images\WizardImage.bmp
WizardSmallImageFile=images\WizardSmallImage.bmp
SetupIconFile=images\fife.ico

; this creates the installer executable in the build folder
; for example: "_build\FifeSDK-0.4.0-Setup-VC14-x86.exe"
OutputBaseFilename={#APP_NAME}-{#APP_VERSION}-Setup-{#APP_COMPILER}-x86
OutputDir=..\_build

; disable wizard pages: Welcome (by default), Ready
DisableReadyPage=yes

; enable wizard pages: Select Destination Location
DisableDirPage=no

; Tell Windows Explorer to reload the environment, because Registry change (env PATH change)
ChangesEnvironment=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

; Define the types of installations
; The user gets a drop-down list to select one of these types.
; Selecting a type will selected a set of components.
[Types]
Name: "full";          Description: "Full installation (build-tools, engine, dependencies, demos, tools)"
Name: "build-tools";   Description: "Build-tools only (CMake, Python, Boost, Swig)"
Name: "fife-only";     Description: "Engine only"
;Name: "fife-demos";    Description: "Engine and Demos"
;Name: "fife-tools";    Description: "Engine and Tools"
Name: "custom";        Description: "Custom installation"; Flags: iscustom

; Define components to install
[Components]
Name: fifengine;       Description: "[fifengine] Fifengine - Isometric Game Engine";    Types: full fife-only
;Name: fifengine;       Description: "[fifengine] Fifengine - Isometric Game Engine";    Types: full fife-only fife-demos
Name: dependencies;    Description: "[fifengine] Dependencies";                         Types: full;
;Name: demos;           Description: "[fifengine] Demos";                                Types: full fife-demos
;Name: tools;           Description: "[fifengine] Tools";                                Types: full fife-tools
Name: cmake;           Description: "[build tools] CMake - build system";               Types: full build-tools
Name: "Python";        Description: "[build tools] Python - programming language";
Name: "Python\py27";   Description: "[build tools] Python v2.7";                        Types: full build-tools; Flags: exclusive
Name: "Python\py35";   Description: "[build tools] Python v3.5";                        Types: full build-tools; Flags: exclusive
Name: swig;            Description: "[build tools] SWIG - interface generator";         Types: full build-tools;

[Files]
Source: "..\repackage\libfife.win32-py2.7.msi"; DestDir: "{tmp}";                       Flags: recursesubdirs;               Components: fifengine
Source: "..\repackage\fifengine-includes\*";    DestDir: "{app}\fifengine-includes";    Flags: recursesubdirs ignoreversion; Components: dependencies
Source: "..\repackage\cmake\*";                 DestDir: "{app}\cmake";                 Flags: recursesubdirs ignoreversion; Components: cmake
Source: "..\repackage\swig\*";                  DestDir: "{app}\swig";                  Flags: recursesubdirs ignoreversion; Components: swig
; include Python from Appveyor
; https://www.appveyor.com/docs/installed-software/#python
Source: "C:\Python27\*";                        DestDir: "{app}\python";                Flags: recursesubdirs ignoreversion; Components: "Python\py27"
Source: "C:\Python35\*";                        DestDir: "{app}\python";                Flags: recursesubdirs ignoreversion; Components: "Python\py35"

; Define items to run automatically on installation...
[Run]
; install "libfife for python2.7" only when "python27" and "fifengine" are selected
Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\libfife.win32-py2.7.msi""";      Components: Python\py27 and fifengine

; Define items to run automatically on un-installation...
[UninstallRun]
; un-install "libfife"
;Filename: "uninstall.exe"; Flags: runascurrentuser runhidden

[Registry]
; A registry change needs the following directive: [SETUP] ChangesEnvironment=yes
; add path to python
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"PATH"; ValueData:"{olddata};{app}\python"; Flags: preservestringtype; Check: NeedsAddPath(ExpandConstant('{app}\python')); Components: Python\py27 or Python\py35;
; add path to libfife
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"PATH"; ValueData:"{olddata};{app}\python\Lib\site-packages\fife"; Flags: preservestringtype; Check: NeedsAddPath(ExpandConstant('{app}\python\Lib\site-packages\fife')); Components: fifengine;

[Code]
// modification and path lookup helper for env PATH
#include "includes\envpath.iss"

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  appDir: string;
begin
  appDir := ExpandConstant('{app}');
  // finally, remove paths from the ENV path
  if (CurUninstallStep = usPostUninstall) then begin
     RemovePathFromEnvironmentPath(appDir + '\python');
     RemovePathFromEnvironmentPath(appDir + '\python\Lib\site-packages\fife');
     RemovePathFromEnvironmentPath(appDir);
  end;
end;


Setup script has been deleted

Setup script has been deleted

The installation files are available in the releases section

[Setup]
AllowNetworkDrive=no
AllowUNCPath=no
AlwaysShowComponentsList=yes
AppCopyright=Copyright (C) 2015 Andrey Lomakin
AppName=Sensor
AppPublisher=Andrey Lomakin
AppVerName=Sensor 1.0
AppVersion=1.0
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
DefaultDirName={pf}\Sensor
DefaultGroupName=Sensor
LicenseFile=license.txt
OutputBaseFilename=setup
SignedUninstaller=yes
SignTool=signtool
SetupIconFile=icon.ico
UninstallDisplayIcon={app}\Sensor.exe,0
UninstallDisplayName=Sensor
VersionInfoVersion=1.0.0.0
WizardImageFile=large.bmp
WizardSmallImageFile=small.bmp

[Files]
Source: "*.dll"; DestDir: "{app}"
Source: "Sensor.exe"; DestDir: "{app}"
Source: "settings.ini"; DestDir: "{app}"
Source: "vcredist_x64.exe"; DestDir: "{app}"; Flags: dontcopy
Source: "bearer\*"; DestDir: "{app}\bearer"
Source: "iconengines\*"; DestDir: "{app}\iconengines"
Source: "imageformats\*"; DestDir: "{app}\imageformats"
Source: "platforms\*"; DestDir: "{app}\platforms"

[CustomMessages]
en.InstallRedist=Installing Microsoft Visual C++ Redistributable 2013...
ru.InstallRedist= Microsoft Visual C++ Redistributable 2013...

[Icons]
Name: "{group}\Sensor"; Filename: "{app}\Sensor.exe"; WorkingDir: "{app}"
Name: "{userdesktop}\Sensor"; Filename: "{app}\Sensor.exe"; WorkingDir: "{app}"

[Run]
Filename: "{app}\vcredist_x64.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "{cm:InstallRedist}"; Check: Check

[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"

[Code]
function MsiQueryProductState(szProduct: String): Longint;
external 'MsiQueryProductStateW@msi.dll stdcall'; function Check(): Boolean;
begin Result := MsiQueryProductState('{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}') <> 5; end;


Installed flag is added under HKLM (to allow for scenario when administrator installs program for users).

[Setup]
AppName=Summae
AppVerName=Summae 0.00
DefaultDirName={pf}\Josip Medved\Summae
OutputBaseFilename=summae000
OutputDir=..\Releases
SourceDir=..\Binaries
AppId=JosipMedved_Summae
AppMutex=Global\JosipMedved_Summae
AppPublisher=Josip Medved
AppPublisherURL=http://www.jmedved.com/summae/
UninstallDisplayIcon={app}\Summae.exe
AlwaysShowComponentsList=no
ArchitecturesInstallIn64BitMode=x64
DisableProgramGroupPage=yes
MergeDuplicateFiles=yes
MinVersion=0,5.01
PrivilegesRequired=admin
ShowLanguageDialog=no
SolidCompression=yes
ChangesAssociations=yes

[Files]
Source: "Summae.exe";         DestDir: "{app}";
Source: "SummaeExecutor.exe"; DestDir: "{app}";
Source: "sum.exe";            DestDir: "{app}";
Source: "SummaeSettings.exe"; DestDir: "{app}";
Source: "ReadMe.txt";         DestDir: "{app}"; Attribs: readonly; Flags: overwritereadonly uninsremovereadonly;

[Icons]
Name: "{userstartmenu}\Summae"; Filename: "{app}\Summae.exe"

[Registry]
Root: HKCU; Subkey: "Software\Josip Medved\Summae"; ValueType: none;  ValueName: "Installed"; Flags: deletevalue uninsdeletevalue
Root: HKLM; Subkey: "Software\Josip Medved\Summae"; ValueType: dword; ValueName: "Installed"; ValueData: "1"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Josip Medved"; Flags: uninsdeletekeyifempty
Root: HKCR; Subkey: "*\shell\Summae"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)"; ValueType: none; Flags: uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)"; ValueType: string; ValueName: "MultiSelectModel"; ValueData: "Player";
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)\command"; ValueType: string; ValueName: ""; ValueData: """{app}\SummaeExecutor.exe"" /sha1 ""%1""";
Root: HKCR; Subkey: "*\shell\Summae (CRC-16)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (CRC-32)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (MD-5)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (RIPE MD-160)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-256)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-384)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-512)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;

[Run]
Filename: "{app}\ReadMe.txt"; Description: "View ReadMe.txt"; Flags: postinstall runasoriginaluser shellexec nowait skipifsilent unchecked
Filename: "{app}\Summae.exe"; Description: "Launch application now"; Flags: postinstall nowait skipifsilent runasoriginaluser unchecked

[Setup]
AppName=Summae
AppVerName=Summae 0.00
DefaultDirName={pf}\Josip Medved\Summae
OutputBaseFilename=summae000
OutputDir=..\Releases
SourceDir=..\Binaries
AppId=JosipMedved_Summae
AppMutex=Global\JosipMedved_Summae
AppPublisher=Josip Medved
AppPublisherURL=http://www.jmedved.com/summae/
UninstallDisplayIcon={app}\Summae.exe
AlwaysShowComponentsList=no
ArchitecturesInstallIn64BitMode=x64
DisableProgramGroupPage=yes
MergeDuplicateFiles=yes
MinVersion=0,5.01
PrivilegesRequired=admin
ShowLanguageDialog=no
SolidCompression=yes
ChangesAssociations=yes

[Files]
Source: "Summae.exe";         DestDir: "{app}";
Source: "SummaeExecutor.exe"; DestDir: "{app}";
Source: "sum.exe";            DestDir: "{app}";
Source: "SummaeSettings.exe"; DestDir: "{app}";
Source: "ReadMe.txt";         DestDir: "{app}"; Attribs: readonly; Flags: overwritereadonly uninsremovereadonly;

[Icons]
Name: "{userstartmenu}\Summae"; Filename: "{app}\Summae.exe"

[Registry]
Root: HKCU; Subkey: "Software\Josip Medved\Summae"; ValueType: dword; ValueName: "Installed"; ValueData: "1"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Josip Medved"; Flags: uninsdeletekeyifempty
Root: HKCR; Subkey: "*\shell\Summae"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)"; ValueType: none; Flags: uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)"; ValueType: string; ValueName: "MultiSelectModel"; ValueData: "Player";
Root: HKCR; Subkey: "*\shell\Summae (SHA-1)\command"; ValueType: string; ValueName: ""; ValueData: """{app}\SummaeExecutor.exe"" /sha1 ""%1""";
Root: HKCR; Subkey: "*\shell\Summae (CRC-16)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (CRC-32)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (MD-5)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (RIPE MD-160)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-256)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-384)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;
Root: HKCR; Subkey: "*\shell\Summae (SHA-512)"; ValueType: none; Flags: dontcreatekey uninsdeletekey;

[Run]
Filename: "{app}\ReadMe.txt"; Description: "View ReadMe.txt"; Flags: postinstall runasoriginaluser shellexec nowait skipifsilent unchecked
Filename: "{app}\Summae.exe"; Description: "Launch application now"; Flags: postinstall nowait skipifsilent runasoriginaluser unchecked