Accessing TWinControl.Handle on TForm.Create - delphi

I have this code:
procedure TForm1.FormCreate(Sender: TObject);
begin
DoSomethingWithCombobox(ComboBox1.Handle);
end;
Q: Is it guaranteed that the ComboBox1.Handle is always created on TForm.FormCreate (Form1 is the parent of ComboBox1)? Maybe on OnFormShow?
from my tests, it seems that the Handle is always available at that point.
I know that ComboBox1.Handle will call HandleNeeded at this point. but can I assume that Handle will always be available at this point?
I also know that the TWincontrol can safely access it's own handle on CreateWnd. My question is specific to a scenario where I cannot control CreateWnd of the child control and only have access to the parent events/messages.
Hope my question is clear.

If your tests show that it's OK to access the control's handle there, then it should be OK. You're the application developer, so if you later change anything to break that assumption, you'll also have the power to fix it.
Accessing a control's Handle property will either yield a valid window handle or throw an exception. You won't get a null handle. The exception would typically come when the control's parent window is unable to exist.
The handle you get at that point isn't guaranteed to be the last handle the control will ever have, because controls' underlying windows may be recreated, but since you're the application developer (as opposed to a component-library developer), you have reasonable control over how often windows will be recreated after the form has finished being created. This is because you're handling the OnCreate event. Had you been overriding the Loaded method, for example, there's be less confidence that all window-creation activity had finished.

Related

What is the correct way to dynamically create/release runtime forms?

I always try to create my Applications with memory usage in mind, if you dont need it then don't create it is the way I look at it.
Anyway, take the following as an example:
Form2:= TForm2.Create(nil);
try
Form2.ShowModal;
finally
Form2.FreeOnRelease;
end;
I actually think Form2.Destroy is probably the better option, which brings me to my question..
What is the difference between calling:
Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;
They all do the same or similar job, unless I am missing something.
And also when should any of the above be used? Obviously when freeing an Object I understand that, but in some situations is Destroy better suited than Free for example?
Form2:= TForm2.Create(nil);
This is a code-smell, because Form2 is probably the global, IDE-generated variable that would normally hold an IDE-created TForm2. You most likely want to use a local variable, and one with a better name. This is not necessary an error, just a code-smell.
Form2.Destroy vs Form2.Free
Use Form2.Free, because it calls Destroy anyway. You can CTRL+Click on the name (Free) to see it's implementation. Essentially Free calls Destroy if Self is not nil.
Form2.FreeOnRelease
As the documentation says, "It should not be necessary to call FreeOnRelease directly."
I've never actually heard of FreeOnRelease before. A quick Google search turned up the reason why. From the official documentation:
FreeOnRelease is called when an
interface implemented by the component
is released. FreeOnRelease is used
internally and calls the corresponding
interface method. It should not be
necessary to call FreeOnRelease
directly.
As for Free vs. Destroy, Free is a safety feature. It's basically implemented as if self <> nil then self.Destroy;, and it was created to make constructors and destructors safe to use. Here's the basic idea:
If you're constructing an object and an unhandled exception is raised, the destructor gets called. If your object contains other objects, they may or may not have been created yet by the time the error occurred, so you can't just try to call Destroy on all of them. But you need a way to make sure that the ones that have been created do get destroyed.
Since Delphi zeros out the address space of an object before calling the constructor, anything that hasn't been created yet is guaranteed to be nil at this point. So you could say if FSubObject <> nil then FSubObject.Destroy again and again for all the sub-objects, (and if you forget that you're going to get access violations,) or you can use the Free method, which does it for you. (This is a huge improvement over C++, where the memory space is not zeroed before the constructor is called, which requires you to wrap all your sub-objects in smart pointers and use RAII to maintain exception safety!)
It's useful in other places as well, and there's really no reason not to use it. I've never noticed that Free imposes any measurable performance penalty, and it improves the safety of your code, so it's a good idea to use it in all cases.
Having said that, when dealing with forms specifically, there's an additional variable to factor into the equation: the Windows message queue. You don't know if there are still pending messages for the form you're about to free, so it's not always safe to call Free on a form. For that, there's the Release method. It posts a message to the queue that causes the form to free itself once it's got no more messages to handle, so it's generally the best way to free a form you no longer need.
The canonical form is:
Form := TMyForm.Create(nil);
try
Form.ShowModal;
finally
Form.Free;
end;
Never call Destroy, always call Free instead.
FreeOnRelease is a total red herring. Sometimes, if there are queued messages destined for your form or its children, then you might elect to call Release although often that's indicative of design problems.
The idiomatic usage is
procedure SomeProc;
var
frm: TForm2;
begin
frm := TForm2.Create(nil);
try
frm.ShowModal;
finally
frm.Free;
end;
end;
or, unless you hate the with construct,
with TForm2.Create(nil) do
try
ShowModal;
finally
Free;
end;
You should never call Destroy, according to the documentation. In fact, Free is exactly equivalent to if Self <> nil then Destroy;. That is, it is a 'safe' version of Destroy. It doesn't crash totally if the pointer happens to be nil. [To test this, add a private field FBitmap: TBitmap to your form class, and then OnCreate (for instance), try FBitmap.Free vs. FBitmap.Destroy.]
If you create the form using the approach above, Free is perfectly safe, unless you do some strange things in the form class.
However, if you use CreateForm(TForm2, Form2) to create the form and store the form object in the global instance variable Form2 and you don't free it immediately [for instance, if you want the window to stick around next to the main form in a non-modal way for a few minutes], you should probably use Release instead of Free. From the documentation,
Release does not destroy the form
until all event handlers of the form
and event handlers of components on
the form have finished executing.
Release also guarantees that all
messages in the form's event queue are
processed before the form is released.
Any event handlers for the form or its
children should use Release instead of
Free (Delphi) or delete (C++). Failing
to do so can cause a memory access
error.
FreeOnRelease has nothing in particular do to with forms. From the docs:
It should not be necessary to call
FreeOnRelease directly.
the other way is passing caFree to Action of formonclose
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end

