Form appears after 'Application.CreateForm' step - delphi

I am working on a project in delphi 2007 (CodeGear RAD Studio).
There are couple of forms in the application. Thouse forms are created as follows:
program MyProgram;
uses
Forms,
uMain in 'Source\uMain.pas' {MainForm},
uSettings in 'Source\uSettings.pas' {fSettings};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TSettings, Settings);
Application.Run;
end.
the problem is, that on line Application.CreateForm(TSettings, Settings); Settings form appears (not modal). And the question is why it is happening?.
I know that it is probably not enough information, but I am ready to provide some, if it is needed.
P.S. I am currently re-wrighting programm logic so settings form will be created only before it is about to appear, and after that delete it. Still, I would like to know the answer to this question.

Your settings form's Visible property is set to true at design time, and thus it appears as soon as it's created.

Related

Why is this resource directive showing in the list of available forms?

I just stumbled on something very peculiar. Refer to this screenshot:
Why is it showing $R *.res in the list of available forms? This project only has two forms and one additional unit, and here's the project's main file source:
program MyProgram;
uses
Forms,
uMain in 'uMain.pas' {fMain},
uEmail in 'uEmail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Unit in 'Other.Unit.pas';
{$R *.res}
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
PS - This is slightly modified code, the only thing that changed was the program name, program title, and the name of one of the units (Other.Unit.pas) which I know is a bad example since Unit is a reserved word. But the original unit name has a namespace prefix such as this one.
UPDATE
I followed the recommendation to move this RES reference to before the uses clause. After dong this (and cleaning all temp files, restarting IDE, etc.), it still shows in the list. But to my surprise, the IDE has actually added this RES reference back!
So now the IDE its self has turned it into:
UpdateUnit in 'UpdateUnit.pas' {$R *.res};
(UpdateUnit is a new name I gave it so I'm not giving internal information away)
So, I opened the DPROJ file and did a search for *.res and sure enough found this:
<ItemGroup>
....
<DCCReference Include="UpdateUnit.pas">
<Form>$R *.res</Form>
</DCCReference>
As written, I could not reproduce this... however if I removed the trailing semicolon (";") after the "Other.Unit in 'Other.unit.pas'" line, the "$R *.res" shows up in the project options.
This isn't a bug, as far as I can see. Since your comments indicate that the presented code isn't the same as what you're using it will be hard to diagnose. I will try and explain what is happening; If you look at the uMain and uEmail units, there is a comment next to each that is the name of the form. Since these units may not actually be open in the IDE, there is no way to know if there is a form associated with that unit. The presence of a uMain.dfm isn't a guarantee that uMain.pas actually has a form (it may be left-over cruft). The IDE places this simple comment within the uses clause for that unit in order to tell the project manager that this unit has a form.
By removing the ";", the parser sees the next comment token as {$R *.res}. It then concludes that Other.Unit.pas must contain a form named "$R *.res". It does no validation of the name nor even tries to open the unit. It merely takes the raw content of that comment and assumes it's a form name.
You can safely move the {$R *.res} before the uses clause so that the project parser doesn't confuse that directive comment as a form.
EDIT: From my comment above:
What has likely happened is this; at some point you may have edited the .dpr file in a manner that confused the parser into thinking that "$R *.res" was the form name. You then saved it while in that state, which also injected that information into the .dproj file. The IDE tries to keep those two things in sync and sometimes will take the .dproj file as being the "master" and will update the .dpr file to match. You should be able to safely remove the $R *.res from the dproj file.
This does not reproduce with Delphi XE2 Update 4 (see below).
More accurately: the code you posted does not reproduce.
But the scenario that you describe in the comments does: if the .dproj is hosed, the IDE will re-add the incorrect information to your .dpr. See below for further explanation.
At the end of this answer an edit that shows you an occurrence at a client: Delphi XE2 can get confused somehow to the internal state gets wrong, and it writes back both a wrong .dproj and .dpr file.
If the code you posted is not the same as the code that fails, please correct your question with the code that fails (and post a comment to my answer so I get a notification and update the QC entry; in the current form your QC entry will be marked as "cannot reproduce" and then closed).
I have seen the IDE being confused in various places (including the project options) after an AV, or when line-endings in the .pas or .dpr files are not CRLF, or when manually editing .DPR files.
Those issues usually disappear when you restart the IDE. Sometimes you even have to clean up some files (with extensions like .DCU, .local, etc).
Worst case is that the IDE got so confused that both the .DPR and .DPROJ contain wrong information (hence my comment), that appears to be the case in your situation (thanks to your edited question). You can manually edit the .DPROJ and .DPR files to resolve this. Make sure to have backups as it is easy to break the XML format of a .DPROJ file
I could reproduce it if I moved the RES declaration before the semicolon: that's the format the IDE expects so it can parse the .DPR for Forms, DataModules and Frames (and potentially other design surfaces):
Unit1 in 'Unit1.pas' {DataModule1: TDataModule},
Unit2 in 'Unit2.pas' {Frame2: TFrame};
Unit3 in 'Unit3.pas' {Form3};
Basically, you should not edit the .DPR file: the IDE owns it and will rewrite it for instance when you add new units to your project, you change the program icon, change the application caption, etc.
Main program that does not reproduce:
program MyProgram;
uses
Vcl.Forms,
uMain in 'uMain.pas' {fMain},
uEMail in 'uEMail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Module in 'Other.Module.pas';
{$R *.res}
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
The options dialog:
Main program that does reproduce (note where the RES is):
program MyProgram;
uses
Vcl.Forms,
uMain in 'uMain.pas' {fMain},
uEMail in 'uEMail.pas' {frmEmail},
Vcl.Themes,
Vcl.Styles,
Other.Module in 'Other.Module.pas' {$R *.res};
begin
Application.Initialize;
TStyleManager.TrySetStyle('Iceberg Classico');
Application.Title := 'My Program Title';
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
Edit 20130616
Ran into this at a client below is the diff of the before/after in both the .dpr and the .dproj (some of the names have been anonymized).
Delphi XE2 got confused somehow: it was not an edit in the .dpr that induced this problem.
There are two things I suspect:
an access violation somewhere overwrote some internal state causing the internal project structure to be damaged (the project depends on a lot of 3rd party packages to be installed, all of which are in the same BDS process)
there is lots of code in the .dpr that might have confused the internal project structure
I've refactored all of the .dpr code into a separate module. Hopefully that was the cause and this won't happen again.
Old .dpr fragment:
program Server;
uses
ShareMem,
SysUtils,
Forms,
SvcMgr,
WebReq,
uMain in 'uMain.pas' {fMain},
//...
uDBOrm in 'uDBOrm.pas',
uWinProxySettings in '..\..\..\Server\trunk\Server\uWinProxySettings.pas',
GpStuff in 'GpStuff.pas',
DSiWin32 in 'DSiWin32.pas';
{$R *.res}
function IsServiceApp: Boolean;
begin
//...
end;
begin
if IsServiceApp = True then
begin
//...
end else
begin // GUI Interface
if Assigned(Application) then
FreeAndNil(Application);
Forms.Application.Initialize;
Forms.Application.MainFormOnTaskbar := True;
ReportMemoryLeaksOnShutdown := True;
Forms.Application.CreateForm(TfMain, fMain);
Forms.Application.Run;
end;
end.
New .dpr fragment:
program Server;
uses
ShareMem,
SysUtils,
Forms,
SvcMgr,
WebReq,
uMain in 'uMain.pas' {fMain},
//...
uDBOrm in 'uDBOrm.pas' {$R *.res},
uWinProxySettings in '..\..\..\Server\trunk\Server\uWinProxySettings.pas',
GpStuff in 'GpStuff.pas',
DSiWin32 in 'DSiWin32.pas';
{$R *.res}
function IsServiceApp: Boolean;
begin
//...
end;
begin
if IsServiceApp = True then
begin
//...
end else
begin // GUI Interface
if Assigned(Application) then
FreeAndNil(Application);
Forms.Application.Initialize;
Forms.Application.MainFormOnTaskbar := True;
ReportMemoryLeaksOnShutdown := True;
Forms.Application.CreateForm(TfMain, fMain);
Forms.Application.Run;
end;
end.
Old .dproj fragment:
<DCCReference Include="uDBOrm.pas"/>
<DCCReference Include="..\..\..\Server\trunk\Server\uWinProxySettings.pas"/>
New .dproj fragment:
<DCCReference Include="uDBOrm.pas">
<Form>$R *.res</Form>
</DCCReference>
<DCCReference Include="..\..\..\Server\trunk\Server\uWinProxySettings.pas"/>

Why main form can't access to DataModule's images and actions when project is open in Delphi XE?

My Delphi XE application was fine till a couple of days and I can't figure out what is wrong. My project layout:
Visual controls are on the main form
Actions and image lists for those controls are on a data module
When I open my project, the main form doesn't have any image or actions associated to any of the controls, even though they should be. When I compile I get the error message: "Module 'winMain' links to module 'modGeneral' which cannot be found in the current project. Do you wish to remove/redirect the links to another module?".
The work around: close the main form after I've opened the project, then open the module in the IDE by double-clicking it in the project manager (yes, it is present in the current project), then re-open the main form: all my actions and images are now correctly displayed.
What do you think, is that a known Delphi bug ? A problem with my project ?
Check your .dpr file. One way to reproduce your problem is to change the uses clause in it.
Consider this example which works fine:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {DataModule2: TDataModule};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TDataModule2, DataModule2);
Application.Run;
end.
The icon in the Project Manager looks as usual for a module with a dfm:
If you remove the comment, or comment it out:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas'; // {DataModule2: TDataModule};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TDataModule2, DataModule2);
Application.Run;
end.
Here, the icon has changed:
...and you get the errors you describe.
You need to close and reopen the project for your changes to take effect.
TOndrej's answer is complete and correct. I have just a small addition which I maybe should post as comment but I'm afraid it won't be noticeable.
I faced with the described error after unit renaming and project file refactoring (actually I removed all the in and comments from uses section). I returned the required pattern in the uses section but I still got the error. My mistake was an alignment that I added to comments in uses section:
DMMain in 'DMMain.pas' {fdmMain : TDataModule},
DMIndex in 'DMIndex.pas' {fdmIndex : TDataModule},
Surprisingly it really matters. Removing the alignment
DMMain in 'DMMain.pas' {fdmMain: TDataModule},
DMIndex in 'DMIndex.pas' {fdmIndex: TDataModule},
fixed the error and I got things working.

