I need to browse or create a new directory at the end of my setup for my database files.
I create an TInputDirWizardPage to choose the directory, and I use a button to launch database installation.
My problem is that the new directory is not created and installation of database fails.
This is my code:
[Code]
var
Page0: TInputQueryWizardPage;
Page1: TInputDirWizardPage;
{ Launch DB CLIP installation }
procedure ButtonOnClick(Sender: TObject);
var
Params: string;
ScriptPath: string;
ResultCode: Integer;
DBPath: string;
Server: String;
Instance: String;
SQL_User: String;
SQL_Password: String;
begin
DBPath := Page1.Values[0];
Server:= Page0.Values[0];
Instance:= Page0.Values[1];
SQL_User:= Page0.Values[2];
SQL_Password:= Page0.Values[3];
ScriptPath := ExpandConstant('"{app}\DB\Create Database 2.12.3.sql"');
Params := '-v CLIPDATA="'+DBPath+'" CLIPINDEX="'+DBPath+'" CLIPLOG="'+DBPath+'" -S '+Server+'\'+Instance+' -U '+SQL_User+' -P '+SQL_Password+' -i '+ScriptPath ;
if MsgBox('' + Params + '', mbInformation, mb_YesNo) = idYes then
Exec ('sqlcmd',Params, '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
Exit;
end;
procedure InitializeWizard();
var
DBButton: TNewButton;
begin
Page0 := CreateInputQueryPage(wpInfoAfter,
'SQL Informations', '',
'Please specify Server and Instance name , then click Next.');
Page0.Add('Server:', False);
Page0.Add('Instance:', False);
Page0.Add('SQL User:', False);
Page0.Add('SQL Password:', True);
Page0.Values[0] := ('localhost');
Page0.Values[1] := ('CLIP');
Page0.Values[2] := ('sa');
Page0.Values[3] := ('clip');
Page1 := CreateInputDirPage(Page0.ID,
'Select CLIP Database files Location', '',
'CLIP DB data files will be stored in the following folder.'#13#10#13#10 +
'To continue, click Next. ' +
'If you would like to select a different folder, click Browse.',
False, 'New Folder');
Page1.Add('Database Folder');
Page1.Values[0] := ExpandConstant('{pf}\CLIP\CLIP_DATA\DB\');
DBButton := TNewButton.Create(Page1);
DBButton.Left := ScaleX(16);
DBButton.Top := ScaleY(205);
DBButton.Width := ScaleX(100);
DBButton.Height := ScaleY(25);
DBButton.Caption := 'Install DB CLIP';
DBButton.OnClick := #ButtonOnClick;
DBButton.Parent := Page1.Surface;
end;
CreateInputDirPage does not create the selected directory on its own.
The Make New Folder button does not create a physical folder. It only creates a virtual node in the tree.
I'm aware that this somewhat contradicts the documentation, which says:
Make New Folder button will be shown that creates a new folder with the specified default name.
If you want to really create a physical folder for the selected path, use CreateDir function in your ButtonOnClick handler.
if not DirExists(DBPath) then
begin
CreateDir(DBPath);
end;
Related
I'm trying to write an installer in Inno Setup that includes a page where a TNewCheckListBox is created and then used to populate a selection of choices on the next page:
var
ListBox: TNewCheckListBox;
SelectedConfigs: array of Integer;
function ConfigurationPage(): Integer;
var
Page: TWizardPage;
I: Integer;
begin
Page := CreateCustomPage(wpSelectComponents, 'Select Configuration',
'Please select the configuration you would like to install to.');
ListBox := TNewCheckListBox.Create(Page);
ListBox.Parent := Page.Surface;
ListBox.Left := ScaleX(0);
ListBox.Top := ScaleY(0);
ListBox.Width := Page.SurfaceWidth;
ListBox.Height := Page.SurfaceHeight;
ListBox.BorderStyle := bsNone;
for I := 0 to GetArrayLength(ConfigurationNames) - 1 do
begin
ListBox.AddCheckBox(ConfigurationNames[I], '', 0, False, True, False, False, nil);
end;
ListBox.ItemIndex := 0;
Result := Page.ID;
end;
procedure PortSelectionPage(PageID: Integer);
var
Page: TWizardPage;
ArrayLength: Integer;
I: Integer;
begin
Page := CreateCustomPage(PageID, 'Select Port',
'Please select the port you want the configurations to receive on.');
for I := 0 to ListBox.Items.Count - 1 do
begin
Log(Format('ListBox[%d], %s is checked? %d', [I, ListBox.Items[I], ListBox.Checked[I]]));
if ListBox.Checked[I] then
begin
ArrayLength := GetArrayLength(SelectedConfigs);
SetArrayLength(SelectedConfigs, ArrayLength + 1);
SelectedConfigs[ArrayLength] := I;
Log(Format('Config %d was selected...', [I]));
end;
end;
end;
procedure InitializeWizard;
var
PageID: Integer;
begin
PageID := ConfigurationPage;
PortSelectionPage(PageID);
end;
The problem I'm having is that, regardless of the selections I make in the ConfigurationPage procedure, the SelectedConfigs array is not being updated and my debugging messages are showing that none of the options are selected. Before creating the PortSelectionPage procedure, the code lived on the CurStepChanged event handler so I'm not sure if the issue is with my having moved the code to a different page or if there's something else going on here. Do I need to force an update to the component or should I be using event handlers instead? If so, how would I implement one for this usecase?
Your whole code is executed from InitializeWizard event function. Hence even before the installer wizard is shown.
You have to query the checkbox states only after the user changes them. For example, from some of these events:
NextButtonClick
CurStepChanged
CurPageChanged
I would like to create a custom Inno Setup page that will be displayed at the very beginning of installation, with 3 radio buttons to select from. That selection should set the value in #define BinVer. Currently I'm forced to make 3 separate installers, but I prefer to have just one with such feature. I'm setting it up like that for each exe:
#define BinVer "111111", in another compilation I change it to #define BinVer "222222", and finaly I have #define BinVer "333333" for the third compilation. I'm using this define in such situations li ke that:
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
case CurUninstallStep of
usPostUninstall:
begin
CreateDir(ExpandConstant('{app}\bin\{#BinVer}\files'));
end;
end;
end;
or
Source: "{#CompPath}\Folder\sed.exe"; DestDir: "{app}\bin\{#BinVer}\files\gui\unbound\"; Flags: deleteafterinstall
So far I have tried something like this, but it's just very beginning, not sure what to do next, I'm not that good with programming it:
[Code]
procedure InitializeWizard();
var
Page: TInputOptionWizardPage;
begin
Page := CreateInputOptionPage(wpWelcome, '', '', '', False, False);
Page.AddEx('Radio button 1', 0, True);
Page.AddEx('Radio button 2', 0, True);
Page.AddEx('Radio button 3', 0, True);
end;
Also tried something like that (but I don't know if this is correct way to achieve this, it's not even compiling without errors):
[Code]
var
BinVer: string;
function InitializeSetup(): Boolean;
var
Page: TInputOptionWizardPage;
begin
Page := CreateInputOptionPage(wpWelcome, 'Select BinVer', 'Select BinVer', '', False, False);
Page.Add('BinVer 1', '111111');
Page.Add('BinVer 2', '222222');
Page.Add('BinVer 3', '333333');
Page.DefaultValueIndex := 0; // initially select the first radio button
Result := True;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
Page: TInputOptionWizardPage;
begin
Result := True;
if CurPageID = wpWelcome then
begin
Page := GetInputOptionPage(wpWelcome);
case Page.SelectedValueIndex of
0: BinVer := '111111';
1: BinVer := '222222';
2: BinVer := '333333';
end;
end;
end;
You cannot change a value of a preprocessor variable (used on compile-time) on runtime.
But you do not have to. You want to use the value on runtime from Pascal Code. And you already have the value stored to runtime Pascal variable (BinVer: string). So use that:
CreateDir(ExpandConstant('{app}\bin\' + BinVer + '\files'));
Though you do not really need to store the value to the global variable either. You can query the "InputOptionPage" when needed.
Example of full code, linking the selection to the [Files] section entry destination:
[Files]
Source: "{#CompPath}\Folder\sed.exe"; \
DestDir: "{app}\bin\{code:GetBinVer}\files\gui\unbound\"; \
Flags: deleteafterinstall
[Code]
var
InputOptionPage: TInputOptionWizardPage;
procedure InitializeWizard();
begin
InputOptionPage := CreateInputOptionPage(wpWelcome, '', '', '', False, False);
InputOptionPage.AddEx('Radio button 1', 0, True);
InputOptionPage.AddEx('Radio button 2', 0, True);
InputOptionPage.AddEx('Radio button 3', 0, True);
// initially select the first radio button
InputOptionPage.SelectedValueIndex := 0;
end;
function GetBinVer(Param: string): string;
begin
case InputOptionPage.SelectedValueIndex of
0: BinVer := '111111';
1: BinVer := '222222';
2: BinVer := '333333';
else RaiseException('Unexpected selection');
end;
end;
(not tested)
Though linking it to a code in CurUninstallStepChanged is more complicated, that happens in another (uninstaller) process. So you will have to store the selection/BinVer somewhere (e.g. Windows Registry), where you will load it from in the uninstaller. You might by able to use SetPreviousData/GetPreviousData.
How Should i modify my code so i can let user detemine the path of second directory (path of java in script)
I used this Command befor i try in mode:
mysetup.exe /DIR="C:\test"
installation path
second path
And how to let user to choose one of these Component1 or component2 or both.
choose component to be installed
#define AppName "My App"
[Setup]
AppName={#AppName}
AppVersion=1
DefaultDirName={code:getInstallDir}\{#AppName}
;DefaultDirName={pf}\My App
DisableDirPage=yes
[Files]
[Code]
#include 'System.iss'
var
Page: TInputDirWizardPage;
UsagePage: TInputOptionWizardPage;
function InputDirPageNextButtonClick(Sender: TWizardPage): Boolean;
begin
{ Use the first path as the "destination path" }
WizardForm.DirEdit.Text := Page.Values[0];
Result := True;
end;
procedure InitializeWizard;
begin
Page := CreateInputDirPage(wpWelcome,
'Destination', '',
'Where should App be installed?',
False, 'New Folder');
Page.Add('App path');
Page.Values[0] := WizardForm.DirEdit.Text;
UsagePage := CreateInputOptionPage(wpWelcome,
'Installation', 'choose component',
'please choose one!:',
False, False);
UsagePage.Add('Component1');
UsagePage.Add('Component2');
Page.OnNextButtonClick := #InputDirPageNextButtonClick;
Page := CreateInputDirPage(wpSelectDir,
'Java path', '',
'please specify Java Folder:', False, '');
Page.Add('Java');
Page.OnNextButtonClick := #InputDirPageNextButtonClick;
end;
If I understand your question: You are looking for a way to use a custom command-line parameter to populate the directory value on a custom directory page. Here's one way:
[Code]
var
CustomPage: TInputDirWizardPage;
CustomPath: string;
function InitializeSetup(): Boolean;
begin
result := true;
CustomPath := ExpandConstant('{param:CustomPath}');
end;
procedure InitializeWizard();
begin
CustomPage := CreateInputDirPage(wpSelectDir,
'Select Custom Path',
'What custom path do you want?',
'Select a directory.',
false,
'');
CustomPage.Add('Custom path:');
CustomPage.Values[0] := CustomPath;
end;
With this in your [Code] section, running the setup program with a /CustomPath="directory name" parameter will set the value on the form to the parameter from the command line.
I'm trying to build a setup for my application , which contains two parts: server and client. The client part needs to have an IP address entered by the user. I'm using a custom page to prompt for the IP address. But I need to display the custom page, only if user selects "Client" component.
[Components]
Name: "Serveur"; Description: "Server installation"; Types: Serveur; Flags: exclusive;
Name: "Client"; Description: "Client installation"; Types: Client; Flags: exclusive
[Types]
Name: "Serveur"; Description: "Server Installation"
Name: "Client"; Description: "Client Installation"
[Code]
var
Page: TInputQueryWizardPage;
ip: String;
procedure InitializeWizard();
begin
Page := CreateInputQueryPage(wpWelcome,
'IP Adresse du serveur', 'par exemple : 192.168.1.120',
'Veuillez introduire l''adresse IP du serveur :');
Page.Add('IP :', False);
Page.Values[0] := ExpandConstant('192.168.x.x');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if (CurPageID = Page.ID) then
begin
ip := Page.Values[0];
SaveStringToFile('C:\Program Files\AppClient\ipAddress.txt', ip, False);
end;
Result := True;
end;
Your custom page must go only after the "Select Components" page, so you need to pass wpSelectComponents to CreateInputQueryPage:
var
Page: TInputQueryWizardPage;
procedure InitializeWizard();
begin
Page :=
CreateInputQueryPage(
wpSelectComponents, 'IP Adresse du serveur', 'par exemple : 192.168.1.120',
'Veuillez introduire l''adresse IP du serveur :');
Page.Add('IP :', False);
Page.Values[0] := '192.168.x.x';
end;
(Also note that there's no point in calling ExpandConstant on a string literal that does not include any constants).
Skip the custom page, when the "Client" component is not selected:
function IsClient: Boolean;
begin
Result := IsComponentSelected('Client');
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := False;
if PageID = Page.ID then
begin
Result := not IsClient;
end;
end;
See also Skipping custom pages based on optional components in Inno Setup.
Well behaving installer should not make any modifications to a system, before the user finally confirms the installation. So make any changes only, once installation really starts, not already when user click "Next" on the custom page.
Also, you cannot hard-code a path to the file, use {app} constant.
procedure CurStepChanged(CurStep: TSetupStep);
var
IP: string;
begin
if (CurStep = ssInstall) and IsClient() then
begin
IP := Page.Values[0];
SaveStringToFile(ExpandConstant('{app}\ipAddress.txt'), IP, False);
end;
end;
Is the following code it right or not and, if it is wrong, please correct it.
Note: I want to open the file with "WordPad.exe" not with "Microsoft Office Word" until if "Microsoft Office Word" is the default program.
My code:
function InitializeSetup: Boolean;
var
S: AnsiString;
begin
// Show the contents of Readme.txt (non Unicode) in a message box
ExtractTemporaryFile('Info.rtf');
Result := True;
end;
procedure AboutButtonOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', ExpandConstant('{tmp}\Info.rtf'), '', '', SW_SHOWNORMAL, ewNoWait,
ErrorCode);
end;
ShellExec('open','Documentname'....); will open with the program associated with the extension of the file. If there is no program associated it will prompt you to select which program you want to view it with.
You could look for WordPad.exe and if it's found you could call ShellExec using the WordPad.EXE directly. Then pass the documentName as a parameter.
Updated with function to do this
procedure OpenDocumentInWordPad(Document : String);
var
WordPad : String;
ErrorCode : Integer;
begin
// Typical Location on XP and later.
WordPad := ExpandConstant('{pf}') + '\Windows NT\Accessories\WordPad.exe'
// Find word pad
if Not FileExists(WordPad) then
begin
// Location in Windows 95/98
WordPad := ExpandConstant('{pf}') + '\Accessories\WordPad.exe'
if Not FileExists(WordPad) then
begin
// Fall back to anything associated with document.
WordPad := Document;
Document := '';
end;
end;
if not ShellExec('open',WordPad,Document,'',SW_SHOW,ewNoWait,ErrorCode) then
begin
MsgBox(SysErrorMessage(ErrorCode),mbError,MB_OK);
end;
end;