can anyone tell me how to connect to SQL 2008 using windows authentication thru inno? Currently I'm using ado connection to connect to SQL from inno, the user needs windows authentication option too. Please suggest.
It's enough to remove the credential attributes from your connection string (User Id and Password) when we are talking about the example you've linked in your question and include one of the following:
Integrated Security=SSPI;
Trusted_Connection=True;
This answer is based just on this topic, I haven't tested it.
Update:
I don't know if that's what you want to do, but I'll post it here. The following script creates a custom page with radio buttons letting user choose authentication mode and optionally fill the credentials.
Important:
There is no protection against SQL injection for those credential fields!
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
const
LT_WindowsAuthentication = 0;
LT_SQLServerAuthentication = 1;
var
LoginType: Integer;
UsernameEdit: TNewEdit;
UsernameLabel: TLabel;
PasswordEdit: TNewEdit;
PasswordLabel: TLabel;
procedure OnLoginTypeChange(Sender: TObject);
var
EditColor: TColor;
LabelColor: TColor;
begin
LoginType := TNewRadioButton(Sender).Tag;
UsernameEdit.Enabled := LoginType = LT_SQLServerAuthentication;
PasswordEdit.Enabled := LoginType = LT_SQLServerAuthentication;
case LoginType of
LT_WindowsAuthentication:
begin
EditColor := clBtnFace;
LabelColor := clGray;
end;
LT_SQLServerAuthentication:
begin
EditColor := clWindow;
LabelColor := clBlack;
end;
end;
UsernameEdit.Color := EditColor;
PasswordEdit.Color := EditColor;
UsernameLabel.Font.Color := LabelColor;
PasswordLabel.Font.Color := LabelColor;
end;
procedure InitializeWizard;
var
LoginPage: TWizardPage;
begin
LoginPage := CreateCustomPage(wpWelcome, 'DB Login', 'Choose a login type to continue...');
with TNewRadioButton.Create(WizardForm) do
begin
Parent := LoginPage.Surface;
Left := 0;
Top := 0;
Width := LoginPage.Surface.ClientWidth;
Checked := True;
Tag := 0;
Caption := 'Windows authentication';
OnClick := #OnLoginTypeChange;
end;
with TNewRadioButton.Create(WizardForm) do
begin
Parent := LoginPage.Surface;
Left := 0;
Top := 20;
Width := LoginPage.Surface.ClientWidth;
Checked := False;
Tag := 1;
Caption := 'SQL Server authentication';
OnClick := #OnLoginTypeChange;
end;
UsernameLabel := TLabel.Create(WizardForm);
with UsernameLabel do
begin
Parent := LoginPage.Surface;
Left := 12;
Top := 44;
Width := 200;
Font.Color := clGray;
Font.Style := [fsBold];
Caption := 'Username';
end;
UsernameEdit := TNewEdit.Create(WizardForm);
with UsernameEdit do
begin
Parent := LoginPage.Surface;
Left := 12;
Top := UsernameLabel.Top + UsernameLabel.Height + 6;
Width := 200;
Color := clBtnFace;
Enabled := False;
end;
PasswordLabel := TLabel.Create(WizardForm);
with PasswordLabel do
begin
Parent := LoginPage.Surface;
Left := 12;
Top := UsernameEdit.Top + UsernameEdit.Height + 6;
Width := 200;
Font.Color := clGray;
Font.Style := [fsBold];
Caption := 'Password';
end;
PasswordEdit := TNewEdit.Create(WizardForm);
with PasswordEdit do
begin
Parent := LoginPage.Surface;
Left := 12;
Top := PasswordLabel.Top + PasswordLabel.Height + 6;
Width := 200;
Color := clBtnFace;
Enabled := False;
PasswordChar := '*';
end;
end;
// and in your connection event then use
case LoginType of
LT_WindowsAuthentication:
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' + // provider
'Data Source=Default\SQLSERVER;' + // server name
'Initial Catalog=Northwind;' + // default database
'Integrated Security=SSPI;'; // trusted connection
LT_SQLServerAuthentication:
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' + // provider
'Data Source=Default\SQLSERVER;' + // server name
'Initial Catalog=Northwind;' + // default database
'User Id=' + UsernameEdit.Text + ';' + // user name
'Password=' + PasswordEdit.Text + ';'; // password
end;
Related
I'm trying to create something like this:
I want the check box to be hidden behind the lock image, and clicking on it will open a form requesting code entry, and if the code is correct the image will be removed and the check box will be available.
Here's what I tried:
[files]
Source: "Lock.bmp"; Flags: dontcopy
{...}
[code]
var
CustomFuncPage: TWizardPage;
CBAdvFunctions: TNewCheckBox;
Locked: TBitmapImage;
procedure OnClickLock(Sender: TObject);
var
PassForm: TSetupForm;
Edit: TNewEdit;
OKButton, CancelButton: TNewButton;
begin
PassForm := CreateCustomForm();
PassForm.ClientWidth := ScaleX(256);
PassForm.ClientHeight := ScaleY(128);
PassForm.Caption := 'Password required';
Edit := TNewEdit.Create(PassForm);
Edit.Top := ScaleY(10);
Edit.Left := ScaleX(10);
Edit.Width := PassForm.ClientWidth - ScaleX(20);
Edit.Height := ScaleY(23);
Edit.Anchors := [akLeft, akTop, akRight];
Edit.Parent := PassForm;
OKButton := TNewButton.Create(PassForm);
OKButton.Parent := PassForm;
OKButton.Caption := 'OK';
OKButton.Left := PassForm.ClientWidth - ScaleX(166);
OKButton.Top := PassForm.ClientHeight - ScaleY(33);
OKButton.Height := ScaleY(23);
OKButton.Anchors := [akRight, akBottom]
OKButton.ModalResult := mrOk;
OKButton.Default := True;
CancelButton := TNewButton.Create(PassForm);
CancelButton.Parent := PassForm;
CancelButton.Caption := 'Cancel';
CancelButton.Left := PassForm.ClientWidth - ScaleX(85);
CancelButton.Top := PassForm.ClientHeight - ScaleY(33);
CancelButton.Height := ScaleY(23);
CancelButton.Anchors := [akRight, akBottom]
CancelButton.ModalResult := mrCancel;
CancelButton.Cancel := True;
PassForm.ActiveControl := Edit;
if PassForm.ShowModal() = mrOk then
begin
if Edit.Text = '1234' then
begin
Locked.Free;
PassForm.Free;
end else
begin
MsgBox('Password incorrect', mbError, MB_OK);
PassForm.Free;
end;
end else
begin
PassForm.Free;
end;
end;
Procedure InitializeWizard;
begin
CustomFuncPage := CreateCustomPage(wpSelectProgramGroup, {...}, {...});
CBAdvFunctions := TNewCheckBox.Create(CustomFuncPage);
CBAdvFunctions.Parent := CustomFuncPage.Surface;
CBAdvFunctions.Top := 0;
CBAdvFunctions.Left := 0;
CBAdvFunctions.Caption := 'Advanced Functions'
CBAdvFunctions.Width := ScaleX(130);
CBAdvFunctions.Cursor := 1;
CBAdvFunctions.SendToBack;
ExtractTemporaryFile('Lock.bmp');
Locked := TBitmapImage.Create(CustomFuncPage);
Locked.Parent := CustomFuncPage.Surface;
Locked.Bitmap.LoadFromFile(ExpandConstant('{tmp}\Lock.bmp'));
Locked.Bitmap.AlphaFormat := afPremultiplied;
Locked.SetBounds(0, 0, CBAdvFunctions.Width, CBAdvFunctions.Height);
Locked.Stretch := True;
Locked.BringToFront;
Locked.OnClick := #OnClickLock;
{...}
And this is the result:
This is the image I used:
I tried a few ways, but was unable to get the image to cover the checkbox.
Maybe someone has an idea?
By the way, maybe someone has an explanation for why the background of the image is not transparent?
I have added new checkboxes to my inno setup tasks page but i dont know how to make them work with the tasks, i want them to work with the [Tasks] zone in the script.
[Tasks]
Name: "Newcheckboox1"; Description: "Newcheckbox1"; MinVersion: 0.0,5.0
Name: "Newcheckboox2"; Description: "Newcheckbox2"; MinVersion: 0.0,5.0
other tasks checkboxes here.........
Here an image:
Here the code generated when the checkboxes are added:
[Code]
{ RedesignWizardFormBegin } // Don't remove this line!
// Don't modify this section. It is generated automatically.
var
NewGroupBox1: TNewGroupBox;
NewCheckBox1: TNewCheckBox;
NewCheckBox2: TNewCheckBox;
NewCheckBox3: TNewCheckBox;
NewGroupBox2: TNewGroupBox;
NewCheckBox4: TNewCheckBox;
NewCheckBox5: TNewCheckBox;
NewGroupBox3: TNewGroupBox;
NewCheckBox6: TNewCheckBox;
NewCheckBox7: TNewCheckBox;
NewCheckBox8: TNewCheckBox;
procedure RedesignWizardForm;
begin
with WizardForm.SelectTasksLabel do
begin
Visible := False;
Left := ScaleX(392);
end;
{ NewGroupBox1 }
NewGroupBox1 := TNewGroupBox.Create(WizardForm);
with NewGroupBox1 do
begin
Parent := WizardForm.SelectTasksPage;
Left := ScaleX(0);
Top := ScaleY(0);
Width := ScaleX(145);
Height := ScaleY(238);
Caption := 'NewGroupBox1';
end;
{ NewCheckBox1 }
NewCheckBox1 := TNewCheckBox.Create(WizardForm);
with NewCheckBox1 do
begin
Parent := NewGroupBox1;
Left := ScaleX(8);
Top := ScaleY(16);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox1';
end;
{ NewCheckBox2 }
NewCheckBox2 := TNewCheckBox.Create(WizardForm);
with NewCheckBox2 do
begin
Parent := NewGroupBox1;
Left := ScaleX(8);
Top := ScaleY(40);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox2';
end;
{ NewCheckBox3 }
NewCheckBox3 := TNewCheckBox.Create(WizardForm);
with NewCheckBox3 do
begin
Parent := NewGroupBox1;
Left := ScaleX(8);
Top := ScaleY(64);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox3';
end;
NewCheckBox1.TabOrder := 0;
NewCheckBox2.TabOrder := 1;
NewCheckBox3.TabOrder := 2;
{ NewGroupBox2 }
NewGroupBox2 := TNewGroupBox.Create(WizardForm);
with NewGroupBox2 do
begin
Parent := WizardForm.SelectTasksPage;
Left := ScaleX(152);
Top := ScaleY(0);
Width := ScaleX(265);
Height := ScaleY(97);
Caption := 'NewGroupBox2';
end;
{ NewCheckBox4 }
NewCheckBox4 := TNewCheckBox.Create(WizardForm);
with NewCheckBox4 do
begin
Parent := NewGroupBox2;
Left := ScaleX(8);
Top := ScaleY(16);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox4';
end;
{ NewCheckBox5 }
NewCheckBox5 := TNewCheckBox.Create(WizardForm);
with NewCheckBox5 do
begin
Parent := NewGroupBox2;
Left := ScaleX(8);
Top := ScaleY(40);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox5';
end;
NewCheckBox4.TabOrder := 0;
NewCheckBox5.TabOrder := 1;
{ NewGroupBox3 }
NewGroupBox3 := TNewGroupBox.Create(WizardForm);
with NewGroupBox3 do
begin
Parent := WizardForm.SelectTasksPage;
Left := ScaleX(152);
Top := ScaleY(96);
Width := ScaleX(265);
Height := ScaleY(142);
Caption := 'NewGroupBox3';
end;
{ NewCheckBox6 }
NewCheckBox6 := TNewCheckBox.Create(WizardForm);
with NewCheckBox6 do
begin
Parent := NewGroupBox3;
Left := ScaleX(16);
Top := ScaleY(24);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox6';
end;
{ NewCheckBox7 }
NewCheckBox7 := TNewCheckBox.Create(WizardForm);
with NewCheckBox7 do
begin
Parent := NewGroupBox3;
Left := ScaleX(16);
Top := ScaleY(48);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox7';
end;
{ NewCheckBox8 }
NewCheckBox8 := TNewCheckBox.Create(WizardForm);
with NewCheckBox8 do
begin
Parent := NewGroupBox3;
Left := ScaleX(16);
Top := ScaleY(72);
Width := ScaleX(97);
Height := ScaleY(17);
Caption := 'NewCheckBox8';
end;
NewCheckBox6.TabOrder := 0;
NewCheckBox7.TabOrder := 1;
NewCheckBox8.TabOrder := 2;
NewGroupBox1.TabOrder := 2;
NewGroupBox2.TabOrder := 3;
NewGroupBox3.TabOrder := 4;
{ ReservationBegin }
// This part is for you. Add your specialized code here.
{ ReservationEnd }
end;
// Don't modify this section. It is generated automatically.
{ RedesignWizardFormEnd } // Don't remove this line!
procedure InitializeWizard();
begin
RedesignWizardForm;
end;
You cannot "make them work with Tasks". That does not make sense. The only purpose of Tasks is to automatically create the checkboxes on the "Select Additional Tasks" page. As you create the checkboxes programmatically, there's nothing that Tasks will give you on top of that.
If you want to use your custom checkboxes as Tasks, use Check parameter, instead of Tasks.
[Files]
Source: "MyProg.exe"; DestDir: "{app}"; Check: IsCustomTask1Selected
[Code]
var
NewCheckBox1: TNewCheckBox;
function IsCustomTask1Selected: Boolean;
begin
Result := NewCheckBox1.Checked;
end;
For a complete solution, see How to split tasklist at tasks page of Inno Setup into multiple columns?
It works with the latest version of proper Inno Setup, with no need for an obsolete custom build of Inno Setup of doubtful origin.
Side notes:
I'd recommend you to use TNewCheckListBox, instead of TNewGroupBox with individual checkboxes.
5.5.1 is very old version that suffers many security issues.
Add a method for OnClickCheck event,
procedure InitializeWizard;
begin
WizardForm.TasksList.OnClickCheck := #TasksListClickCheck
end;
Then implement TasksListClickCheck method,
procedure TasksListClickCheck(Sender: TObject);
begin
/** Do whatever you want here **/
end;
I am creating a set up which involves in conditionally skipping pages based on a value I get in the 3rd page. I create all the possible pages in the InitializeWizard() and while debugging I can see all the pages created. When I try to skip pages in the ShouldSkipPage, I am unable to skip as I expected.
At which scenario a page becomes invalid or is there any way to check through log or something about the status of the page.
P.S - The page is very much valid and available and I am only not able to skip it.
The code snippet is given below...
[Code]
var
PageSQL2008SetupFile2: Integer;
PageSQL2008R2SetupFile2: Integer;
PageSQL2012SetupFile2: Integer;
PageSQL2014SetupFile2: Integer;
procedure InitializeWizard();
begin
MyModeTypical := false;
PageProductName := CreateInputQueryPage(wpSelectComponents,
'Settings',
'Product Name',
'Please specify the product name, then click Next.');
PageProductName.Add('Product Name:', False);
PageProductName.Values[0] := ProductName;
//SQL Server selection page
PageSQLServerSelection := CreateInputOptionPage(PageProductName.ID,
'SQL Server Selection', 'Please select the version of SQL Server you want to install.',
'',
True, False);
PageSQLServerSelection.Add('SQL 2008');
PageSQLServerSelection.Add('SQL 2008R2');
PageSQLServerSelection.Add('SQL 2012');
PageSQLServerSelection.Add('SQL 2014');
PageSQLServerSelection.Values[0] := False;
PageSQLServerSelection.Values[1] := False;
PageSQLServerSelection.Values[2] := False;
PageSQLServerSelection.Values[3] := False;
// Creating Setup pages for the 4 servers
PageSQL2008SetupFile2 := MSSQL2008SETUPDIR_CreatePage(PageSQLServerSelection.ID);
PageSQL2008R2SetupFile2 := MSSQL2008R2SETUPDIR_CreatePage(PageSQL2008SetupFile2);
PageSQL2012SetupFile2 := MSSQL2012SETUPDIR_CreatePage(PageSQL2008R2SetupFile2);
PageSQL2014SetupFile2 := MSSQL2014SETUPDIR_CreatePage(PageSQL2012SetupFile2);
// some more logic...
end;
// Function for creating the Setup pages for 4 SQL Servers (Same logic for all 4 servers)
function MSSQL2008SETUPDIR_CreatePage(PreviousPageId: Integer): Integer;
var
Page: TWizardPage;
BMPFile: String;
begin
SelectedSQLServerVersion := GetSQLServerVersion('');
Page := CreateCustomPage(
PreviousPageId,
ExpandConstant('Database Settings'),
ExpandConstant('Special note for the Microsoft SQL Server 2008 Setup')
);
BMPFile:= ExpandConstant('{tmp}\caution.bmp');
if not FileExists(BMPFile) then ExtractTemporaryFile(ExtractFileName(BMPFile));
{ BitmapImage1 }
BitmapImage1 := TBitmapImage.Create(Page);
with BitmapImage1 do
begin
Bitmap.LoadFromFile(BMPFile);
Parent := Page.Surface;
Left := ScaleX(8);
Top := ScaleY(8);
Width := ScaleX(97);
Height := ScaleY(209);
end;
{ NewStaticText1 }
NewStaticText1 := TNewStaticText.Create(Page);
with NewStaticText1 do
begin
Parent := Page.Surface;
Caption := 'To install Microsoft SQL Server 2008 you have to insert the Microsoft SQL Server 2008 Setup CD, when XXX setup requests it. The installation path of your Microsoft SQL Server 2008 setup and the additional Service Packs can be defined on the next pages.';
Left := ScaleX(112);
Top := ScaleY(8);
Width := ScaleX(292);
Height := ScaleY(77);
AutoSize := False;
TabOrder := 0;
WordWrap := True;
end;
{ NewStaticText2 }
NewStaticText2 := TNewStaticText.Create(Page);
with NewStaticText2 do
begin
Parent := Page.Surface;
Caption :=
'CAUTION: When autorun is activated, dont click in the autorun menu of Microsoft SQL Server 2008.' + #13 +
'Otherwise you must reboot your machine and restart the setup !';
Left := ScaleX(112);
Top := ScaleY(88);
Width := ScaleX(293);
Height := ScaleY(62);
AutoSize := False;
Font.Color := -16777208;
Font.Height := ScaleY(-11);
Font.Name := 'Tahoma';
Font.Style := [fsBold];
ParentFont := False;
TabOrder := 1;
WordWrap := True;
end;
with Page do
begin
//OnActivate := #MSSQLSETUPDIR_Activate;
//OnShouldSkipPage := #MSSQLSETUPDIR_ShouldSkipPage;
//OnBackButtonClick := #MSSQLSETUPDIR_BackButtonClick;
//OnNextButtonClick := #MSSQLSETUPDIR_NextButtonClick;
//OnCancelButtonClick := #MSSQLSETUPDIR_CancelButtonClick;
end;
Result := Page.ID;
end;
function ShouldSkipPage(PageID: Integer): Boolean;
var
begin
if PageID = wpSelectComponents then begin
Result := MyModeTypical;
end else if PageID = PageProductName.ID then begin
Result := MyModeTypical;
end;
Log('Server is...' + SelectedSQLServerVersion);
if SelectedSQLServerVersion <> '' then begin
// Database Settings Warning
if (SQLServer2008Flag = True) and (IsComponentSelected('DBS\SERVER')) then begin
if PageID = PageSQL2008SetupFile2 then begin
Result := false;
end else if PageID = PageSQL2008R2SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2012SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2014SetupFile2 then begin
Result := true;
end;
end else if (SQLServer2008R2Flag = True) and (IsComponentSelected('DBS\SERVER')) then begin
if PageID = PageSQL2008R2SetupFile2 then begin
Result := false;
end else if PageID = PageSQL2012SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2014SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2008SetupFile2 then begin
Result := true;
end;
end else if (SQLServer2012Flag = True) and (IsComponentSelected('DBS\SERVER')) then begin
if PageID = PageSQL2012SetupFile2 then begin
Result := false;
// This PageSQL2014SetupFile2 is not skipped.....
end else if PageID = PageSQL2014SetupFile2 then begin
Result := true;
// This PageSQL2008SetupFile2 and PageSQL2008R2SetupFile2 are skipped properly.....
end else if PageID = PageSQL2008SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2008R2SetupFile2 then begin
Result := true;
end;
end else if (SQLServer2014Flag = True) and (IsComponentSelected('DBS\SERVER')) then begin
if PageID = PageSQL2014SetupFile2 then begin
Result := false;
end else if PageID = PageSQL2008SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2008R2SetupFile2 then begin
Result := true;
end else if PageID = PageSQL2012SetupFile2 then begin
Result := true;
end;
end;
// some more logic
end;
DeeJay
We are switching our application to .Net4, but we still have customers on Windows XP SP2. So I need to make additionnal checks in the setup.
Making a popup message at the start of the setup to throw away XP SP2 users is pretty easy :
function InitializeSetup(): Boolean;
var
Version: TWindowsVersion;
begin
if IsModuleLoaded('monalbumphoto.exe') then begin
MsgBox(ExpandConstant('{cm:PleaseClose}'), mbError, MB_OK);
Result := false;
Abort;
end else begin
// check Windows version (to display a better error message for XP SP2 users)
GetWindowsVersionEx(Version);
if (Version.Major = 5) and (Version.Minor = 1) and (Version.ServicePackMajor < 3) then begin
MsgBox(ExpandConstant('{cm:WrongVersion}'), mbError, MB_OK);
Result := false;
Abort;
end else begin
Result := true;
end;
end;
end;
But now, the requirements have changed. I need to display a (kind of long) message, explaining that the user either have to upgrade to SP3, or download a legacy version of our app, with a link to it.
The easy way is to change the messagebox to use "YESNO" buttons (like in this question How to show a hyperlink in Inno Setup?) to automatically download the setup. But I want to go further.
I would like to display a custom wizard page with the explanation, and an embedded link. Another question (Inno Setup custom page) shows how to do it, but it looks like I can only create a page AFTER a specific page, and not BEFORE anything.
So, is it possible to display a custom wizard page BEFORE any other page, that cancels the whole installation ?
Thank you !
You can create the page to appear after wpWelcome and return true from the ShouldSkipPage(wpWelcome) event function.
Alternatively, you can skip all pages and jump straight to the "Prepare to install" page and retunr text giving instructions.
Thanks to #TLama, I now have this, which seems to be working great :
// http://stackoverflow.com/questions/5461674/
function GetSystemMetrics (nIndex: Integer): Integer;
external 'GetSystemMetrics#User32.dll stdcall setuponly';
Const
SM_CXSCREEN = 0; // The enum-value for getting the width of the cient area for a full-screen window on the primary display monitor, in pixels.
SM_CYSCREEN = 1; // The enum-value for getting the height of the client area for a full-screen window on the primary display monitor, in pixels.
// Download the legacy version of the software
procedure DownloadLegacyVersion(Sender : TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://download.monalbumphoto.fr/monAlbumPhoto_XPSP2.exe', '', '', SW_SHOW, ewNoWait, ErrorCode);
end;
// Download the legacy version of the software
procedure OpenWindowsUpdate(Sender : TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://update.microsoft.com/', '', '', SW_SHOW, ewNoWait, ErrorCode);
end;
// creates a form specifying that the user must upgrade to SP3 or download a legacy version
procedure WindowsUpgradeNeeded();
var
Form: TSetupForm;
StaticText: TNewStaticText;
LinkButton, UpdateButton, OKButton: TNewButton;
begin
Form := CreateCustomForm();
try
Form.ClientWidth := ScaleX(500);
Form.ClientHeight := ScaleY(200);
Form.Caption := ExpandConstant('{cm:WrongVersionTitle}');
Form.BorderStyle := bsDialog;
Form.Center();
StaticText := TNewStaticText.Create(Form);
StaticText.Top := ScaleY(10);
StaticText.Left := ScaleX(10);
StaticText.Caption := ExpandConstant('{cm:WrongVersion}');
StaticText.AutoSize := True;
StaticText.Parent := Form;
LinkButton := TNewButton.Create(Form);
LinkButton.Parent := Form;
LinkButton.Width := ScaleX(200);
LinkButton.Height := ScaleY(30);
LinkButton.Left := Round(Form.ClientWidth / 2) - Round(LinkButton.Width / 2);
LinkButton.Top := ScaleY(StaticText.Top + StaticText.Height + 10);
LinkButton.Caption := ExpandConstant('{cm:WrongVersionDL}');
LinkButton.OnClick := #DownloadLegacyVersion;
LinkButton.Default := True;
UpdateButton := TNewButton.Create(Form);
UpdateButton.Parent := Form;
UpdateButton.Width := ScaleX(200);
UpdateButton.Height := ScaleY(30);
UpdateButton.Left := Round(Form.ClientWidth / 2) - Round(LinkButton.Width / 2);
UpdateButton.Top := ScaleY(StaticText.Top + StaticText.Height + 10 + LinkButton.Height + 10);
UpdateButton.Caption := ExpandConstant('{cm:WrongVersionWU}');
UpdateButton.OnClick := #OpenWindowsUpdate;
UpdateButton.Default := True;
OKButton := TNewButton.Create(Form);
OKButton.Parent := Form;
OKButton.Width := ScaleX(75);
OKButton.Height := ScaleY(23);
OKButton.Left := Round(Form.ClientWidth / 2) - Round(OKButton.Width / 2);
OKButton.Top := Form.ClientHeight - ScaleY(23 + 10);
OKButton.Caption := 'OK';
OKButton.ModalResult := mrOk;
OKButton.Default := False;
Form.ActiveControl := LinkButton;
if Form.ShowModal() = mrOk then
MsgBox('You clicked OK.', mbInformation, MB_OK);
finally
Form.Free();
end;
end;
// checks if map already running, and the minimum Windows version
function InitializeSetup(): Boolean;
var
Version: TWindowsVersion;
begin
// check Windows version (to display a better error message for XP SP2 users)
GetWindowsVersionEx(Version);
if (Version.Major = 5) and (Version.Minor = 1) and (Version.ServicePackMajor < 3) then begin
WindowsUpgradeNeeded();
Result := false;
end else begin
Result := true;
end;
end;
How to fix it? FormStyle:fsStayOnTop. I call Input Query in a thread, but it appears behind a main form or is not visible!
I dynamically create ZipForge in a thread.
procedure StartUpdating.DoPassword;
var
S: String;
begin
if PassSkip then
FSkipFile := True
else if InputQuery('Pas', FFileName, S) then
FPassword := AnsiString(S)
else
begin
PassSkip := True;
FSkipFile := True;
Terminate;
end;
end;
procedure StartUpdating.ZipForgePassword(Sender: TObject; FileName: String;
var NewPassword: AnsiString; var SkipFile: Boolean);
begin
FFileName := FileName;
FPassword := NewPassword;
FSkipFile := SkipFile;
Synchronize(DoPassword);
FileName := FFileName;
NewPassword := FPassword;
SkipFile := FSkipFile;
end;
Even if I call this from a thread it does not help me:
Function TForm1.InQuery(cap1: string; cap2: string):bool;
var s:string;
begin
if InputQuery(cap1,cap2,s) then
begin
ThreadUpdating.MainPas:=s;
result:=true;
end else result:=false;
end;
Edit (2)
The form shown by InputQuery() is a modal form (shown using .ShowModal, and Delphi's VCL is smart enough to make sure no modal form is shown behind a top-most window. Essentially calls are made to DisableTaskWindows and NormalizeAllTopMosts, the interesting one being NormalizeAllTopMosts: this makes sure there are no top-most windows while the modal form is shown. Those calls aren't directly made, the VCL uses a number of tricks to make it happen. The details can be found by reading the code for TCustomForm.ShowModal, Forms.DisableTaskWindows, TApplication.WndProc - specifically the handling of the WM_ENABLE message.
What needs to be known is that there appears to a bug allowing a modal form to be shown behind the Main form of the application, if the main form is top-most. This is happening on both Delphi 2010 and Delphi XE, didn't test with older versions. The test is very simple: Create a new Delphi VCL application, on Form1 set FormStyle=fsStayOnTop, drop a button and in the button's OnClick do this:
procedure TForm2.Button1Click(Sender: TObject);
var s:string;
begin
s := '';
InputQuery('a', 'b', s);
end;
The fix
This should be considered a temporary fix, because clearly the design calls for top-most windows to be "degraded" before showing modal forms. If you know your main form is top-most, you should do something like this before calling ShowModal for anything:
MainForm.FormStyle := fsNormal;
try
YourDialog.ShowModal;
finally MainForm.FormStyle := fsStayOnTop;
end;
In the particular case of InputQuery one can use a function similar to the following one. Please note I included the ability to turn the text editor into a password-editor, based on what the OP requested in an other question:
function CustomInputQuery(const Caption, Prompt: string; const Password:Boolean; var Value:string): Boolean;
var F: TForm;
Ed: TEdit;
Lb: TLabel;
Bt: TButton;
WasStayOnTop:Boolean;
begin
F := TForm.Create(nil);
try
F.Caption := Caption;
Lb := TLabel.Create(F);
Lb.Parent := F;
Lb.Caption := Prompt;
Lb.Left := 8;
Lb.Top := 8;
Ed := TEdit.Create(F);
Ed.Parent := F;
Ed.Left := Lb.Left + Lb.Width + 8;
Ed.Top := 8;
Ed.Width := 150;
Ed.Text := Value;
if Password then
Ed.PasswordChar := '*';
Bt := TButton.Create(F);
Bt.Caption := 'Ok';
Bt.Default := True;
Bt.ModalResult := mrOk;
Bt.Left := 8;
Bt.Top := Ed.Top + Ed.Height + 8;
Bt.Parent := F;
Bt := TButton.Create(F);
Bt.Caption := 'Cancel';
Bt.Cancel := True;
Bt.ModalResult := mrCancel;
Bt.Left := 8 + Bt.Width + 8;
Bt.Top := Ed.Top + Ed.Height + 8;
Bt.Parent := F;
F.Width := F.Width - F.ClientWidth + Ed.Left + Ed.Width + 8;
F.Height := F.Height - F.ClientHeight + Bt.Top + Bt.Height + 8;
F.Position := poDesktopCenter;
WasStayOnTop := Assigned(Application.MainForm) and (Application.MainForm.FormStyle = fsStayOnTop);
if WasStayOnTop then Application.MainForm.FormStyle := fsNormal;
try
if F.ShowModal = mrOk then
begin
Value := Ed.Text;
Result := True;
end
else
Result := False;
finally if WasStayOnTop then Application.MainForm.FormStyle := fsStayOnTop;
end;
finally F.Free;
end;
end;