Closing a secondary delphi form causes the main form to lose focus

When showing a secondary form from the main form and from the second form showing a third form and then closing both forms will cause the main form to lose focus.
Using Delphi 2009 with XP SP3
Here are my steps for reproducing the problem:
Create a new VCL forms applications
Drag a button onto the created form
In the click handler create a new TForm1 and show it
Run the program. Click the button to show a second form. Click the button on the second form to create a third form. When closing both new forms the main form will lose its focus.
This is my code in the button click event handler:
// Using Self does not change the results
with TForm1.Create(nil) do
show;
Is there any way to stop my main form from losing focus?
After upgrading my Delphi installation from version 12.0.3170.16989 (no updates) to version 12.0.3420.21218 (update 3 & 4) I could not reproduce the problem anymore.
Seems like it was a bug that was fixed in the update.
I don't see how what you describe creates a "child" Form.
But anyway, I just tried with exactly what you described in your steps and could not reproduce it in D2009 (updates 3 & 4), whether I create the 2nd "child" from the main Form or from the 1st "child", and whatever the order in which I close them.
So, there must be something else you did not tell...
Try the following (and avoid the with):
with TForm1.Create(nil) do begin
show;
activate;
bringtofront;
end;
From a pure Win32 perspective Applications tend to loose focus when popup windows are closed because the underlying framework has an order of operations issue. Windows will not activate a disabled window, so, when destroying a modal popup window it is very important that the parent window is (reenabled) BEFORE DestroyWindow is called on the popup.
I have no idea how this might apply to development in delphi or vcl. The code sample does not imply you have a lot - or any - control over how modal popup windows are destroyed.
Like François I cannot reproduce this behaviour with Delphi 2009 on Windows XP SP3. The form that was opened first gets the focus back as soon as the other forms are closed.
To be sure, is your project code:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
And your Unit code:
unit Unit1;
interface
uses
Forms, Classes, Controls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
with TForm1.Create(nil) do
Show;
end;
end.
Corrected the name of François, sorry