Make sure nested child control is visible

I have a utility routine that I call when validating user input in a dialog fails. It sets focus to the offending control, beeps and displays an appropriate message to the user. This works well as long as the offending control is not hidden. Now I have to adapt this to a situation where the relevant controls are children of some kind of collapsible group boxes (possibly even nested), and I have to make sure that the "ancestor" boxes are expanded before calling SetFocus.
Now I have a few possibilities:
Build knowledge about the collapsible component into the error reporting routine. I'd like to avoid that as the routine should rather stay generic.
Pass an callback that can be called prior to (or instead of) SetFocus. This is error prone because one has to remember to pass the callback at all the relevant places.
My favourite solution would probably be an event (or overrideable method) (probably in TWinControl) that tells a container control "please make sure you and you child controls are visible" but I don't know of such a thing.
Any ideas how I can handle this situation?
Define an interface with a method called something like: EnsureVisible.
Implement it for all your components (you may need to derive your own versions of some of these components). This allows different controls to have quite different behaviour.
When a control needs to make sure it is visible it walks its parents and calls EnsureVisible if the interface is implemented.
If you don't like interfaces then do it with a custom Windows message, but you get the basic idea.
In my opinion the best solution would be a separate routine that builds knowledge about all container controls, allowing the dialog validation routine to stay generic and at the same time being focused enough to be easily tested and maintained. Something along the lines of:
procedure ForceControlVisible(C: TControl);
begin
// Recursive code
if Assigned(C.Parent) then ForceControlVisible(C.Parent);
// Code specific to each container control class
if C is TTabSheet then
begin
// Code that makes sure "C" is the active page in the PageControl
// goes here. We already know the PageControl itself is visible because
// of the recursive call.
end
else if C is TYourCollapsibleBox then
begin
// Code that handles your specific collapsible boxes goes here
end
end;
OOP-style methods that rely on virtual methods or implementing interfaces would be way more elegant, but require access to the source code of all the controls you want to use: even if you do have access to all required sources, it's preferable not to introduce any changes because it makes upgrading those controls difficult (you'd have to re-introduce your changes after getting the new files from the supplier).
Each component knows its Parent. You can walk up the list to make each parent visible.

