How to change the parent class of an inherited class at runtime in Delphi? - delphi

Hi I'm developing a TControl descendant, lets name it THTMLBaseControl, at runtime that control only generates and output HTML code based on the settings of that control, so all the additional properties of the base TControl class and methods, including Windows Messaging system is really not used at runtime and causes memory overhead.
I need that control to be inherited from TControl so at design time I can use all the IDE designer stuff.
But at runtime almost all of those properties that at desingtime are needed i dont need them.
I also have all my controls inherited from that THTMLBaseControl, so creating a wrapper class per control class is not an option because it will duplicate the code a lot.
So what i need is something that at runtime, before the class is instantiated I can change the parent class so it will be instantiated based on another TControl-like class, maybe named TmyBaseControl inherited from "TComponent" as TControl Does, but that will not have all that TControl memory overhead and will only have the properties and methods needed by my THTMLBaseControl.
I really dont have a GUI at rutime is a web server that will serve only HTML, is some thing that intraweb and Raudus do, but always the issue is that all are based on TControl, so they have to be created at run time and generate a lot memory and process overhead that is not used. and maybe there could a solution so any THTMlBaseControl descendant instantiated at runtime will inherit the all properties and methods from TmyBaseControl and not from TControl.
I have seen there are ways to hack the VMT but maybe there are other solution and have not seen it. I already done changing the NewInstance, ClassParent and TnstanceSize class methods but i have to specify from which class and obviously i have to do the same steps per each inherited THTMLBaseControl class
And for the sake of all:
This is just a doubt, I need the components to be controls like TEdit, TPanel, visible and editable by the designer IDE I even could create my own TControl class but I was just thinking if I can reuse the code already existing.
Regards

You cannot change the class a run time. Once an object is instantiated, its class is fixed. You could hack the object to change its VMT pointer, making it refer to a different class, but that would still not address your main concern, which is memory usage — even if you change the VMT pointer, all the memory for the object has already been allocated; changing the VMT pointer doesn't magically make the object occupy less memory.
The first thing you could do is stop descending from TControl. As you've noted, you don't need any of the things it provides. All you want is something you can drop on a form at design time to set its properties. For that, all you need is TComponent, so make that your base class instead of TControl. Then you'll get something more like TTimer, which has no GUI. Once you've done that, you no longer need TForm, either. Instead, you can put your component on a TDataModule, which is specifically designed for managing non-visual components at design time.

Related

Hide properties and events in new component

I created in Lazarus a new component based on TPaintBox. Now in Object Inspector I have all Properties and Events which belong to this base component (TPaintBox).
My question is: can I hide chosen Properties and Events for my component?
For example I would like to leave visible only Width and Height properties.
Can you help me?
Once a property/event has been published, it cannot be un-published.
However, it can be hidden from the Object Inspector, at least (it is still accessible to code).
After your design-time code has registered the component with the IDE, it can then:
in Delphi, call UnlistPublishedProperty() from the DesignIntf unit.
in Lazarus, call RegisterPropertyEditor() from the PropEdits unit to register the THiddenPropertyEditor class for the property/event (see Hide Properties (UnlistPublishedProperty) in the Lazarus forum).
Not sure about Lazarus, but in Delphi TPaintBox is a lightweight descendant of TGraphicControl. The majority of its declaration is just publishing properties. I don't know what your component is doing, but it might be easier to derive it directly from TGraphicControl and duplicate the TPaintBox code wherever it actually is needed. Then you can publish only the properties you want. Note that you still have those properties declared published in TControl and TComponent.
No, you can't hide (unpublish) published properties.
In Delphi most objects are based on a parent classes with all the same properties, but mostly hidden.
So while you can't hide exposed properties you can usually achieve what you want by basing your class on the TCustomxxx instead.
Sadly, TPaintbox is an exception. It is descended from TGraphicControl, but that in turn is descended from TControl which already has a number of published properties, including AlignWithMargins, CustomHint and several others, and that in turn is descended from TComponent which has Name and Tag published. To be fair, you need name for sure, and Tag is not a problem I would think.
If you just had to go back to TGraphicControl, that is not too bad. Just one member and a couple of routines to copy. But to go back to TComponent, which is what you would need to do to hide a number of properties is not really viable.

Class Reference as Property