How do you deal with IFDEFs in .dpr uses section

Whenever you add a new unit to the project Delphi rebuilds the .dpr file and all the IFDEFs in the uses section are gone.
To work around this I typically use NotePad to create new .pas files, and add it to the .dpr manually. If I need a form I use File->New->Form and then revert the .dpr file to the previous version. Not very RAD if you ask me ;-)
How do you deal with that? Is there a way to add a unit in the IDE while keeping the IFDEFs?
Sometimes I create a unit specifically as a place for all the IFDEFs and other stuff the IDE would mess up if it were in the dpr. This unit typically goes to the top of the dpr's uses clause. This trick doesn't cater for all scenarios but it sometimes saves a lot of tedious work.
I don't put any ifdefs into a dpr file. If I want to use different units/forms in a project, depending on some condition, I split the project in two.
I spent quite a while trying to work that one out,
I ended up have a project file (.dpr) for each build type,
with the Conditions in Project|Project Options|Directories/Conditionals
and only the units i wanted added in to the project
this dose have the down side that if you have custom code in the .dpr, it will have to be manually copied to the other project files when it changes.
as noted by Rob Kennedy, this can handled by putting the custom code into its own unit, which is called by a single procedure. thus minimizing the .dpr code size/changes to be made
Also, another bonus you get is that if you add all your .dpr files to a project group, you can build all your different versions with one click / cmd line
You can add it manually from within the IDE. (Use the "view source" option on the project).
Normally the dpr is "hidden". You are not expected to change anything in there.
And if you do, you better make sure all your changes are manual else you are losing some information.
For forms, datamodules, and other units which contain a single class by which functionaity will be replaced, the solution is rather simple. Just DON'T add the custom units directly to the product, but do save them some place in the search path (or modify the project search path to include thier location).
1) Create a NEW unit, which contains either the parent for all of the other classes, or the interfaces that they all will implement (I generally prefer the later as it allows easier customization) [for example purposes this is called uSpecialParent.pas]
2) Add a class variable which will referenced when you need to create the new functionality. for instance if you just were going to show modal a bunch of forms, so didn't care about any other methods then you could have a variable that looked like the following:
TYPE
TMySpecialFormClass : class of TForm;
VAR
TMySpecialForm : TMySpecialFormClass;
3) Create another unit which will contain all of the IFDEFS. It could look something like the following:
Unit uRegisterSpecialForms;
interface
uses
{$IFDF SPECIAL1}
uSpecial1,
{$ENDIF}
{$IFDEF SPECIAL2}
uSpecial2,
{$ENDIF}
uSpecialParent;
implementation
// no code needed.
initialization
{$IFDEF SPECIAL1}
TMySpecialForm := uSpecial1.TSpecialForm1;
{$ENDIF}
{$IFDEF SPECIAL2}
TMySpecialForm := uSpecial2.TSPecialForm2;
{$ENDIF}
end.
4) To reference this in your code you only need the uSpecialParent added to the unit which will be requesting a special form and then create it dynamically for example to show this modal you could invoke the following:
var
frm : TForm;
begin
frm := TMySpecialForm.Create(nil);
try
frm.showmodal;
finally
frm.free;
end;
end;
And here's the lo-tech approach for completeness' sake:
After the IDE has messed up your uses clause again:
close the project
go to your version control tool of choice and diff the DPR against the latest checked-in
version using a merge-enabled diff tool like WinMerge
revert the IDE changes
save the DPR
get on with it
(Delphi 7)
I've just tried the same.
Take a look at the first code version and at my comments below:
program Project1;
{$IFDEF TESTIFDEF}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$ELSE}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$ENDIF TESTIFDEF}
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.
At that point, I've just inserted the 2nd Form and noticed that the corresponding unit (Unit2.pas) was inserted inside the first part of the IFDEF i.e. inside the "TESTIFDEF" labeled part - hence not overriding the second block (after the {$ELSE}).
Thus your solution should be:
define a IFDEF statement like "{$IFDEF DELPHIBASISCONFIGURATION}" in place of my "{$IFDEF TESTIFDEF}" where all the forms will be added.
define as many alternative LABELS for the different configurations you want to work with.
each time you've added a form to the project, copy the inserted line of the first block into the corresponding blocks below - depending on your needs...
activate the required configuration using the define statement or the option dialog
NEVER DEFINE "DELPHIBASISCONFIGURATION" ;)
Hence, it should look like this:
program Project1;
{$DEFINE MYCONFIG1} // THIS ONE IS NOW ACTIVE
{$IFDEF DELPHIBASISCONFIGURATION}
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3};
{$ELSE}
// THIS IS A "COMMON TO ALL CONFIG" PART
uses
Forms,
// FIRST CONFIGURATION
{$IFDEF MYCONFIG1}
Unit1 in 'Unit1.pas' {Form1},
Unit3 in 'Unit3.pas' {Form3}
{$ENDIF MYCONFIG1}
// SECOND CONFIGURATION
{$IFDEF MYCONFIG2}
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2}
{$ENDIF MYCONFIG2}
// THIS IS THE "COMMON TO ALL CONFIG" END :)
;
{$ENDIF TESTIFDEF}
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
//Application.CreateForm(TForm3, Form3);
//Application.CreateForm(TForm2, Form2);
Application.Run;
end.
As you can see, I've discarded the calls to Application.CreateForm(...) for Form2 and Form3.
IMHO, it's usually better to dynamically create the supplemental forms at the moment you really need them i.e. not all the forms at program start...