How do I check if form is Closed?

The only way I see is to add flag for this, but is this the best way?
When the form is destroyed and I check if(Assigned(form2)) the result is true? Why?
What is the way to do this?
You can use Form1.Showing to see if a form is closed or not.
Just closing a form does not free it unless you set Action := caFree in OnClose event. Default is caHide.
Wow, a blast from the past :)
The way that Assigned() works, is that it basically does nil check on the pointer. If you destroy form2, there will still be a memory address that form2 points to.
I has been a very long time since I've done any Delphi, but from memory, you need to manually set the form2 var to nil when it is destroyed. If you have a central place (eg. a form broker?) where you create & destroy forms, this should be quite easy.
If you use Form1.Free or Form1.Destroy, Delphi will destroy the object but wont set the object reference to nil. So instead use FreeAndNil.
For more information, check Andreas Rejbrand answer in this link
Faced with the same issue when doing some routine on closing application. In this case all forms are destroyed behind the stage but pointers are not set to nil. This code helphs me:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyForm:=nil;
end;
So pointer becomes nil and I can check it with Assigned or compare to nil.
Just as a tip, the correct way to do it in some special cases is to create a timer that do the nil assign to the variable.
I will explain it (somehow it is complex), if you create your form within your own code MyForm:=TMyForm.Create and you have a MyFrom.Close it is very easy, just add a MyForm:=nil or also better MyForm.FreeAndNil... but sometimes the reference is not anyware.
Sample: You create inside a procedure, on a loop a lot of copies of the same form (or just one), let the form open and end that procedure, now the reference to the opened form is nowhere, so you can not assign nil or do a freeandnil, etc., in a normal way.
For that cases, the trick is to use a timer (of just one milisecond) that do it, that timer needs the reference, so you must store on a global like the reference to Self, all that can be done on the on close event.
The easiest way to do the free (when no reference anywhere) is to create a TObjectList on the main form, so it will hold all form references that needs to be free, and define a timer (one milisecond) that will go through that list doing the freeandnil; then on the onlcose you add Self to that list and enable that timer.
Now the other part, you have a normal form that is auto created on start, but you need to set it to nil and re-create it on your own code.
That case has a global that point to that form, so you only need to free and nil it, but NOT (i say it loud) on any part inside the own form code, you must do it OUT (i say if loud) of the form code.
Some times you will need to free the form, when user close it, and it is not shown in modal, this case is complex, but again the same trick is valid, on the onclose event you enable a timer (that is out of that form, normally on main form) adn that timer will free and nil. That timer interval can be set as just one milisecond, it will not be run until form has totally closed (please have in mind not using Application.ProcessMessages, that is normally a really bad idea).
If you set Self to nil, free or whatever inside the own form, you can corrupt your application memory (doing that is totally unsafe, not to mention it can eat ram).
The only way to free a form (and nil its reference), a form that is not shown as modal and is the user who close it, is to program a trigger that do that after the form is totally closed.
I know about setting action to do the free, but to set it to nil there is no other safe way.
Must say: If you use timers on your main form, run a Enabled:=False on all of them on the Onclose event... otherwise weird things may occur (not allways, but sometimes... race conditions about destroying application and running code on that timers), and of couse if some one was enabled act correctly to terminate it correctly or abort it, etc.
Your question is one of the complex things to do... free and nil a form that is closed not by code, but by user action.
For all the rest: Think like if the application has at the same time a lot of forms opened and all can interact with the user at the same time (anyone is modal), and you have code that references some of them from the others... you need to know f user has closed any form to avoid accesing that form from code. This is not trivial to be done unless you use timers.
If you have a 'central' form (like an MDI application) you can put that timer on the main MDI form, so any child form that is closed can be freed and nil, the trick is again a timer on that main form.
Only and only if you are sure you can free and nil all non visible forms, you can have a timer on the main form that goes through all forms and if Visible is false, then call FreeAndNil, i consider this way prone to errors, since if you add on a future a form that must not be freed but can stay hidden... this code will not be valid.
Allways remember that if is the user the onw who closes the form that must be freed and nil, there is no way on code to detect and act, no event is launched (after the form is totally closed) and before the form is totally closed you must not even try to free it or nil its reference, weird things can occur (more prone to that if motherboard has more than one socket, also more if your app uses threads, etc).
So, for threaded apps (and also not threaded) i use another method that works great and do not need timers, but need double checking prior to each ThatForm.*, the trick is to define a Form bolean public variable like as PleaseFreeAndNilMe on the public section on the form, then on the onclose (as last line) set it to True and on the OnCreate set it as False.
That way you will know if that form had been closed or only hidden (to hide a form never call close, just call hide).
So coded will look like (you can use this as a warper, instead of defining forms as TForm define them as TMyform, or also better, use a hack like type TForm=class(Forms.TForm) instead of TMyForm=class(TForm) just to have that variable added to all forms):
TMyForm=class(TForm)
...
public
PleaseFreeAndNilMe:=Boolean;
...
procedure TMyForm.FormCreate(Sender: TObject);
begin
PleaseFreeAndNilMe:=False;
...
end;
procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
...
PleaseFreeAndNilMe:=True;
end;
If you preffer hacked version:
TForm=class(Froms.TForm)
public
PleaseFreeAndNilMe:=Boolean;
end;
procedure TForm.FormCreate(Sender:TObject);
begin
inherited Create(Sender);
PleaseFreeAndNilMe:=False;
end;
procedure TForm.FormClose(Sender:TObject;var Action:TCloseAction);
begin
PleaseFreeAndNilMe:=True;
inherited FormClose(Sender,Action);
end;
But as i said, prior to access any member (or just where you do the nil compare) just call a 'global' function passign the reference (no matter if it was nil or not), coded as:
function IsNilTheForm(var TheForm: TMyForm);
begin
if nil=TheForm
then begin // The form was freed and nil
IsNilTheForm:=True; // Return value
end
else begin // The form refence is not nil, but we do not know is it has been freed or not
try
if TheForm.PleaseFreeAndNilMe
then begin // The form is not freed but wants to
try
TheForm.Free;
except
end;
try
TheForm:=Nil;
except
end;
IsNilTheForm:=True; // Return value
end
else begin // The form is not nil, not freed and do not want to be freed
IsNilTheForm:=False; // Return value
end;
except // The form was freed but not set to nil
TheForm:=Nil; // Set it to nil since it had beed freed
IsNilTheForm:=True; // Return value
end;
end;
end;
So where you do if nil=MyForm then ... you can now do if (IsNilTheForm(MyForm)) then ....
That is it.
It is better the timer solution, since form is freed as soon as possible (less ram used), with the PleaseFreeAndNilMe trick the form is not freed until IsNilTheForm is called (if you do not free it any where else).
That IsNilTheForm is so complex because it is considering all states (for a multi socket motherboard and threaded apps) and letting the code free / nil it anywhere else.
Of course, that function must be called on main thread and in atomic exclusion.
Free a Form and Nil its pointer is not a trivial thing, most when user can close it at any time (since no code out of the form is fired).
The big problem is: When a user closes a form there is no way to have a event handler that is triggered out of that form and after the form ends all things it is doing.
Imaigne now that the coder has put a lot of Application.ProcessMessages; every where on the app, also on that form, etc... and has not taken the care for race conditions... try to free and nil such a form after the user asks it to be closed... this is a nightmare, but can be solved with the hacked version of TForm that has a variable that tells that the form has not been freed but wants it.
Now imagine you use hacked TForm and want a normal TForm, just define it as ...= class(Forms.TForm), that way it will now have that extra variable., so calling IsNilTheForm will act as comparing to nil.
Hope this helps VCL coders to FIX such things, like raising an event when an object is destroyed, freed, niled, hide, etc... out of the code of that object, like on main form, etc. That would make live easier... or just fix it... Close and Free implies set to Nil all refences that point to it.
There is another thing that can be done (but i try to allways avoid it): Have multiple variables that point to the exact same form (not to copies ot it), that is prone to a lot of errors, you free one and need to nil all of them, etc... The code i show is also compatible with that.
I know the code is comples... but Free and Nil a form is more complex than my code.