Google is useless for these sorts of searches, because you get hundreds of millions of results absolutely none of which relate to the specific question.
The question is simply this:
Is it possible to have a Class Reference Property in Delphi?
If so, how?
Here's what I've tried...
type
TMyObject = class
// ...
end;
TMyObjectClass = class of TMyObject
TMyObjectA = class(TMyObject)
// specifics here
end;
TMyObjectB =class(TMyObject)
// specifics here
end;
TMyComponent = class(TComponent)
private
FObjectType: TMyObjectClass;
published
property ObjectType: TMyObjectClass read FObjectType write FObjectType;
end;
The above code compiles fine, however the Object Inspector does not show the ObjectType property at all.
My objective here (if you haven't already guessed) is to make it so that I can select a class descendant from a specific base class, to make the same component behave in a different way.
I want to do it this way so that the component doesn't need to know about the sub-classes directly (it needs to be fully modular).
Let me just make this bit clear: I cannot use an Enum to choose between the sub-class types as the component cannot directly link to the sub-class types (It's simply not possible in this particular case)
Anyway... thanks in advance!
You can find all classes that descend from a particular base class: Delphi: At runtime find classes that descend from a given base class? and make this a special property with list of values using TPropertyEditor.
If you were going to do this then you would need to provide a property editor. The IDE does not come with property editors for class type properties. You would also need to handle .dfm persistence. You would write the class type out to the .dfm file as a string and when the .dfm file is read, you would need to fixup the reference. New style RTTI could do that.
However, I don't think any of this is actually viable for the following reason. Your design time code runs in a package inside the IDE and does not have access to the class types in the active project in the IDE. Those class types only exist when that project runs. So the ObjectType property in the code in your question cannot be assigned to anything meaningful in the design time package. Well, you could use it for classes defined in the VCL and any other packages installed in your IDE but I rather imagine you'd want to use it on classes defined in the active project.
I think all this means that you should instead use a simple string property and fixup the class type references only at runtime.

How to explicitly release GDI handles allocated by TForm derived class owned by the Application?

A single class derived from TForm appears to hold onto GDI handles until the application is closed.
class TTestForm : public TForm {
public:
TTestForm(TComponent*);
};
std::auto_ptr<TTestForm> test(new TTestForm(NULL));
test->ShowModal();
I'm quite new to VCL, so please bear with me. This test was done with a form that contains no controls. As far as I udnerstand, all objects are owned by the Application if no owner is specified.
My application creates (and destroys) a lot of forms dynamically. 3-4 new GDI handles are allocated each time a form is displayed. Is there a way to explicitly release those GDI handles during application lifetime?
Caveat: I'm a Delphi programmer, not C++, but the VCL is basically the VCL. You can try the form's Release() method instead of free(). Or alternatively, in the OnClose event set the Action parameter passed to caFree - thats supposed to tell the VCL to free the window's resources when the form closes, rather than hiding it.
I guess another question is - do you need to keep creating/destroying the forms? Can you create them once and then reuse them?
It turns out that the leak was caused by an incorrectly set TImageList.ShareImages property.

Where should a class free its private variables?

As there is no garbage collection in Delphi, where exactly do you unload variables?
Say I have a type with a set of private vars.
Would it suffice to have a Destroy method that does this work?
Do I need to explicitly call this destroy method in my consuming classes?
The best way to organize destruction in delphi is to always think about "who will create the given vars".
If you also free them in this context (For you private vars the destroy method of the class) it's much less likely that you will encounter memory leaks.
Actually the destructor of a class is normally not called via
myInstance.Destroy();
instead the typical way of doing it is via
FreeAndNil(myInstance);
or
myInstance.Free();
As delphi will handle calling the destructor method at order
Objects need to be destroyed when you are ready with them: using .Free (which calls the destructor .Destroy) or FreeAndNil.
If you are using interfaces: they are reference counted and hence they are freed for you. The same for strings.
Most functions that you need to pass an object do not take ownership of the object so you should free it afterwards when you are done with them. If you create components on a form, please note that they are objects, are owned by the form and you should let the form free them for you.
For example: in your TLight you create a TTimer probably without an owner. In this case you should Free the timer in the destructor of the TLight class. If your TLight was a TControl or TComponent itself you could have created the Timer with Self as the Owner and it was automatically freed when your TLight instance was freed.
That's how I see it:
Primitive types (like integer, real, double, extended), arrays, sets, records: they are automatically destroyed when out of scope.
Reference-counted types (strings, interfaces types, interface references): they are automatically destroyed when their reference counter is equal to zero.
Objects from classes that fall in one of those situations: does not descend from TComponent, are in list objects that do not implement ownership or are a TComponent descendant but does not have an owner assigned to it:
When their class descend from TInterfacesObject and are accessed from a interface reference: same behavior from reference-counter types (see above)
Other cases: call Object.Free or FreeAndNil(Object) to manually destroy it (in a try..finally structure would be even better)
Objects that have an owner (TComponent descendants or are in list objects that implement ownership): the owner will take of them in proper time.
I noticed the following comment from OP:
I have noticed the concept of owner.
Yet I couldn't pass my custom class to
the TTimer.Create() method as it is
expecting a TComponent. Why do they
restrict things to be used in forms
only? Doesn't that furhter petrify the
bad habit of putting logic in your
views (forms)?
See, a TComponent descendant can be registered on the pallete to have the ability to be used in design-time (for example, in a form) . But it's doesn't means it must!!
You can pass your custom-class to TTimer.Create() if it descends from TComponent but you don't need to instantiate it in design-time - or even be owned by a TForm descendant (if you want to manage it's lifetime, you don't even need an owner!).
Ownership is a mechanism it's to help people to save time....
You keep referring to a "type with private vars" and asking about "unloading variables." I'm going to go out on a limb (as I may be have misinterpreted your message), and presume you're talking about class variables and are asking about when these class variables should be finalized when the "class unloads." (You've been doing Java or .NET programming at some point, no ;-).
The key to what you're asking is a unit finalization section. The overall layout of a unit includes 4 overall sections, two of which are optional, initialization and finalization.
unit Foo;
interface
// put things here you want other units to see
implementation
// put the *implementation* of the things from the interface here along with things
// you only want this unit to see.
initialization
// <optional> put code here that you want to execute when this unit is "loaded"
finalization
// <optional> put code here that you want to execute when this unit is "unloaded"
end.
If you're talking about instance variables of a class type, then some of the other answers you've already gotten (and are bound to get) should shed some light on that.

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