enable Polish. use utf-8 encoding

enable Polish.
use utf-8 encoding

#define SourceDir "..\"
#define AppName "AIMP Control Plugin"
#define SrcApp "temp_build\Release\Control Plugin.dll"
; use absolute path as GetFileVersion() argument since there is problem with relative path when we execute this script from command line.
#define FileVerStr GetFileVersion(SourcePath + "\" + SourceDir + SrcApp)
#define StripBuild(VerStr) Copy(VerStr, 1, RPos(".", VerStr)-1)
#define AppVerStr StripBuild(FileVerStr)
#define PluginWorkDirectoryName "Control Plugin"
#define AimpPluginsDirectoryName "Plugins"
#define FreeImage_VERSION GetEnv('FreeImage_VERSION')
#define LegacyPluginExecutableFilename "aimp_control_plugin.dll"
#define LogsDirectoryName "logs"
#define AlbumCoverCacheDirectoryName "album_covers_cache"
#define LegacyAIMP3_6_RC_PluginDirName "aimp_control_plugin"

[Setup]

SourceDir={#SourceDir}
AppName={#AppName}
AppVersion={#AppVerStr}
AppVerName={#AppName} {#AppVerStr}
UninstallDisplayName={#AppName} {#AppVerStr}
UninstallFilesDir={app}\{#PluginWorkDirectoryName}
VersionInfoVersion={#FileVerStr}
VersionInfoTextVersion={#AppVerStr}
VersionInfoDescription=AIMP player plugin. Provides network access to AIMP player.
VersionInfoProductName={#AppName}
VersionInfoProductVersion={#FileVerStr}
OutputBaseFilename=aimp_control_plugin-{#FileVerStr}-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={{F171581D-00CD-4E77-8982-B1B68FDCAAFA}
AppPublisher=Alexey Ivanov
AppCopyright=Copyright © 2015 Alexey Ivanov
AppPublisherURL=https://github.com/a0ivanov/aimp-control-plugin
AppSupportURL=http://code.google.com/p/aimp-control-plugin/w/list
AppUpdatesURL=https://github.com/a0ivanov/aimp-control-plugin/releases/latest

DefaultDirName={#AimpPluginsDirectoryName}
DefaultGroupName={#AppName}
DisableProgramGroupPage=true
OutputDir=temp_build\Release\distrib\
SetupIconFile=inno_setup_data\icons\aimp_control_plugin_installer.ico
Compression=lzma/ultra
SolidCompression=true
InternalCompressLevel=ultra
PrivilegesRequired=admin
DirExistsWarning=no
AllowUNCPath=false
AppendDefaultDirName=true

[Languages]
; Language name is used on Donation page as {language} constant.
Name: en; MessagesFile: inno_setup_data\English.isl; LicenseFile: License-English.txt;
Name: ru; MessagesFile: inno_setup_data\Russian.isl; LicenseFile: License-Russian.txt;
Name: cs; MessagesFile: inno_setup_data\Czech.isl;   LicenseFile: License-English.txt;
Name: pl; MessagesFile: inno_setup_data\Polish.isl;  LicenseFile: License-English.txt;

[Files]
Source: "{#SrcApp}"; DestDir: "{code:GetPluginDllDestinationDir}"; DestName: "{#PluginWorkDirectoryName}.dll"; BeforeInstall: RemoveLegacyPluginExecutable; Flags: ignoreversion
Source: "temp_build\Release\htdocs\*"; DestDir: "{code:GetBrowserScriptsDir}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Source: "inno_setup_data\default_settings.dat"; DestDir: "{code:GetPluginSettingsDir}"; DestName: "settings.dat"; Flags: onlyifdoesntexist; AfterInstall: AfterInstallSettingsFile( ExpandConstant('{code:GetPluginSettingsDir}\settings.dat') )
Source: "3rd_party\FreeImage\{#FreeImage_VERSION}\Dist\FreeImage.dll"; DestDir: "{code:GetFreeImageDLLsDstDir}"; Flags: ignoreversion
Source: "3rd_party\FreeImage\{#FreeImage_VERSION}\Wrapper\FreeImagePlus\dist\FreeImagePlus.dll"; DestDir: "{code:GetFreeImageDLLsDstDir}"; Flags: ignoreversion
Source: "temp_build\Release\SettingsManager\*"; DestDir: "{code:GetSettingsManagerDir}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Registry]
; etc.

[UninstallDelete]
Type: filesandordirs; Name: "{code:GetBrowserScriptsDirOnUninstall}\{#AlbumCoverCacheDirectoryName}"
Type: filesandordirs; Name: "{code:GetPluginSettingsDir}\{#LogsDirectoryName}"

[Code]
var
  BrowserScriptsDirPage: TInputDirWizardPage;
  AimpVersionSelectionPage: TInputOptionWizardPage;
  PluginOptionsPage: TInputOptionWizardPage;
  SettingsManagerInstallationPage: TOutputMsgMemoWizardPage;
  AfterInstallPage: TOutputMsgMemoWizardPage;
  AllowNetworkAccess: Boolean;
  AllowFilesUpload: Boolean;
  AllowFilesDeletion: Boolean;
  EnableScheduler: Boolean;
  SettingsFileDestination: String;
  Port: Integer;

procedure InitDonationPage; forward;
function GetTextForSettingsManagerInstallationMemo(): AnsiString; forward;

procedure InitializeWizard;
begin
  { Set AIMP player version, used to determine default path of Aimp's Plugins directory. }
  AimpVersionSelectionPage := CreateInputOptionPage(wpLicense,
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg1}'),
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg2}'),
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg3}'),
                                                    True,
                                                    False
                                                    );
  AimpVersionSelectionPage.Add('AIMP2');
  AimpVersionSelectionPage.Add('AIMP3');
  AimpVersionSelectionPage.Add('AIMP4');

  AimpVersionSelectionPage.SelectedValueIndex := 2; { default is AIMP4 }

  BrowserScriptsDirPage := CreateInputDirPage(wpSelectDir,
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg1}'),
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg2}'),
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg3}'),
                                              False,
                                              ''
                                              );
  BrowserScriptsDirPage.Add('');

  InitDonationPage();

  PluginOptionsPage := CreateInputOptionPage(BrowserScriptsDirPage.ID,
                                            ExpandConstant('{cm:PluginOptionsTitle}'),
                                            ExpandConstant('{cm:PluginOptionsDescription}'),
                                            ExpandConstant('{cm:PluginOptionsSubDescription}'),
                                            False, False);

  PluginOptionsPage.Add(ExpandConstant('{cm:OptionNetworkCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionUploadTracksCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionPhysicalTrackDeletionCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionSchedulerCheckBox}'));

  SettingsManagerInstallationPage := CreateOutputMsgMemoPage(PluginOptionsPage.ID,
                                          ExpandConstant('{cm:SettingsManagerInstallationTitle}'),
                                          ExpandConstant('{cm:SettingsManagerInstallationDescription}'),
                                          ExpandConstant('{cm:SettingsManagerInstallationSubDescription}'),
                                          GetTextForSettingsManagerInstallationMemo());

  AfterInstallPage := CreateOutputMsgMemoPage(wpInfoAfter,
   SetupMessage(msgWizardInfoAfter),
   SetupMessage(msgInfoAfterLabel),
   SetupMessage(msgInfoAfterClickLabel),
   '' // memo text will be set later by AfterInstallPage.RichEditViewer.RTFText.
  );

  Port := 3333;
end;

procedure TerminateAimpExecutionIfNeedeed(); forward;
function GetInfoAfterMemoText() : String; forward;
function DefaultWritableBrowserScriptsDir(): String; forward;

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = wpSelectDir then
    begin
    WizardForm.DirEdit.Text := ExpandConstant('{pf}\{code:GetAimpPlayerAppDirName}\{code:AimpPluginsDirName}')

    TerminateAimpExecutionIfNeedeed(); { must do this after WizardForm.DirEdit.Text set. }
    end
  else if CurPageID = BrowserScriptsDirPage.ID then
    begin
    SettingsFileDestination := ExpandConstant('{code:GetPluginSettingsDir}\settings.dat');

    { Set default values, using settings that were stored last time if possible }
    BrowserScriptsDirPage.Values[0] := DefaultWritableBrowserScriptsDir();
    end
  else if CurPageID = wpReady then
     begin
     AllowNetworkAccess := PluginOptionsPage.Values[0];
     AllowFilesUpload := PluginOptionsPage.Values[1];
     AllowFilesDeletion := PluginOptionsPage.Values[2];
     EnableScheduler := PluginOptionsPage.Values[3];
     AfterInstallPage.RichEditViewer.RTFText := GetInfoAfterMemoText();
     end
end;

function IsDotNetDetected(version: string; service: cardinal): boolean; forward;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  // initialize result to not skip any page (not necessary, but safer)
  Result := False;

  // if the page that is asked to be skipped is your custom page, then...
  if PageID = SettingsManagerInstallationPage.ID then
    Result := IsDotNetDetected('v4\Full', 0)
end;

function GetTextForSettingsManagerInstallationMemo(): AnsiString;
begin
   Result := ExpandConstant('{cm:SettingsManagerInstallationMessage}');
end;

function DefaultWritableBrowserScriptsDir(): String;
begin
  //GetPreviousData( 'BrowserScriptsDir',
  //                  ExpandConstant('{code:GetPluginWorkDir}\htdocs')
  //                );

  Result := ExpandConstant('{userappdata}\{code:GetAimpPlayerAppDataDirName}\{#PluginWorkDirectoryName}\htdocs');
end;

function IsAimp2(): Boolean; forward;
function IsAimp3(): Boolean; forward;

function GetAimpPlayerAppDataDirName(): String;
begin
  { Return the name of AppData directory for selected AIMP player version }
  if IsAimp3() then
	  Result := 'AIMP3'
  else
	  Result := 'AIMP';
end;

function GetBrowserScriptsDir(Param: String): String;
begin
  { Return the selected BrowserScriptsDir }
  Result := BrowserScriptsDirPage.Values[0];
end;

function IsAimp2(): Boolean;
begin
   Result := AimpVersionSelectionPage.SelectedValueIndex = 0;
end;

function IsAimp3(): Boolean;
begin
   Result := AimpVersionSelectionPage.SelectedValueIndex = 1;
end;

function GetPluginWorkDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetPluginSettingsDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetFreeImageDLLsDstDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetSettingsManagerDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}\SettingsManager')
end;

function AimpPluginsDirName(Param: String): String;
begin
  { Return name of AIMP's Plugins directory. }
  Result := ExpandConstant('{#AimpPluginsDirectoryName}')
  { We do not distinguish between AIMP2/3 Plugins directory names
    since supporting of this difference is hard
    while Windows is case insensitive.
  if IsAimp2() then
    Result := 'PlugIns'
  else
    Result := 'Plugins';
  }
end;

function GetAimpIniFileName(): String; forward;

function GetAimp3VersionCode(): Integer;
var
    version: Longint;
    aimpIniFilePath: String;
begin
   aimpIniFilePath := ExpandConstant('{app}\..\' + GetAimpIniFileName());
   version := GetIniInt('System', 'Version', 0, 0, 555555, aimpIniFilePath);
   Log('Aimp version is: ' + IntToStr(version));

   Result := version;
end;

function GetPluginDllDestinationDir(Param: String): String;
var aimpVersionCode: Integer;
begin
    aimpVersionCode := GetAimp3VersionCode();
    if aimpVersionCode >= 3600 then
        Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
    else
        Result := ExpandConstant('{app}');
end;

function GetAimpPlayerAppDirName(Param: String): String;
begin
  { Return the name of program directory for selected AIMP player version }
  if IsAimp2() then
    Result := 'AIMP2'
  else if IsAimp3() then
    Result := 'AIMP3'
  else
    Result := 'AIMP'; // AIMP4+.
end;

function GetAimpIniFileName(): String;
begin
  { Return the name of ini file in program directory for selected AIMP player version }
  if IsAimp3() then
    Result := 'AIMP3.ini'
  else
    Result := 'AIMP.ini'; // AIMP4+, AIMP2 has no ini file in program directory.
end;

procedure RemoveLegacyPluginExecutable();
var path: String;
begin
  path := ExpandConstant('{app}\{#PluginWorkDirectoryName}\{#LegacyPluginExecutableFilename}');
  DeleteFile(path);
  path := ExpandConstant('{app}\{#LegacyPluginExecutableFilename}');
  DeleteFile(path);
  path := ExpandConstant('{app}\{#LegacyAIMP3_6_RC_PluginDirName}');
  DelTree(path, True, True, True);
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
  SetPreviousData(PreviousDataKey, 'BrowserScriptsDir', BrowserScriptsDirPage.Values[0]);
end;

function BooleanToString(condition: Boolean): String;
begin
  if (condition) then
    Result := 'true'
  else
    Result := 'false';
end;

procedure AfterInstallSettingsFile(Path: String);
var
  // See http://msdn.microsoft.com/en-us/library/ms757878(VS.85).aspx for details about
  XMLDoc : Variant;       // IXMLDOMDocument
  DocRootNodes : Variant; // IXMLDOMNodeList
  DocRootNode : Variant;  // IXMLDOMNode
  HttpServerNode : Variant;  // IXMLDOMNode
  AllInterfacesNode : Variant;  // IXMLDOMNode
  MiscNode : Variant;  // IXMLDOMNode
  Nodes : Variant;        // IXMLDOMNode
  Node : Variant;        // IXMLDOMNode
begin
  //MsgBox('Try to load the XML file: ' + Path, mbInformation, mb_Ok);

  { Load the XML File }
  XMLDoc := CreateOleObject('Msxml2.DOMDocument');
  XMLDoc.async := False;
  XMLDoc.resolveExternals := False;
  XMLDoc.setProperty('SelectionLanguage', 'XPath');
  XMLDoc.load(Path);
  if XMLDoc.parseError.errorCode <> 0 then
    RaiseException('Error in xml file "' + Path + '" on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);

  //MsgBox('Loaded the XML file.', mbInformation, mb_Ok);

  { Modify the XML document }
  DocRootNodes := XMLDoc.selectNodes('//httpserver/document_root');
  //MsgBox('Mathing nodes: ' + IntToStr(DocRootNodes.length), mbInformation, mb_Ok);
  DocRootNode := DocRootNodes.item(0);
  DocRootNode.Text := GetBrowserScriptsDir('');

  Nodes := XMLDoc.selectNodes('//httpserver/port');
  if (Nodes.length > 0) then
    Port := Nodes.item(0).Text;

  HttpServerNode := XMLDoc.selectNodes('//httpserver').item(0);
  if (AllowNetworkAccess) then
    begin
    Nodes := XMLDoc.selectNodes('//httpserver/ip_to_bind');
    if (Nodes.length > 0) then
       HttpServerNode.removeChild(Nodes.item(0));

    Nodes := XMLDoc.selectNodes('//httpserver/port');
    if (Nodes.length > 0) then
       HttpServerNode.removeChild(Nodes.item(0));

    Nodes := XMLDoc.selectNodes('//httpserver/all_interfaces');
    if (Nodes.length > 0) then
      begin
      AllInterfacesNode := Nodes.item(0);
      Port := AllInterfacesNode.getAttribute('port');
      end
    else
      begin
      AllInterfacesNode := XMLDoc.createElement('all_interfaces')
      AllInterfacesNode.setAttribute('port', IntToStr(Port));
      HttpServerNode.appendChild(AllInterfacesNode);
      end;
    end;

  MiscNode := XMLDoc.selectNodes('//misc').item(0);

  Nodes := XMLDoc.selectNodes('//misc/enable_track_upload');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_track_upload');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_track_upload').item(0);
    end;
  Node.Text := BooleanToString(AllowFilesDeletion);

  Nodes := XMLDoc.selectNodes('//misc/enable_physical_track_deletion');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_physical_track_deletion');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_physical_track_deletion').item(0);
    end;
  Node.Text := BooleanToString(AllowFilesDeletion);

  Nodes := XMLDoc.selectNodes('//misc/enable_scheduler');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_scheduler');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_scheduler').item(0);
    end;
  Node.Text := BooleanToString(EnableScheduler);

  { Save the XML document }
  XMLDoc.Save(Path);
  //MsgBox('Saved the modified XML as ''' + Path + '''.', mbInformation, mb_Ok);
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 := '';
  S := S + MemoDirInfo + NewLine;
  S := S + ExpandConstant('{cm:BrowserScriptsDirDestination}') + NewLine + Space + GetBrowserScriptsDir('') + NewLine;
  S := S + ExpandConstant('{cm:SettingsFileDestination}') + NewLine + Space + SettingsFileDestination + NewLine;
  S := S + ExpandConstant('{cm:SettingsManager}') + ':' + NewLine + Space + GetSettingsManagerDir('') + '\SettingsManager.exe' + NewLine;
  Result := S;
end;

function GetAimpHWND(): HWND;
begin
  Result := FindWindowByClassName('AIMP2_RemoteInfo');
end;

function IsAimpLaunched(): boolean;
begin
  Result := GetAimpHWND() <> 0;
end;

const
  WM_AIMP_COMMAND = 1024 + $75;
  WM_AIMP_CALLFUNC = 3;
  AIMP_QUIT = 10;
procedure KillAimp();
begin
  SendMessage(GetAimpHWND(), WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_QUIT);
end;

procedure TerminateAimpExecutionIfNeedeed();
begin
  if IsAimpLaunched() then
    if MsgBox(ExpandConstant('{cm:AimpApplicationTerminateQuery}'),
          mbConfirmation,
          MB_YESNO) = IDYES then
      KillAimp();
end;

function GetUninstallString(): String;
var
  sUnInstPath: String;
  sUnInstallString: String;
begin
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
  sUnInstallString := '';
  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
  Result := sUnInstallString;
end;

function GetBrowserScriptsStringDirectlyFromRegistry(): String;
var
  sUnInstPath: String;
  sBrowserScriptsString: String;
begin
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
  sBrowserScriptsString := '';
  if not RegQueryStringValue(HKLM, sUnInstPath, 'Inno Setup CodeFile: BrowserScriptsDir', sBrowserScriptsString) then
    RegQueryStringValue(HKCU, sUnInstPath, 'Inno Setup CodeFile: BrowserScriptsDir', sBrowserScriptsString);

  Result := sBrowserScriptsString;
end;

function GetBrowserScriptsString(): String;
begin
  Result := GetPreviousData('BrowserScriptsDir', '');
end;

function IsUpgrade(): Boolean;
begin
  Result := (GetUninstallString() <> '');
end;

function UnInstallOldVersion(): Integer;
var
  sUnInstallString: String;
  iResultCode: Integer;
begin
// Return Values:
// 1 - uninstall string is empty
// 2 - error executing the UnInstallString
// 3 - successfully executed the UnInstallString

  // default return value
  Result := 0;

  // get the uninstall string of the old app
  sUnInstallString := GetUninstallString();
  if sUnInstallString <> '' then begin
    sUnInstallString := RemoveQuotes(sUnInstallString);
    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

function RemoveInstalledBrowserScripts(): Integer;
var
  sBrowserScriptsDir: String;
begin
// Return Values:
// 1 - Browser scripts dir string is empty
// 2 - error executing the DelTree
// 3 - successfully executed the DelTree

  // default return value
  Result := 0;

  // get the uninstall string of the old app.
  sBrowserScriptsDir := GetBrowserScriptsString();
  if sBrowserScriptsDir <> '' then begin
    sBrowserScriptsDir := RemoveQuotes(sBrowserScriptsDir);
    if DelTree(sBrowserScriptsDir, True, True, True) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

function GetBrowserScriptsDirOnUninstall(Param: String): String;
begin
    Result := GetBrowserScriptsString();
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if (CurStep=ssInstall) then
  begin
    if (IsUpgrade()) then
    begin
      // Do not uninstall previous version till it will be possible remain settings file.
      // Instead remove old browser scripts.
      // UnInstallOldVersion();
      RemoveInstalledBrowserScripts();
    end;
  end;
end;

procedure DonationButtonOnClick(Sender: TObject);
var
  ErrorCode: Integer;
  URL: String;
  lang: String;
begin
  lang := ExpandConstant('{language}');
  if (lang <> 'ru') and (lang <> 'en') then lang := 'en';

  URL := 'http://www.a0ivanov.ru/aimp/donate_' + lang + '.html';

  if not ShellExec('', URL, '', '', SW_SHOW, ewNoWait, ErrorCode) then
  begin
    // handle failure if necessary
  end;
end;

procedure InitDonationPage;
var
  Page: TWizardPage;
  Button: TNewButton;
  Label1: TLabel;
begin
  Page := CreateCustomPage(wpInfoAfter, ExpandConstant('{cm:DonatePageTitle}'), ExpandConstant('{cm:DonateMsg}')); // cm:DonatePageTitle2

  Label1 := TLabel.Create(Page);
  Label1.AutoSize := False;
  Label1.Top := ScaleY(15);
  Label1.Left := ScaleX(0);
  Label1.Width := Page.SurfaceWidth;
  Label1.Alignment := taCenter;
  Label1.Caption := ExpandConstant('{cm:DonateMsg}');
  Label1.WordWrap := True;
  Label1.Parent := Page.Surface;

  Button := TNewButton.Create(Page);
  Button.Width := ScaleX(80);
  Button.Height := ScaleY(26);
  Button.Caption := ExpandConstant('{cm:DonateButton}');
  Button.OnClick := @DonationButtonOnClick;
  Button.Parent := Page.Surface;
  Button.Top := Label1.Top + Label1.Height + ScaleY(8);
  Button.Left := Label1.Left + (Label1.Width - Button.Width) / 2;
end;

procedure GetIpAddresses(Addresses : TStringList); forward;
function GetInfoAfterMemoText(): String;
var
  SL : TStringList;
  I: Integer;
  Msg: String;
begin
  if (AllowNetworkAccess) then
     begin
     Msg := ExpandConstant('{cm:InfoAfterPageMemoTextRemoteBegin}');
     SL := TStringList.Create;
     GetIpAddresses(SL);
     For I := 0 to SL.Count - 1 do
       begin
        Msg := Msg + #13#10 + FmtMessage('http://%1:%2/index.htm', [SL.Strings[I], IntToStr(Port)]);
       end;
     SL.Free;
     Msg := Msg + #13#10 + ExpandConstant('{cm:InfoAfterPageMemoTextRemoteEnd}');
     end
   else
     Msg := ExpandConstant('{cm:InfoAfterPageMemoTextLocal}');

   Msg := Msg + #13#10 + #13#10 + ExpandConstant('{cm:SettingsManagerInfo}');
   Result := Msg;
end;

const
 ERROR_INSUFFICIENT_BUFFER = 122;

function GetIpAddrTable( pIpAddrTable: Array of Byte;
  var pdwSize: Cardinal; bOrder: WordBool ): DWORD;
external 'GetIpAddrTable@IpHlpApi.dll stdcall';

procedure GetIpAddresses(Addresses : TStringList);
var
 Size : Cardinal;
 Buffer : Array of Byte;
 IpAddr : String;
 AddrCount : Integer;
 I, J : Integer;
begin
  // Find Size
  if GetIpAddrTable(Buffer,Size,False) = ERROR_INSUFFICIENT_BUFFER then
  begin
     // Allocate Buffer with large enough size
     SetLength(Buffer,Size);
     // Get List of IP Addresses into Buffer
     if GetIpAddrTable(Buffer,Size,True) = 0 then
     begin
       // Find out how many addresses will be returned.
       AddrCount := (Buffer[1] * 256) + Buffer[0];
       // Loop through addresses.
       For I := 0 to AddrCount -1 do
       begin
         IpAddr := '';
         // Loop through each byte of the address
         For J := 0 to 3 do
         begin
           if J > 0 then
             IpAddr := IpAddr + '.';
           // Navigagte through record structure to find correct byte of Addr
           IpAddr := IpAddr + IntToStr(Buffer[I*24+J+4]);
         end;
         Addresses.Add(IpAddr);
       end;
     end;
  end;
end;

function IsDotNetDetected(version: string; service: cardinal): boolean;
// Indicates whether the specified version and service pack of the .NET Framework is installed.
//
// version -- Specify one of these strings for the required .NET Framework version:
//    'v1.1.4322'     .NET Framework 1.1
//    'v2.0.50727'    .NET Framework 2.0
//    'v3.0'          .NET Framework 3.0
//    'v3.5'          .NET Framework 3.5
//    'v4\Client'     .NET Framework 4.0 Client Profile
//    'v4\Full'       .NET Framework 4.0 Full Installation
//    'v4.5'          .NET Framework 4.5
//
// service -- Specify any non-negative integer for the required service pack level:
//    0               No service packs required
//    1, 2, etc.      Service pack 1, 2, etc. required
var
    key: string;
    install, release, serviceCount: cardinal;
    check45, success: boolean;
begin
    // .NET 4.5 installs as update to .NET 4.0 Full
    if version = 'v4.5' then begin
        version := 'v4\Full';
        check45 := true;
    end else
        check45 := false;

    // installation key group for all .NET versions
    key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + version;

    // .NET 3.0 uses value InstallSuccess in subkey Setup
    if Pos('v3.0', version) = 1 then begin
        success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install);
    end else begin
        success := RegQueryDWordValue(HKLM, key, 'Install', install);
    end;

    // .NET 4.0/4.5 uses value Servicing instead of SP
    if Pos('v4', version) = 1 then begin
        success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
    end else begin
        success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
    end;

    // .NET 4.5 uses additional value Release
    if check45 then begin
        success := success and RegQueryDWordValue(HKLM, key, 'Release', release);
        success := success and (release >= 378389);
    end;

    result := success and (install = 1) and (serviceCount >= service);
end;

#define SourceDir "..\"
#define AppName "AIMP Control Plugin"
#define SrcApp "temp_build\Release\Control Plugin.dll"
; use absolute path as GetFileVersion() argument since there is problem with relative path when we execute this script from command line.
#define FileVerStr GetFileVersion(SourcePath + "\" + SourceDir + SrcApp)
#define StripBuild(VerStr) Copy(VerStr, 1, RPos(".", VerStr)-1)
#define AppVerStr StripBuild(FileVerStr)
#define PluginWorkDirectoryName "Control Plugin"
#define AimpPluginsDirectoryName "Plugins"
#define FreeImage_VERSION GetEnv('FreeImage_VERSION')
#define LegacyPluginExecutableFilename "aimp_control_plugin.dll"
#define LogsDirectoryName "logs"
#define AlbumCoverCacheDirectoryName "album_covers_cache"
#define LegacyAIMP3_6_RC_PluginDirName "aimp_control_plugin"

[Setup]

SourceDir={#SourceDir}
AppName={#AppName}
AppVersion={#AppVerStr}
AppVerName={#AppName} {#AppVerStr}
UninstallDisplayName={#AppName} {#AppVerStr}
UninstallFilesDir={app}\{#PluginWorkDirectoryName}
VersionInfoVersion={#FileVerStr}
VersionInfoTextVersion={#AppVerStr}
VersionInfoDescription=AIMP player plugin. Provides network access to AIMP player.
VersionInfoProductName={#AppName}
VersionInfoProductVersion={#FileVerStr}
OutputBaseFilename=aimp_control_plugin-{#FileVerStr}-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={{F171581D-00CD-4E77-8982-B1B68FDCAAFA}
AppPublisher=Alexey Ivanov
AppCopyright=Copyright © 2015 Alexey Ivanov
AppPublisherURL=https://github.com/a0ivanov/aimp-control-plugin
AppSupportURL=http://code.google.com/p/aimp-control-plugin/w/list
AppUpdatesURL=https://github.com/a0ivanov/aimp-control-plugin/releases/latest

DefaultDirName={#AimpPluginsDirectoryName}
DefaultGroupName={#AppName}
DisableProgramGroupPage=true
OutputDir=temp_build\Release\distrib\
SetupIconFile=inno_setup_data\icons\aimp_control_plugin_installer.ico
Compression=lzma/ultra
SolidCompression=true
InternalCompressLevel=ultra
PrivilegesRequired=admin
DirExistsWarning=no
AllowUNCPath=false
AppendDefaultDirName=true

[Languages]
; Language name is used on Donation page as {language} constant.
Name: en; MessagesFile: inno_setup_data\English.isl; LicenseFile: License-English.txt;
Name: ru; MessagesFile: inno_setup_data\Russian.isl; LicenseFile: License-Russian.txt;
Name: cs; MessagesFile: inno_setup_data\Czech.isl;   LicenseFile: License-English.txt;

[Files]
Source: "{#SrcApp}"; DestDir: "{code:GetPluginDllDestinationDir}"; DestName: "{#PluginWorkDirectoryName}.dll"; BeforeInstall: RemoveLegacyPluginExecutable; Flags: ignoreversion
Source: "temp_build\Release\htdocs\*"; DestDir: "{code:GetBrowserScriptsDir}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Source: "inno_setup_data\default_settings.dat"; DestDir: "{code:GetPluginSettingsDir}"; DestName: "settings.dat"; Flags: onlyifdoesntexist; AfterInstall: AfterInstallSettingsFile( ExpandConstant('{code:GetPluginSettingsDir}\settings.dat') )
Source: "3rd_party\FreeImage\{#FreeImage_VERSION}\Dist\FreeImage.dll"; DestDir: "{code:GetFreeImageDLLsDstDir}"; Flags: ignoreversion
Source: "3rd_party\FreeImage\{#FreeImage_VERSION}\Wrapper\FreeImagePlus\dist\FreeImagePlus.dll"; DestDir: "{code:GetFreeImageDLLsDstDir}"; Flags: ignoreversion
Source: "temp_build\Release\SettingsManager\*"; DestDir: "{code:GetSettingsManagerDir}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Registry]
; etc.

[UninstallDelete]
Type: filesandordirs; Name: "{code:GetBrowserScriptsDirOnUninstall}\{#AlbumCoverCacheDirectoryName}"
Type: filesandordirs; Name: "{code:GetPluginSettingsDir}\{#LogsDirectoryName}"

[Code]
var
  BrowserScriptsDirPage: TInputDirWizardPage;
  AimpVersionSelectionPage: TInputOptionWizardPage;
  PluginOptionsPage: TInputOptionWizardPage;
  SettingsManagerInstallationPage: TOutputMsgMemoWizardPage;
  AfterInstallPage: TOutputMsgMemoWizardPage;
  AllowNetworkAccess: Boolean;
  AllowFilesUpload: Boolean;
  AllowFilesDeletion: Boolean;
  EnableScheduler: Boolean;
  SettingsFileDestination: String;
  Port: Integer;

procedure InitDonationPage; forward;
function GetTextForSettingsManagerInstallationMemo(): AnsiString; forward;

procedure InitializeWizard;
begin
  { Set AIMP player version, used to determine default path of Aimp's Plugins directory. }
  AimpVersionSelectionPage := CreateInputOptionPage(wpLicense,
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg1}'),
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg2}'),
                                                    ExpandConstant('{cm:AimpVerionSelectionMsg3}'),
                                                    True,
                                                    False
                                                    );
  AimpVersionSelectionPage.Add('AIMP2');
  AimpVersionSelectionPage.Add('AIMP3');
  AimpVersionSelectionPage.Add('AIMP4');

  AimpVersionSelectionPage.SelectedValueIndex := 2; { default is AIMP4 }

  BrowserScriptsDirPage := CreateInputDirPage(wpSelectDir,
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg1}'),
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg2}'),
                                              ExpandConstant('{cm:BrowserScriptsDirSelectionMsg3}'),
                                              False,
                                              ''
                                              );
  BrowserScriptsDirPage.Add('');

  InitDonationPage();

  PluginOptionsPage := CreateInputOptionPage(BrowserScriptsDirPage.ID,
                                            ExpandConstant('{cm:PluginOptionsTitle}'),
                                            ExpandConstant('{cm:PluginOptionsDescription}'),
                                            ExpandConstant('{cm:PluginOptionsSubDescription}'),
                                            False, False);

  PluginOptionsPage.Add(ExpandConstant('{cm:OptionNetworkCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionUploadTracksCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionPhysicalTrackDeletionCheckBox}'));
  PluginOptionsPage.Add(ExpandConstant('{cm:OptionSchedulerCheckBox}'));

  SettingsManagerInstallationPage := CreateOutputMsgMemoPage(PluginOptionsPage.ID,
                                          ExpandConstant('{cm:SettingsManagerInstallationTitle}'),
                                          ExpandConstant('{cm:SettingsManagerInstallationDescription}'),
                                          ExpandConstant('{cm:SettingsManagerInstallationSubDescription}'),
                                          GetTextForSettingsManagerInstallationMemo());

  AfterInstallPage := CreateOutputMsgMemoPage(wpInfoAfter,
   SetupMessage(msgWizardInfoAfter),
   SetupMessage(msgInfoAfterLabel),
   SetupMessage(msgInfoAfterClickLabel),
   '' // memo text will be set later by AfterInstallPage.RichEditViewer.RTFText.
  );

  Port := 3333;
end;

procedure TerminateAimpExecutionIfNeedeed(); forward;
function GetInfoAfterMemoText() : String; forward;
function DefaultWritableBrowserScriptsDir(): String; forward;

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = wpSelectDir then
    begin
    WizardForm.DirEdit.Text := ExpandConstant('{pf}\{code:GetAimpPlayerAppDirName}\{code:AimpPluginsDirName}')

    TerminateAimpExecutionIfNeedeed(); { must do this after WizardForm.DirEdit.Text set. }
    end
  else if CurPageID = BrowserScriptsDirPage.ID then
    begin
    SettingsFileDestination := ExpandConstant('{code:GetPluginSettingsDir}\settings.dat');

    { Set default values, using settings that were stored last time if possible }
    BrowserScriptsDirPage.Values[0] := DefaultWritableBrowserScriptsDir();
    end
  else if CurPageID = wpReady then
     begin
     AllowNetworkAccess := PluginOptionsPage.Values[0];
     AllowFilesUpload := PluginOptionsPage.Values[1];
     AllowFilesDeletion := PluginOptionsPage.Values[2];
     EnableScheduler := PluginOptionsPage.Values[3];
     AfterInstallPage.RichEditViewer.RTFText := GetInfoAfterMemoText();
     end
end;

function IsDotNetDetected(version: string; service: cardinal): boolean; forward;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  // initialize result to not skip any page (not necessary, but safer)
  Result := False;

  // if the page that is asked to be skipped is your custom page, then...
  if PageID = SettingsManagerInstallationPage.ID then
    Result := IsDotNetDetected('v4\Full', 0)
end;

function GetTextForSettingsManagerInstallationMemo(): AnsiString;
begin
   Result := ExpandConstant('{cm:SettingsManagerInstallationMessage}');
end;

function DefaultWritableBrowserScriptsDir(): String;
begin
  //GetPreviousData( 'BrowserScriptsDir',
  //                  ExpandConstant('{code:GetPluginWorkDir}\htdocs')
  //                );

  Result := ExpandConstant('{userappdata}\{code:GetAimpPlayerAppDataDirName}\{#PluginWorkDirectoryName}\htdocs');
end;

function IsAimp2(): Boolean; forward;
function IsAimp3(): Boolean; forward;

function GetAimpPlayerAppDataDirName(): String;
begin
  { Return the name of AppData directory for selected AIMP player version }
  if IsAimp3() then
	  Result := 'AIMP3'
  else
	  Result := 'AIMP';
end;

function GetBrowserScriptsDir(Param: String): String;
begin
  { Return the selected BrowserScriptsDir }
  Result := BrowserScriptsDirPage.Values[0];
end;

function IsAimp2(): Boolean;
begin
   Result := AimpVersionSelectionPage.SelectedValueIndex = 0;
end;

function IsAimp3(): Boolean;
begin
   Result := AimpVersionSelectionPage.SelectedValueIndex = 1;
end;

function GetPluginWorkDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetPluginSettingsDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetFreeImageDLLsDstDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
end;

function GetSettingsManagerDir(Param: String): String;
begin
  Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}\SettingsManager')
end;

function AimpPluginsDirName(Param: String): String;
begin
  { Return name of AIMP's Plugins directory. }
  Result := ExpandConstant('{#AimpPluginsDirectoryName}')
  { We do not distinguish between AIMP2/3 Plugins directory names
    since supporting of this difference is hard
    while Windows is case insensitive.
  if IsAimp2() then
    Result := 'PlugIns'
  else
    Result := 'Plugins';
  }
end;

function GetAimpIniFileName(): String; forward;

function GetAimp3VersionCode(): Integer;
var
    version: Longint;
    aimpIniFilePath: String;
begin
   aimpIniFilePath := ExpandConstant('{app}\..\' + GetAimpIniFileName());
   version := GetIniInt('System', 'Version', 0, 0, 555555, aimpIniFilePath);
   Log('Aimp version is: ' + IntToStr(version));

   Result := version;
end;

function GetPluginDllDestinationDir(Param: String): String;
var aimpVersionCode: Integer;
begin
    aimpVersionCode := GetAimp3VersionCode();
    if aimpVersionCode >= 3600 then
        Result := ExpandConstant('{app}\{#PluginWorkDirectoryName}')
    else
        Result := ExpandConstant('{app}');
end;

function GetAimpPlayerAppDirName(Param: String): String;
begin
  { Return the name of program directory for selected AIMP player version }
  if IsAimp2() then
    Result := 'AIMP2'
  else if IsAimp3() then
    Result := 'AIMP3'
  else
    Result := 'AIMP'; // AIMP4+.
end;

function GetAimpIniFileName(): String;
begin
  { Return the name of ini file in program directory for selected AIMP player version }
  if IsAimp3() then
    Result := 'AIMP3.ini'
  else
    Result := 'AIMP.ini'; // AIMP4+, AIMP2 has no ini file in program directory.
end;

procedure RemoveLegacyPluginExecutable();
var path: String;
begin
  path := ExpandConstant('{app}\{#PluginWorkDirectoryName}\{#LegacyPluginExecutableFilename}');
  DeleteFile(path);
  path := ExpandConstant('{app}\{#LegacyPluginExecutableFilename}');
  DeleteFile(path);
  path := ExpandConstant('{app}\{#LegacyAIMP3_6_RC_PluginDirName}');
  DelTree(path, True, True, True);
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
  SetPreviousData(PreviousDataKey, 'BrowserScriptsDir', BrowserScriptsDirPage.Values[0]);
end;

function BooleanToString(condition: Boolean): String;
begin
  if (condition) then
    Result := 'true'
  else
    Result := 'false';
end;

procedure AfterInstallSettingsFile(Path: String);
var
  // See http://msdn.microsoft.com/en-us/library/ms757878(VS.85).aspx for details about
  XMLDoc : Variant;       // IXMLDOMDocument
  DocRootNodes : Variant; // IXMLDOMNodeList
  DocRootNode : Variant;  // IXMLDOMNode
  HttpServerNode : Variant;  // IXMLDOMNode
  AllInterfacesNode : Variant;  // IXMLDOMNode
  MiscNode : Variant;  // IXMLDOMNode
  Nodes : Variant;        // IXMLDOMNode
  Node : Variant;        // IXMLDOMNode
begin
  //MsgBox('Try to load the XML file: ' + Path, mbInformation, mb_Ok);

  { Load the XML File }
  XMLDoc := CreateOleObject('Msxml2.DOMDocument');
  XMLDoc.async := False;
  XMLDoc.resolveExternals := False;
  XMLDoc.setProperty('SelectionLanguage', 'XPath');
  XMLDoc.load(Path);
  if XMLDoc.parseError.errorCode <> 0 then
    RaiseException('Error in xml file "' + Path + '" on line ' + IntToStr(XMLDoc.parseError.line) + ', position ' + IntToStr(XMLDoc.parseError.linepos) + ': ' + XMLDoc.parseError.reason);

  //MsgBox('Loaded the XML file.', mbInformation, mb_Ok);

  { Modify the XML document }
  DocRootNodes := XMLDoc.selectNodes('//httpserver/document_root');
  //MsgBox('Mathing nodes: ' + IntToStr(DocRootNodes.length), mbInformation, mb_Ok);
  DocRootNode := DocRootNodes.item(0);
  DocRootNode.Text := GetBrowserScriptsDir('');

  Nodes := XMLDoc.selectNodes('//httpserver/port');
  if (Nodes.length > 0) then
    Port := Nodes.item(0).Text;

  HttpServerNode := XMLDoc.selectNodes('//httpserver').item(0);
  if (AllowNetworkAccess) then
    begin
    Nodes := XMLDoc.selectNodes('//httpserver/ip_to_bind');
    if (Nodes.length > 0) then
       HttpServerNode.removeChild(Nodes.item(0));

    Nodes := XMLDoc.selectNodes('//httpserver/port');
    if (Nodes.length > 0) then
       HttpServerNode.removeChild(Nodes.item(0));

    Nodes := XMLDoc.selectNodes('//httpserver/all_interfaces');
    if (Nodes.length > 0) then
      begin
      AllInterfacesNode := Nodes.item(0);
      Port := AllInterfacesNode.getAttribute('port');
      end
    else
      begin
      AllInterfacesNode := XMLDoc.createElement('all_interfaces')
      AllInterfacesNode.setAttribute('port', IntToStr(Port));
      HttpServerNode.appendChild(AllInterfacesNode);
      end;
    end;

  MiscNode := XMLDoc.selectNodes('//misc').item(0);

  Nodes := XMLDoc.selectNodes('//misc/enable_track_upload');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_track_upload');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_track_upload').item(0);
    end;
  Node.Text := BooleanToString(AllowFilesDeletion);

  Nodes := XMLDoc.selectNodes('//misc/enable_physical_track_deletion');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_physical_track_deletion');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_physical_track_deletion').item(0);
    end;
  Node.Text := BooleanToString(AllowFilesDeletion);

  Nodes := XMLDoc.selectNodes('//misc/enable_scheduler');
  if (Nodes.length > 0) then
    Node := Nodes.item(0)
  else
    begin
    Node := XMLDoc.createElement('enable_scheduler');
    MiscNode.appendChild(Node);
    Node := XMLDoc.selectNodes('//misc/enable_scheduler').item(0);
    end;
  Node.Text := BooleanToString(EnableScheduler);

  { Save the XML document }
  XMLDoc.Save(Path);
  //MsgBox('Saved the modified XML as ''' + Path + '''.', mbInformation, mb_Ok);
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 := '';
  S := S + MemoDirInfo + NewLine;
  S := S + ExpandConstant('{cm:BrowserScriptsDirDestination}') + NewLine + Space + GetBrowserScriptsDir('') + NewLine;
  S := S + ExpandConstant('{cm:SettingsFileDestination}') + NewLine + Space + SettingsFileDestination + NewLine;
  S := S + ExpandConstant('{cm:SettingsManager}') + ':' + NewLine + Space + GetSettingsManagerDir('') + '\SettingsManager.exe' + NewLine;
  Result := S;
end;

function GetAimpHWND(): HWND;
begin
  Result := FindWindowByClassName('AIMP2_RemoteInfo');
end;

function IsAimpLaunched(): boolean;
begin
  Result := GetAimpHWND() <> 0;
end;

const
  WM_AIMP_COMMAND = 1024 + $75;
  WM_AIMP_CALLFUNC = 3;
  AIMP_QUIT = 10;
procedure KillAimp();
begin
  SendMessage(GetAimpHWND(), WM_AIMP_COMMAND, WM_AIMP_CALLFUNC, AIMP_QUIT);
end;

procedure TerminateAimpExecutionIfNeedeed();
begin
  if IsAimpLaunched() then
    if MsgBox(ExpandConstant('{cm:AimpApplicationTerminateQuery}'),
          mbConfirmation,
          MB_YESNO) = IDYES then
      KillAimp();
end;

function GetUninstallString(): String;
var
  sUnInstPath: String;
  sUnInstallString: String;
begin
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
  sUnInstallString := '';
  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
  Result := sUnInstallString;
end;

function GetBrowserScriptsStringDirectlyFromRegistry(): String;
var
  sUnInstPath: String;
  sBrowserScriptsString: String;
begin
  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
  sBrowserScriptsString := '';
  if not RegQueryStringValue(HKLM, sUnInstPath, 'Inno Setup CodeFile: BrowserScriptsDir', sBrowserScriptsString) then
    RegQueryStringValue(HKCU, sUnInstPath, 'Inno Setup CodeFile: BrowserScriptsDir', sBrowserScriptsString);

  Result := sBrowserScriptsString;
end;

function GetBrowserScriptsString(): String;
begin
  Result := GetPreviousData('BrowserScriptsDir', '');
end;

function IsUpgrade(): Boolean;
begin
  Result := (GetUninstallString() <> '');
end;

function UnInstallOldVersion(): Integer;
var
  sUnInstallString: String;
  iResultCode: Integer;
begin
// Return Values:
// 1 - uninstall string is empty
// 2 - error executing the UnInstallString
// 3 - successfully executed the UnInstallString

  // default return value
  Result := 0;

  // get the uninstall string of the old app
  sUnInstallString := GetUninstallString();
  if sUnInstallString <> '' then begin
    sUnInstallString := RemoveQuotes(sUnInstallString);
    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

function RemoveInstalledBrowserScripts(): Integer;
var
  sBrowserScriptsDir: String;
begin
// Return Values:
// 1 - Browser scripts dir string is empty
// 2 - error executing the DelTree
// 3 - successfully executed the DelTree

  // default return value
  Result := 0;

  // get the uninstall string of the old app.
  sBrowserScriptsDir := GetBrowserScriptsString();
  if sBrowserScriptsDir <> '' then begin
    sBrowserScriptsDir := RemoveQuotes(sBrowserScriptsDir);
    if DelTree(sBrowserScriptsDir, True, True, True) then
      Result := 3
    else
      Result := 2;
  end else
    Result := 1;
end;

function GetBrowserScriptsDirOnUninstall(Param: String): String;
begin
    Result := GetBrowserScriptsString();
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if (CurStep=ssInstall) then
  begin
    if (IsUpgrade()) then
    begin
      // Do not uninstall previous version till it will be possible remain settings file.
      // Instead remove old browser scripts.
      // UnInstallOldVersion();
      RemoveInstalledBrowserScripts();
    end;
  end;
end;

procedure DonationButtonOnClick(Sender: TObject);
var
  ErrorCode: Integer;
  URL: String;
  lang: String;
begin
  lang := ExpandConstant('{language}');
  if (lang <> 'ru') and (lang <> 'en') then lang := 'en';

  URL := 'http://www.a0ivanov.ru/aimp/donate_' + lang + '.html';

  if not ShellExec('', URL, '', '', SW_SHOW, ewNoWait, ErrorCode) then
  begin
    // handle failure if necessary
  end;
end;

procedure InitDonationPage;
var
  Page: TWizardPage;
  Button: TNewButton;
  Label1: TLabel;
begin
  Page := CreateCustomPage(wpInfoAfter, ExpandConstant('{cm:DonatePageTitle}'), ExpandConstant('{cm:DonateMsg}')); // cm:DonatePageTitle2

  Label1 := TLabel.Create(Page);
  Label1.AutoSize := False;
  Label1.Top := ScaleY(15);
  Label1.Left := ScaleX(0);
  Label1.Width := Page.SurfaceWidth;
  Label1.Alignment := taCenter;
  Label1.Caption := ExpandConstant('{cm:DonateMsg}');
  Label1.WordWrap := True;
  Label1.Parent := Page.Surface;

  Button := TNewButton.Create(Page);
  Button.Width := ScaleX(80);
  Button.Height := ScaleY(26);
  Button.Caption := ExpandConstant('{cm:DonateButton}');
  Button.OnClick := @DonationButtonOnClick;
  Button.Parent := Page.Surface;
  Button.Top := Label1.Top + Label1.Height + ScaleY(8);
  Button.Left := Label1.Left + (Label1.Width - Button.Width) / 2;
end;

procedure GetIpAddresses(Addresses : TStringList); forward;
function GetInfoAfterMemoText(): String;
var
  SL : TStringList;
  I: Integer;
  Msg: String;
begin
  if (AllowNetworkAccess) then
     begin
     Msg := ExpandConstant('{cm:InfoAfterPageMemoTextRemoteBegin}');
     SL := TStringList.Create;
     GetIpAddresses(SL);
     For I := 0 to SL.Count - 1 do
       begin
        Msg := Msg + #13#10 + FmtMessage('http://%1:%2/index.htm', [SL.Strings[I], IntToStr(Port)]);
       end;
     SL.Free;
     Msg := Msg + #13#10 + ExpandConstant('{cm:InfoAfterPageMemoTextRemoteEnd}');
     end
   else
     Msg := ExpandConstant('{cm:InfoAfterPageMemoTextLocal}');

   Msg := Msg + #13#10 + #13#10 + ExpandConstant('{cm:SettingsManagerInfo}');
   Result := Msg;
end;

const
 ERROR_INSUFFICIENT_BUFFER = 122;

function GetIpAddrTable( pIpAddrTable: Array of Byte;
  var pdwSize: Cardinal; bOrder: WordBool ): DWORD;
external 'GetIpAddrTable@IpHlpApi.dll stdcall';

procedure GetIpAddresses(Addresses : TStringList);
var
 Size : Cardinal;
 Buffer : Array of Byte;
 IpAddr : String;
 AddrCount : Integer;
 I, J : Integer;
begin
  // Find Size
  if GetIpAddrTable(Buffer,Size,False) = ERROR_INSUFFICIENT_BUFFER then
  begin
     // Allocate Buffer with large enough size
     SetLength(Buffer,Size);
     // Get List of IP Addresses into Buffer
     if GetIpAddrTable(Buffer,Size,True) = 0 then
     begin
       // Find out how many addresses will be returned.
       AddrCount := (Buffer[1] * 256) + Buffer[0];
       // Loop through addresses.
       For I := 0 to AddrCount -1 do
       begin
         IpAddr := '';
         // Loop through each byte of the address
         For J := 0 to 3 do
         begin
           if J > 0 then
             IpAddr := IpAddr + '.';
           // Navigagte through record structure to find correct byte of Addr
           IpAddr := IpAddr + IntToStr(Buffer[I*24+J+4]);
         end;
         Addresses.Add(IpAddr);
       end;
     end;
  end;
end;

function IsDotNetDetected(version: string; service: cardinal): boolean;
// Indicates whether the specified version and service pack of the .NET Framework is installed.
//
// version -- Specify one of these strings for the required .NET Framework version:
//    'v1.1.4322'     .NET Framework 1.1
//    'v2.0.50727'    .NET Framework 2.0
//    'v3.0'          .NET Framework 3.0
//    'v3.5'          .NET Framework 3.5
//    'v4\Client'     .NET Framework 4.0 Client Profile
//    'v4\Full'       .NET Framework 4.0 Full Installation
//    'v4.5'          .NET Framework 4.5
//
// service -- Specify any non-negative integer for the required service pack level:
//    0               No service packs required
//    1, 2, etc.      Service pack 1, 2, etc. required
var
    key: string;
    install, release, serviceCount: cardinal;
    check45, success: boolean;
begin
    // .NET 4.5 installs as update to .NET 4.0 Full
    if version = 'v4.5' then begin
        version := 'v4\Full';
        check45 := true;
    end else
        check45 := false;

    // installation key group for all .NET versions
    key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + version;

    // .NET 3.0 uses value InstallSuccess in subkey Setup
    if Pos('v3.0', version) = 1 then begin
        success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install);
    end else begin
        success := RegQueryDWordValue(HKLM, key, 'Install', install);
    end;

    // .NET 4.0/4.5 uses value Servicing instead of SP
    if Pos('v4', version) = 1 then begin
        success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
    end else begin
        success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
    end;

    // .NET 4.5 uses additional value Release
    if check45 then begin
        success := success and RegQueryDWordValue(HKLM, key, 'Release', release);
        success := success and (release >= 378389);
    end;

    result := success and (install = 1) and (serviceCount >= service);
end;


Update to MFT Agent installation script

Update to MFT Agent installation script

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; ************************************************************************
; Copyright (c) IBM Corporation 2016
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
; http://www.apache.org/licenses/LICENSE-2.0
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific
;  Contributors:
;    Shashikanth Rao T - Initial Contribution
;***************************************************************************
; This installation script is developed using a trial version of Inno Setup
; http://www.jrsoftware.org/isinfo.php
; The script demonstrates how MFT redistributable Agent binaries can be
; bundled into another product's installation package and deployed.
;***************************************************************************
#define MyAppName "MFT Agent"
#define MyAppVersion "1.5"
#define MyAppPublisher "IBM Corp"
#define MyAppURL "http://www.ibm.com/"

[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={{4E1BA108-409D-45CA-90D7-BCD7B6A04C15}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=C:\MFT91\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}
Compression=lzma
SolidCompression=yes
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes

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

[Files]
; Location where MFT Redistributable package has been unzipped. All files under the folder and subfolders
; will be picked up.
Source: "C:\Downloads\IBM-MQFA-Redist-Win64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Registry]
; Update the PATH variable.
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"BFG_DATA"; ValueData:"{code:GetAgentConfigDataPath}" ; Flags: preservestringtype ;

[Run]
;Flags: "64bit"

; Setup Coordination
Filename: "{app}\bin\fteSetupCoordination.cmd"; Parameters: " -coordinationQMgr {code:GetCoordinationQmgrName} -coordinationQMgrHost {code:GetCoordinationQmgrNameHost} -coordinationQMgrPort {code:GetCoordinationQmgrNamePort} -coordinationQMgrChannel {code:GetCoordinationQmgrNameChannel} -f > {app}\instlog.txt"

; Setup Command
Filename: "{app}\bin\fteSetupCommands.cmd"; Parameters: " -p {code:GetCoordinationQmgrName} -connectionQMgr  {code:GetCommandQmgrName} -connectionQMgrHost {code:GetCommandQmgrNameHost} -coordinationQMgrPort {code:GetCommandQmgrNamePort} -connectionQMgrChannel  {code:GetCommandQmgrNameChannel} -f >> {app}\instlog.txt"

; Setup an agent
Filename: "{app}\bin\fteCreateAgent.cmd"; Parameters: " -p {code:GetCoordinationQmgrName} -agentName {code:GetAgentName} -agentQMgr {code:GetAgentQmgrName} -agentQMgrHost  {code:GetAgentQmgrHost} -agentQMgrPort {code:GetAgentQmgrPort} -agentQMgrChannel  {code:GetAgentQmgrChannel} -f >> {app}\instlog.txt"

[Code]
const
  OffsetPixels = 11;

procedure OffsetPageItem(Page: TInputQueryWizardPage; Index,
  Offset: Integer);
begin
  Page.Edits[Index].Top := Page.Edits[Index].Top + Offset;
  Page.PromptLabels[Index].Top := Page.PromptLabels[Index].Top +
    Offset;
end;

var
  ConfigDataPathPage: TInputQueryWizardPage;
  CoordinationQmgrPage: TInputQueryWizardPage;
  CommandQmgrPage: TInputQueryWizardPage;
  AgentNamePage: TInputQueryWizardPage;
  Index: Integer;

{ Get Coordination queue manager details}
function GetCoordinationQmgrName(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[0];
end;

function GetCoordinationQmgrNameHost(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[1];
end;

function GetCoordinationQmgrNamePort(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[2];
end;

function GetCoordinationQmgrNameChannel(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[3];
end;

{Get Command queue manager details}
function GetCommandQmgrName(Value: string): string;
begin
  Result := CommandQmgrPage.Values[0];
end;

function GetCommandQmgrNameHost(Value: string): string;
begin
  Result := CommandQmgrPage.Values[1];
end;

function GetCommandQmgrNamePort(Value: string): string;
begin
  Result := CommandQmgrPage.Values[2];
end;

function GetCommandQmgrNameChannel(Value: string): string;
begin
  Result := CommandQmgrPage.Values[3];
end;

{ Get Agent details}
function GetAgentName(Value: string): string;
begin
  Result := AgentNamePage.Values[0];
end;

function GetAgentQmgrName(Value: string): string;
begin
  Result := AgentNamePage.Values[1];
end;

function GetAgentQmgrHost(Value: string): string;
begin
  Result := AgentNamePage.Values[2];
end;

function GetAgentQmgrPort(Value: string): string;
begin
  Result := AgentNamePage.Values[3];
end;

function GetAgentQmgrChannel(Value: string): string;
begin
  Result := AgentNamePage.Values[4];
end;

function GetAgentConfigDataPath(Value: string): string;
begin
  Result := ConfigDataPathPage.Values[0];
end;

{End of Gets}

#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif

function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
  external 'SetEnvironmentVariable{#AW}@kernel32.dll stdcall';

procedure SetEnvPath;
begin
  if not SetEnvironmentVariable('BFG_DATA', '{code:GetAgentConfigDataPath}') then
    MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;

procedure InitializeWizard;
begin
  { Create the Configuration Data Path page}
  ConfigDataPathPage := CreateInputQueryPage(wpSelectDir,
    'Configure Data Path', '',
    'Please specify path for storing configuration data, then click Next.');
  ConfigDataPathPage.Add('Configuration Data Path:', False);

  { Create the Coordination Queue Manager Setup page}
  CoordinationQmgrPage := CreateInputQueryPage(ConfigDataPathPage.ID,
    'Coordination Queue Manager Setup', '',
    'Please specify Coordination Queue Manager information, then click Next.');
  CoordinationQmgrPage.Add('Queue Manager Name:', False);
  CoordinationQmgrPage.Add('Host Name:', False);
  CoordinationQmgrPage.Add('Port:', False);
  CoordinationQmgrPage.Add('Channel:', False);

  CoordinationQmgrPage.Values[0] := ExpandConstant('COORDQM');
  CoordinationQmgrPage.Values[1] := ExpandConstant('coordqm.mycomp.com');
  CoordinationQmgrPage.Values[2] := ExpandConstant('1414');
  CoordinationQmgrPage.Values[3] := ExpandConstant('APPSVRCONN');

  { Create the Command Queue Manager Setup page}
  CommandQmgrPage := CreateInputQueryPage(CoordinationQmgrPage.ID,
    'Command Queue Manager Setup', '',
    'Please specify Command Queue Manager information, then click Next..');
  CommandQmgrPage.Add('Queue Manager Name)', False);
  CommandQmgrPage.Add('Host Name',False);
  CommandQmgrPage.Add('Port', False);
  CommandQmgrPage.Add('Channel Name', False);

  CommandQmgrPage.Values[0] := ExpandConstant('CMDQM');
  CommandQmgrPage.Values[1] := ExpandConstant('cmdqm.mycomp.com');
  CommandQmgrPage.Values[2] := ExpandConstant('1414');
  CommandQmgrPage.Values[3] := ExpandConstant('APPSVRCONN');

  { Create the Agent Setup page}
  AgentNamePage := CreateInputQueryPage(CommandQmgrPage.ID,
    'Agent Setup', '',
    'Please provide information required for creating an agent');
  Index := AgentNamePage.Add('Agent Name:', False);
  Index := AgentNamePage.Add('Queue Manager Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Host Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Port :', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Channel Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);

  AgentNamePage.Values[0] := ExpandConstant('ZIPAGENT');
  AgentNamePage.Values[1] := ExpandConstant('ZIPAGENTQM');
  AgentNamePage.Values[2] := ExpandConstant('zipagentqm.mycomp.com');
  AgentNamePage.Values[3] := ExpandConstant('1414');
  AgentNamePage.Values[4] := ExpandConstant('APPSVRCONN');

end;

procedure RegisterPreviousData(PreviousDataKey: Integer);

begin
  { Store the settings so we can restore them next time }
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrName', CoordinationQmgrPage.Values[0]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNameHost', CoordinationQmgrPage.Values[1]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNamePort', CoordinationQmgrPage.Values[2]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNameChannel', CoordinationQmgrPage.Values[3]);

  SetPreviousData(PreviousDataKey, 'CommandQmgrName', CommandQmgrPage.Values[0]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNameHost', CommandQmgrPage.Values[1]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNamePort', CommandQmgrPage.Values[2]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNameChannel', CommandQmgrPage.Values[3]);

  SetPreviousData(PreviousDataKey, 'AgentName', AgentNamePage.Values[0]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrName', AgentNamePage.Values[1]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNameHost', AgentNamePage.Values[2]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNamePort', AgentNamePage.Values[3]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNameChannel', AgentNamePage.Values[4]);
end;

function NextButtonClick(CurPageID: Integer): Boolean;

begin
  { Validate certain pages before allowing the user to proceed }
  if CurPageID = CoordinationQmgrPage.ID then begin
    if CoordinationQmgrPage.Values[0] = '' then begin
      MsgBox('You must enter coordination queue manager name.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[1] = '' then begin
      MsgBox('You must enter coordination queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[2] = '' then begin
      MsgBox('You must enter coordination queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[3] = '' then begin
      MsgBox('You must enter coordination queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else if CurPageID = CommandQmgrPage.ID then begin
    if CommandQmgrPage.Values[0] = '' then begin
      MsgBox('You must enter command queue manager name.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[1] = '' then begin
      MsgBox('You must enter command queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[2] = '' then begin
      MsgBox('You must enter command queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[3] = '' then begin
      MsgBox('You must enter command queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else if CurPageID =  AgentNamePage.ID then begin
    if AgentNamePage.Values[0] = '' then begin
      MsgBox('You must enter Agent name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[1] = '' then begin
      MsgBox('You must enter agent queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[2] = '' then begin
      MsgBox('You must enter agent queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[3] = '' then begin
      MsgBox('You must enter agent queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[4] = '' then begin
      MsgBox('You must enter agent queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else
      Result := True;
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 := '';

  S := S + Space + 'Data Folder' + Space + ConfigDataPathPage.Values[0] + NewLine;

  S := S + Space + 'Coordination Queue Manager Name' + Space + CoordinationQmgrPage.Values[0] + NewLine;
  S := S + Space + 'Coordination Queue Manager Host Name' + Space + CoordinationQmgrPage.Values[1] + NewLine;
  S := S + Space + 'Coordination Queue Manager Port' + Space + CoordinationQmgrPage.Values[2] + NewLine;
  S := S + Space + 'Coordination Queue Manager Channel Name' + Space + CoordinationQmgrPage.Values[3] + NewLine;

  S := S + NewLine;

  S := S + Space + 'Command Queue Manager Name' + Space + CommandQmgrPage.Values[0] + NewLine;
  S := S + Space + 'Command Queue Manager Host Name' + Space + CommandQmgrPage.Values[1] + NewLine;
  S := S + Space + 'Command Queue Manager Port' + Space + CommandQmgrPage.Values[2] + NewLine;
  S := S + Space + 'Command Queue Manager Channel Name' + Space + CommandQmgrPage.Values[3] + NewLine;

  S := S + NewLine;

  S := S + Space + 'Agent Name' + Space + AgentNamePage.Values[0] + NewLine;
  S := S + Space + 'Agent Queue Manager Name' + Space + AgentNamePage.Values[1] + NewLine;
  S := S + Space + 'Agent Queue Manager Host Name' + Space + AgentNamePage.Values[2] + NewLine;
  S := S + Space + 'Agent Queue Manager Port' + Space + AgentNamePage.Values[3] + NewLine;
  S := S + Space + 'Agent Queue Manager Channel Name' + Space + AgentNamePage.Values[4] + NewLine;

  S := S + NewLine;
  Result := S;
end;

function GetUser(Param: String): String;
begin
  { Return a user value }
  { Could also be split into separate GetUserName and GetUserCompany functions }
  if Param = 'Name' then
    Result := CoordinationQmgrPage.Values[0]
  else if Param = 'Company' then
    Result := CoordinationQmgrPage.Values[1];
end;

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; ************************************************************************
; Copyright (c) IBM Corporation 2016
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
; http://www.apache.org/licenses/LICENSE-2.0
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific
;  Contributors:
;    Shashikanth Rao T - Initial Contribution
;***************************************************************************
; This installation script is developed using a trial version of Inno Setup.
; The script demonstrates how MFT redistributable Agent binaries can be
; bundled into another product's installation package and deployed.
;***************************************************************************
#define MyAppName "MFT Agent"
#define MyAppVersion "1.5"
#define MyAppPublisher "IBM Corp"
#define MyAppURL "http://www.ibm.com/"

[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={{4E1BA108-409D-45CA-90D7-BCD7B6A04C15}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=C:\MFT91\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}
Compression=lzma
SolidCompression=yes
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes

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

[Files]
Source: "C:\Downloads\IBM-MQFA-Redist-Win64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Registry]
; set PATH
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName:"BFG_DATA"; ValueData:"{code:GetAgentConfigDataPath}" ; Flags: preservestringtype ;

[Run]
;Flags: "64bit"

; Setup Coordination
Filename: "{app}\bin\fteSetupCoordination.cmd"; Parameters: " -coordinationQMgr {code:GetCoordinationQmgrName} -coordinationQMgrHost {code:GetCoordinationQmgrNameHost} -coordinationQMgrPort {code:GetCoordinationQmgrNamePort} -coordinationQMgrChannel {code:GetCoordinationQmgrNameChannel} -f > {app}\instlog.txt"

; Setup Command
Filename: "{app}\bin\fteSetupCommands.cmd"; Parameters: " -p {code:GetCoordinationQmgrName} -connectionQMgr  {code:GetCommandQmgrName} -connectionQMgrHost {code:GetCommandQmgrNameHost} -coordinationQMgrPort {code:GetCommandQmgrNamePort} -connectionQMgrChannel  {code:GetCommandQmgrNameChannel} -f >> {app}\instlog.txt"

; Setup an agent
Filename: "{app}\bin\fteCreateAgent.cmd"; Parameters: " -p {code:GetCoordinationQmgrName} -agentName {code:GetAgentName} -agentQMgr {code:GetAgentQmgrName} -agentQMgrHost  {code:GetAgentQmgrHost} -agentQMgrPort {code:GetAgentQmgrPort} -agentQMgrChannel  {code:GetAgentQmgrChannel} -f >> {app}\instlog.txt"

[Code]
const
  OffsetPixels = 11;

procedure OffsetPageItem(Page: TInputQueryWizardPage; Index,
  Offset: Integer);
begin
  Page.Edits[Index].Top := Page.Edits[Index].Top + Offset;
  Page.PromptLabels[Index].Top := Page.PromptLabels[Index].Top +
    Offset;
end;

var
  ConfigDataPathPage: TInputQueryWizardPage;
  CoordinationQmgrPage: TInputQueryWizardPage;
  CommandQmgrPage: TInputQueryWizardPage;
  AgentNamePage: TInputQueryWizardPage;
  Index: Integer;

{ Get Coordination queue manager details}
function GetCoordinationQmgrName(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[0];
end;

function GetCoordinationQmgrNameHost(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[1];
end;

function GetCoordinationQmgrNamePort(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[2];
end;

function GetCoordinationQmgrNameChannel(Value: string): string;
begin
  Result := CoordinationQmgrPage.Values[3];
end;

{Get Command queue manager details}
function GetCommandQmgrName(Value: string): string;
begin
  Result := CommandQmgrPage.Values[0];
end;

function GetCommandQmgrNameHost(Value: string): string;
begin
  Result := CommandQmgrPage.Values[1];
end;

function GetCommandQmgrNamePort(Value: string): string;
begin
  Result := CommandQmgrPage.Values[2];
end;

function GetCommandQmgrNameChannel(Value: string): string;
begin
  Result := CommandQmgrPage.Values[3];
end;

{ Get Agent details}
function GetAgentName(Value: string): string;
begin
  Result := AgentNamePage.Values[0];
end;

function GetAgentQmgrName(Value: string): string;
begin
  Result := AgentNamePage.Values[1];
end;

function GetAgentQmgrHost(Value: string): string;
begin
  Result := AgentNamePage.Values[2];
end;

function GetAgentQmgrPort(Value: string): string;
begin
  Result := AgentNamePage.Values[3];
end;

function GetAgentQmgrChannel(Value: string): string;
begin
  Result := AgentNamePage.Values[4];
end;

function GetAgentConfigDataPath(Value: string): string;
begin
  Result := ConfigDataPathPage.Values[0];
end;

{End of Gets}

#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif

function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
  external 'SetEnvironmentVariable{#AW}@kernel32.dll stdcall';

procedure SetEnvPath;
begin
  if not SetEnvironmentVariable('BFG_DATA', '{code:GetAgentConfigDataPath}') then
    MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;

procedure InitializeWizard;
begin
  { Create the Configuration Data Path page}
  ConfigDataPathPage := CreateInputQueryPage(wpSelectDir,
    'Configure Data Path', '',
    'Please specify path for storing configuration data, then click Next.');
  ConfigDataPathPage.Add('Configuration Data Path:', False);

  { Create the Coordination Queue Manager Setup page}
  CoordinationQmgrPage := CreateInputQueryPage(ConfigDataPathPage.ID,
    'Coordination Queue Manager Setup', '',
    'Please specify Coordination Queue Manager information, then click Next.');
  CoordinationQmgrPage.Add('Queue Manager Name:', False);
  CoordinationQmgrPage.Add('Host Name:', False);
  CoordinationQmgrPage.Add('Port:', False);
  CoordinationQmgrPage.Add('Channel:', False);

  CoordinationQmgrPage.Values[0] := ExpandConstant('COORDQM');
  CoordinationQmgrPage.Values[1] := ExpandConstant('coordqm.mycomp.com');
  CoordinationQmgrPage.Values[2] := ExpandConstant('1414');
  CoordinationQmgrPage.Values[3] := ExpandConstant('APPSVRCONN');

  { Create the Command Queue Manager Setup page}
  CommandQmgrPage := CreateInputQueryPage(CoordinationQmgrPage.ID,
    'Command Queue Manager Setup', '',
    'Please specify Command Queue Manager information, then click Next..');
  CommandQmgrPage.Add('Queue Manager Name)', False);
  CommandQmgrPage.Add('Host Name',False);
  CommandQmgrPage.Add('Port', False);
  CommandQmgrPage.Add('Channel Name', False);

  CommandQmgrPage.Values[0] := ExpandConstant('CMDQM');
  CommandQmgrPage.Values[1] := ExpandConstant('cmdqm.mycomp.com');
  CommandQmgrPage.Values[2] := ExpandConstant('1414');
  CommandQmgrPage.Values[3] := ExpandConstant('APPSVRCONN');

  { Create the Agent Setup page}
  AgentNamePage := CreateInputQueryPage(CommandQmgrPage.ID,
    'Agent Setup', '',
    'Please provide information required for creating an agent');
  Index := AgentNamePage.Add('Agent Name:', False);
  Index := AgentNamePage.Add('Queue Manager Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Host Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Port :', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);
  Index := AgentNamePage.Add('Channel Name:', False);
  OffsetPageItem(AgentNamePage, Index, -Index * OffsetPixels);

  AgentNamePage.Values[0] := ExpandConstant('ZIPAGENT');
  AgentNamePage.Values[1] := ExpandConstant('ZIPAGENTQM');
  AgentNamePage.Values[2] := ExpandConstant('zipagentqm.mycomp.com');
  AgentNamePage.Values[3] := ExpandConstant('1414');
  AgentNamePage.Values[4] := ExpandConstant('APPSVRCONN');

end;

procedure RegisterPreviousData(PreviousDataKey: Integer);

begin
  { Store the settings so we can restore them next time }
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrName', CoordinationQmgrPage.Values[0]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNameHost', CoordinationQmgrPage.Values[1]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNamePort', CoordinationQmgrPage.Values[2]);
  SetPreviousData(PreviousDataKey, 'CoordinationQmgrNameChannel', CoordinationQmgrPage.Values[3]);

  SetPreviousData(PreviousDataKey, 'CommandQmgrName', CommandQmgrPage.Values[0]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNameHost', CommandQmgrPage.Values[1]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNamePort', CommandQmgrPage.Values[2]);
  SetPreviousData(PreviousDataKey, 'CommandQmgrNameChannel', CommandQmgrPage.Values[3]);

  SetPreviousData(PreviousDataKey, 'AgentName', AgentNamePage.Values[0]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrName', AgentNamePage.Values[1]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNameHost', AgentNamePage.Values[2]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNamePort', AgentNamePage.Values[3]);
  SetPreviousData(PreviousDataKey, 'AgentQmgrNameChannel', AgentNamePage.Values[4]);
end;

function NextButtonClick(CurPageID: Integer): Boolean;

begin
  { Validate certain pages before allowing the user to proceed }
  if CurPageID = CoordinationQmgrPage.ID then begin
    if CoordinationQmgrPage.Values[0] = '' then begin
      MsgBox('You must enter coordination queue manager name.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[1] = '' then begin
      MsgBox('You must enter coordination queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[2] = '' then begin
      MsgBox('You must enter coordination queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if CoordinationQmgrPage.Values[3] = '' then begin
      MsgBox('You must enter coordination queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else if CurPageID = CommandQmgrPage.ID then begin
    if CommandQmgrPage.Values[0] = '' then begin
      MsgBox('You must enter command queue manager name.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[1] = '' then begin
      MsgBox('You must enter command queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[2] = '' then begin
      MsgBox('You must enter command queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if CommandQmgrPage.Values[3] = '' then begin
      MsgBox('You must enter command queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else if CurPageID =  AgentNamePage.ID then begin
    if AgentNamePage.Values[0] = '' then begin
      MsgBox('You must enter Agent name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[1] = '' then begin
      MsgBox('You must enter agent queue manager host name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[2] = '' then begin
      MsgBox('You must enter agent queue manager port number.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[3] = '' then begin
      MsgBox('You must enter agent queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else if AgentNamePage.Values[4] = '' then begin
      MsgBox('You must enter agent queue manager channel name.', mbError, MB_OK);
      Result := False;
    end else begin
      Result := True;
    end;
  end else
      Result := True;
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 := '';

  S := S + Space + 'Data Folder' + Space + ConfigDataPathPage.Values[0] + NewLine;

  S := S + Space + 'Coordination Queue Manager Name' + Space + CoordinationQmgrPage.Values[0] + NewLine;
  S := S + Space + 'Coordination Queue Manager Host Name' + Space + CoordinationQmgrPage.Values[1] + NewLine;
  S := S + Space + 'Coordination Queue Manager Port' + Space + CoordinationQmgrPage.Values[2] + NewLine;
  S := S + Space + 'Coordination Queue Manager Channel Name' + Space + CoordinationQmgrPage.Values[3] + NewLine;

  S := S + NewLine;

  S := S + Space + 'Command Queue Manager Name' + Space + CommandQmgrPage.Values[0] + NewLine;
  S := S + Space + 'Command Queue Manager Host Name' + Space + CommandQmgrPage.Values[1] + NewLine;
  S := S + Space + 'Command Queue Manager Port' + Space + CommandQmgrPage.Values[2] + NewLine;
  S := S + Space + 'Command Queue Manager Channel Name' + Space + CommandQmgrPage.Values[3] + NewLine;

  S := S + NewLine;

  S := S + Space + 'Agent Name' + Space + AgentNamePage.Values[0] + NewLine;
  S := S + Space + 'Agent Queue Manager Name' + Space + AgentNamePage.Values[1] + NewLine;
  S := S + Space + 'Agent Queue Manager Host Name' + Space + AgentNamePage.Values[2] + NewLine;
  S := S + Space + 'Agent Queue Manager Port' + Space + AgentNamePage.Values[3] + NewLine;
  S := S + Space + 'Agent Queue Manager Channel Name' + Space + AgentNamePage.Values[4] + NewLine;

  S := S + NewLine;
  Result := S;
end;

function GetUser(Param: String): String;
begin
  { Return a user value }
  { Could also be split into separate GetUserName and GetUserCompany functions }
  if Param = 'Name' then
    Result := CoordinationQmgrPage.Values[0]
  else if Param = 'Company' then
    Result := CoordinationQmgrPage.Values[1];
end;