Delphi ignores CS_OWNDC flag when creating TFrame component, wglMakeCurrent subsequently fails

I'm trying to put together some components for using OpenGL in RAD Studio 2009. I want to have multiple Rendering Contexts.
My idea is to have something like a "main OpenGL component", called GLMaster. It's a TFrame descendant so it should provide me with a DC. Also there's a component for a GLMonitor, acting as camera.
I create an OpenGL RC in the overriden GLMaster.Loaded inside an "if not (csDesigning in ComponentState) then"-clause. The DC for this I do not keep, it's stated in the RAD Studio help that you shouldn't:
"TWinControl.Handle
Do not refer to the Handle property during component creation or streaming. The underlying window does not exist until the first time the Handle property is referenced. When this occurs, the HandleNeeded method is called automatically."
I handle this by function pointers in components using GLMaster pointing to GLMaster.GetCurrentDC (returns a HDC).
During destruction GLMonitor wants to clean up some render-to textures and other OpenGL resources. When retrieving the DC for a call to wglMakeActive the function pointer is followed and execution jumps to GLMaster.GetCurrentDC. Pointer(Self) tells me that it's the same GLMaster that we created the "master RC" in during the streaming of the components. The property [GLMaster.]Handle is now invalid! If I however free the GLMonitor in the app form's OnClose (using simply GLMonitor_1.Free;) the Handle inside GLMaster.GetCurrentDC is valid end everything works.
I managed to see that the handle used in GLMaster.Loaded is not the same (!?!?) as after the initialization is done and the app form is showed to the user. When I found this I googled my problem and added an overriden CreateParams to add CS_OWNDC to the GLMaster component. A breakpoint there tells me that it's being executed.
Why does the VCL/Delphi silently provides the newly created components with other Handles, and thereby indirectly other DCs, even if I provide the OWNDC flag? Is there someway to get an "ALL components are now loaded and their properties are read from the .dfm file and"-message so I can run GLMaster.InitEverything inside the component?
Right now I'm thinking the fastest way onward is to put this InitEverything in the main form's OnShow handler. And then a call to GLMatser.CleanAll in the main form's OnClose. But I don't want any code in the form, that's the reason I created the components in the first place!
P.S.
Not that I think it matters for this particular problem but I use OpenGL 3.2 Core Profile.
I'm answering the "Why does the VCL/Delphi silently provides the newly created components with other Handles".
Why an control's Window Handle might change at run-time
Your TFrame (an TWinControl descendant) is placed on an other TWinControl, let's say a TForm. The parent container provides property wrappers around many settings, allowing us to easily make changes; Some of those changes can't be implemented without re-creating the windhow handle. You can get a long list of properties that cause this to happen by doing a search for RecreateWnd in Forms.pas, Controls.pas etc.
Examples of properties that call RecreateWnd to implement a change at run-time:
TScollBox.BorderStyle
TForm.BorderIcons (for MDI childs)
When your TFrame's parent needs to change Window Handle, your TFrame is going to have to change Window Handle as well. Your Delphi Control, no matter the descendense, needs to be handle this, and other controls have it worst: Controls that are implemented as wrappers around Windows controls need to save state and reload state (TEdit, TComboBox, ...)
What I think is going on
While streaming (loading your form) some control does something that needs a Window Handle before loading finishes. It's very likely your own code! After everything finishes loading the Form might need to re-create it's Handle, and this in turn causes your Frame's handle to be changed.
What you might want to override
Given the way the VCL works, you need to be prepared for your Window Handle to change. You should do a search in Controls.pas for the words Handle, HDC. If your control is so intimately linked to it's Window Handle and HDC, it's in your best interest to read up on this stuff.
Take a look at those routintes. Maybe you can sopot a better place to hook:
CreateHandle
CreateWnd
DestroyHandle
DestroyWnd
GetDeviceContext
If the title is the question, then no, Delphi does not ignore CS_OWNDC when creating a frame. Just tested with the below procedure with a frame on a form. When the flag is not specified, the line is drawn on itself again and again, resulting with a line from (0,0) to (10,10). When the DC is owned, the line extends from (0,0) to (50,50), no need to tell but the retrieved DC is same at all times.
procedure TFrame2.WmPaint(var Msg: TWMPaint);
var
i: Integer;
DC: HDC;
Pt: TPoint;
begin
inherited;
for i := 1 to 5 do begin
DC := GetDC(Handle);
GetCurrentPositionEx(DC, #Pt);
LineTo(DC, Pt.X + 10, Pt.Y + 10);
ReleaseDC(Handle, DC);
end;
end;
if your question is this:
ALL components are now loaded and their properties are read from the .dfm file and
The answer is:
Yes, just override the Loaded method of your component. It is called when all the references are valid (after dfm reading is finished).

What's the difference between CreateWnd and CreateWindowHandle?

Delphi components have CreateWnd and CreateWindowHandle (and DestroyWnd and DestroyWindowHandle). They're both intended to be overridden by descendants, right? And not intended to be called except by the underlying VCL implementation?
What's the difference between them; when should either of them be overridden?
So far most of the answers here are pretty much on the mark and you would do well to heed their advice. However, there is a little more to this story. To your specific question about when you would override one or the other, I'll try and nutshell things a little bit.
CreateParams();
In general, most of the time all you really need to do is to override CreateParams(). If all you want to do is to subclass (remember Windows style "subclassing?" See Petzold's seminal work on Windows programming) an existing control class and wrap it up in a VCL control, you do this from CreateParams. You can also control what style bits are set and other various parameters. We've made the process of creating a "subclass" very easy. Just call CreateSubClass() from your CreateParams() method. See the core VCL controls for an example such as TCheckBox or TButton.
CreateWnd();
You would override this one if you need to do a little bit more with the window handle once it is created. For instance, if you have a control that is some kind of list, tree, or otherwise requires post-creation configuration, you'd do that here. Call the inherited CreateWnd, and when it returns (you know you have a valid handle if you return from CreateWnd because it will raise an exception if something went awry), just apply your extra magic. A common scenario is to take the data that is cached in an instance TStrings list and actually move it into the underlying window control. The TListBox is a classic example of this.
CreateWindowHandle();
I had to go refresh my memory on this one, but it seems this is one is rarely, if ever, overridden. In the few cases inside VCL itself, it appears that it is used to work around specific Windows version and locale oddities with some controls, such as the TEdit and TMemo. The other more clear-cut case is in TCustomForm itself. In this case it is there to support the old MDI (mutli-document interface) model. In this case MDI children cannot be created using the normal CreateWindowEx() API, you have to send a message to the MDI parent frame to actually create the handle. So the only reason to overide this method is if the actual process of creating the handle is done via a means completely different than the old tried-and-true CreateWindowEx().
I did notice that your question was merely asking about the creation process, but there are corresponding methods that are overridden in some cases for both handle destruction and the "voodoo" that sometimes surrounds handle recreation. But these are other topics that should be covered separately :-).
CreateWnd first calls CreateParams, then calls CreateWindowHandle using the created Params. Generally, you'll override CreateWnd and CreateParams rather than CreateWindowHandle.
I hope this helps!
Who does what:
CreateWnd is the general contractor that creates the fully formed window for a WinControl.
First, it has to set the required attributes for the WindowClass by calling CreateParams and making sure it is correctly registered.
Then it gets the window actually created, by calling CreateWindowHandle which returns the resulting Handle from the OS.
After that, we have a valid window able to process messages, and CreateWnd does the final grooming, adjusting different visual aspects like size, font, etc.
There is also later step done by CreateHandle, after CreateWnd is finished, to help the VCL in managing its windows (identification, parentage,...).
I'm sure that the final answer can only come from the people involved in the creation of the VCL (Allen?), but IMHO the virtual method with the least responsibility / which is lowest in the chain of calls should be overridden. That's why I have always overridden CreateParams() and CreateWindowHandle(). This looks like a good fit since they are both called by CreateWnd(), and both do only one special thing.
In the end it's probably a matter of preference.

Resources