Show message to user while Delphi program terminating

In some cases I should terminate application with
Application.Terminate;
In that case I want to show some message to user inside destructor of some TFrame.
I have tryed to use MessageBox, MessageBoxIndirect, ShowMessage functions with no success. Message box isn't appears on screen and application closes.
Is there any way to show some message to user while Application terminating?
Btw, Delphi XE used.
Like comments indicate for showing messages with e.g. MessageBox, MessageBoxIndirect or ShowMessage, your process needs to still run.
Delphi for .NET would have a suiting OnShutdown event, but when not compiling with the conditional CLR it is absent.
One can however use an exit procedure, like TApplication does itself with DoneApplication. This procedure is called at a point where the process still lives, before System.Halt is called. It is added by calling AddExitProc(Proc: TProcedure) in System.SysUtils. In code commentary for this is following:
{ AddExitProc adds the given procedure to the run-time library's exit
procedure list. When an application terminates, its exit procedures
are executed in reverse order of definition, i.e. the last procedure
passed to AddExitProc is the first one to get executed upon
termination. }
I would personally decide to use this, despite the warning from the documentation, as TApplication itself is still using it in Tokyo to have DoneApplication called. Excerpt from documentation:
[...]AddExitProc is not compatible with ULX package support and is
provided for backward compatibility only. Do not use AddExitProc in
new applications.[...]
The small code example of a VCL project will show a message on application termination:
program Project1;
uses
Vcl.Forms,
Vcl.Dialogs,
System.SysUtils,
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
procedure AppTerminated;
begin
MessageDlg('Message', mtInformation, [mbOk], 0);
end;
begin
AddExitProc(AppTerminated);
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm2, Form2);
Application.Run;
end.
Once you have called Application.Terminate any attempt to show a dialog fails. You can't have your cake and eat it. You can't terminate your process, and keep it alive to display a dialog.
So, the obvious solutions to that conundrum are:
Show your dialog before you terminate the application, or
Create a separate process to show the dialog, and then terminate the application.

Resources