How to check if unit and function exists? - delphi

I'm using Delphi 11. Is there a way to run a specific function inside a TDataModule, but only if this datamodule exists on my project ?
I need a way to check if the datamodule exists and call the function as string, because some projects will have this datamodule added, others not.
Instead of this :
myDataModule.myfunction(param);
Would be something like this imaginary code :
if TDataModule(findcomponent('myDataModule')) <> nil then
TDataModule(findcomponent('myDataModule')).call('myfunction','param');

A lightweight solution could be Messages (those from System.Messaging).
Declare a new TMessage descendant holding the parameters needed for the call
When the datamodule is created it Subscribes to this message type with a handler doing the actions.
Instead of searching for the datamodule just Send the message.

This may or may not be applicable to your situation... But that seems like the kind of situation I would solve with a multicast event.
Your code would call Event.Execute('Param') instead of myDataModule.myfunction(param).
The part of your code responsible for "importing" and creating the datamodule would register to the event. Something like :
EventClient := TEventClient.create(
procedure (const AParam : ParamType)
begin
myDataModule.myfunction(AParam)
end);
EventClient.Observe(Event);
Now, this approach makes sense if the reasons to call your function is "event-like", but this might make less sense in other contexts.
As for library implementing multicast event, I can't recommend any as I always used a proprietary one. If you need inspiration to implement your own, you can look at TMultiCaster in unit Vcl.AppEvnts which implements more or less the same concept.

Related

Empty Functions - Placeholder?

so I was just looking through the Code of our inventory management system
and I saw some Snippet's of one of my Coworkers, all he does in some Functions is
simply open them and insert a command in there for example
procedure TWerkStF.TBBtnStatiClick(Sender: TObject);
begin
inherited;
//
end;
so i am wondering when you should do something like that and when is it usefull, are there some benefits?
This is not useful, and has no benefits. Such a function can, and should, be removed.
The function in the question, by using inherited, simply searches in the super classes for a function of the same name, and if one is found calls it. If one is not found then no action is performed. As a rule, such a function, one that only calls inherited, does not modify the behaviour of the program. You can remove it without changing behaviour.
We use such functions/procedures most times to tell other Co-Workers where they should not change anything, the reason for that is because some events are just not fitting the needs of some Modules, therefore we "warn" each other with empty Functions.
Sounds wiered, i know.

A better way of creating from a class parameter?

In TApplication.CreateForm (not sure if it is allowed to paste the code here. I will do so if somemone confirms) it seems a way of creating an instance of a TForm descendant by using the class of the derived form and a variable pointing to the form. Both are parameters of CreateForm;
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
Is there a better or even simpler way (maybe with less code) of doing what is done in CreateForm if I wanted to have a method which creates a derived control with only some parameters as indicators of what class it is and the variable it will be using.
EDIT: I would like to have a method that creates a control which I use in my project. The method will also do some additional code related to the control so that is the reason for the method. I do not want to duplicate that additional work and the method will be called numerous times. I can implement the code in the same way as CreateForm but was wondering if there is a way of doing the same in less or simpler code.
I want to have a method which creates a derived control with only some parameters as indicators of what class it is and the variable it will be using.
You don't need a method for that. You can write it like this:
MyForm := TMyForm.Create(Owner);
Don't be put off by all the code in Application.CreateForm. That code performs many tasks, the principle of which is to assign the Application.MainForm variable. The IDE likes to encourage you to use Application.CreateForm but in reality you only need to call it once, and that is to create the main form.
If you are dead set on making this into a method then it would look like this:
function CreateForm(FormClass: TFormClass; Owner: TComponent): TForm;
begin
Result := FormClass.Create(Owner);
end;
When calling this function you would need to cast the value returned:
MyForm := TMyForm(CreateForm(TMyForm, Owner));
or
MyForm := CreateForm(TMyForm, Owner) as TMyForm;
As an alternative you could use a generic method:
type
TFormCreator = class
public
class function CreateForm<T: TForm>(Owner: TComponent): T; static;
end;
Implement it like this:
class function TFormCreator.CreateForm<T>(Owner: TComponent): T;
begin
Result := T(TFormClass(T).Create(Owner));
end;
Call it like this:
MyForm := TFormCreator.CreateForm<TMyForm>(Owner);
Pretty ridiculous isn't it? All you want to do is instantiate a form! So, I have a strong suspicion that you have been confused by the IDE's use of Application.CreateForm and believe that there is more to instantiating forms than there really is. My instincts tell me that you are actually looking for this:
MyForm := TMyForm.Create(Owner);
AS. You can post YOUR OWN code, but with regards to code which copyrights holds someone else - that gets a bit complicated. I believe it falls under USA "Fair Use" doctrine. For example you can post a snippet of VCL source to criticize or demonstrate something, but not to copy-paste it into another project and only as little of the VCL code - as required for that "fair use" intention.
A VCL form is a component, thus it needs an owner, who would be responsible for memory management. So you can create the form in a typical TComponent creation pattern.
MyFormVariable := TMyFormClass.Create( Application );
This also adds for type safety that untyped var Reference in CreateForm denies.
Whether that way is better or worse than using Application.CreateForm is up to your tastes. Personally I prefer uniform way so when I need to create a form or a datamodule explicitly I usually go the "component" way not the "application" way.
I guess (just guess) that back in old days TApplication.CreateForm added some extra required setup that "component way" of creating forms could not do, at least not before VCL would get started by Application.Run call. Or maybe there were types of TApplication - and AFAIR there are 5 ones for different projects - that were not derived from TComponent? But anyway I think today that limitations - if ever there where any - not apply any more.

Why is using procedures to create objects preferred over functions?

This is similar to this question. I asked "Why?" to the most popular response but I don't know that anyone would ever look at it again. At least not in any timely manner.
Anyway, my question is about best practices for delegating responsibility for creation of objects to functions or procedures, without causing memory leaks. It seems that this:
procedure FillObject(MyObject: TMyObject; SomeParam: Integer);
begin
//Database operations to fill object
end;
procedure CallUsingProcedure();
var
MyObject: TMyObject;
begin
MyObject = TMyObject.Create();
try
FillObject(MyObject, 1);
//use object
finally
MyObject.Free();
end;
end;
is preferred over this:
function CreateMyObject(DBID: Integer): TMyObject;
begin
Result := TMyObject.Create();
try
//Database operations to fill object
except on E: Exception do
begin
Result.Free();
raise;
end;
end;
end;
procedure CallUsingFunction();
var
MyObject: TMyObject;
begin
MyObject = CreateMyObject(1);
try
//use object
finally
MyObject.Free();
end;
end;
Why?
I'm relatively new to Delphi, having previously worked most with Java and PHP, as well as C++, though to a lesser extent. Intuitively, I lean toward the function method because:
It encapsulates the object creation code in the function, rather than create the object separately whenever I want to use the procedure.
I dislike methods that alter their parameters. It's often left undocumented and can make tracing bugs more difficult.
Vague, but admittedly it just "smells" bad to me.
I'm not saying I'm right. I just want to understand why the community chooses this method and if there is good reason for me to change.
Edit:
References to #E-Rock in comments are to me(Eric G). I changed my display name.
One problem is what Ken White wrote: you hand the user of the function an object he or she must free.
Another advantage of procedures is that you can pass several objects of a hierarchy, while a function that creates such an object always generates the same. E.g.
procedure PopulateStrings(Strings: TStrings);
To that procedure, you can pass any kind of TStrings, be it the Lines of a TMemo, the Items of a TListBox or TComboBox or a simple standalone TStringList. If you have a function:
function CreateStrings: TStrings;
You always get the same kind of object back (which object exactly is not known, as TStrings is abstract, so you probably get a TStringList), and must Assign() the contents to the TStrings you want to modify. The procedure is to be preferred, IMO.
Additionally, if you are the author of the function, you can't control whether the object you create is freed, or when. If you write a procedure, that problem is taken off your hands, since the user provides the object, and its lifetime is none of your concern. And you don't have to know the exact type of the object, it must just be of the class or a descendant of the parameter. IOW, it is also much better for the author of the function.
It is IMO seldom a good idea to return an object from a function, for all the reasons given. A procedure that only modifies the object has no dependency on the object and creates no dependency for the user.
FWIW, Another problem is if you do that from a DLL. The object returned uses the memory manager of the DLL, and also the VMT to which it points is in the DLL. That means that code that uses as or is in the user code does not work properly (since is and as use the VMT pointer to check for class identity). If the user must pass an object of his, to a procedure, that problem does not arise.
Update
As others commented, passing an object to a DLL is not a good idea either. Non-virtual functions will call the functions inside the DLL and use its memory manager, which can cause troubles too. And is and as will not work properly inside the DLL either. So simply don't pass objects into or out of a DLL. That goes with the maxime that DLLs should only use POD type parameters (or compound types -- arrays, records -- that only contain POD types) or COM interfaces. The COM interfaces should also only use the same kind of parameters.
Creating the object instance and passing it into another procedure makes it clear which code is responsible for freeing the instance.
In the first case (using a procedure to fill it):
MyObj := TMyObject.Create;
try
// Do whatever with MyObj
finally
MyObj.Free;
end;
This is clear that this block of code is responsible for freeing MyObj when it's finished being used.
MyObj := CreateMyObject(DBID);
What code is supposed to free it? When can you safely free it? Who is responsible for exception handling? How do you know (as a user of someone else's code)?
As a general rule, you should create, use, and free object instances where they're needed. This makes your code easier to maintain, and definitely makes it easier for someone who comes along later and has to try and figure it out. :)
I use a combination of both idioms. Pass the object as an optional parameter and if not passed, create the object. And in either case return the object as the function result.
This technique has (1) the flexibility of the creation of the object inside of the called function, and (2) the caller control of the caller passing the object as a parameter. Control in two meanings: control in the real type of the object being used, and control about the moment when to free the object.
This simple piece of code exemplifies this idiom.
function MakeList(aList:TStrings = nil):TStrings;
var s:TStrings;
begin
s:=aList;
if s=nil then
s:=TSTringList.Create;
s.Add('Adam');
s.Add('Eva');
result:=s;
end;
And here are three different ways to use it
simplest usage, for quick and dirty code
var sl1,sl2,sl3:TStrings;
sl1:=MakeList;
when programmer wants to make more explicit ownership and/or use a custom type
sl2:=MakeList(TMyStringsList.create);
when the object is previously created
sl3:=TMyStringList.Create;
....
MakeList(sl3);

Using another forms event procedure

Is there any way to allow one form to use the event procedures from another form?
E.g. I have a form called PongForm and another called ObstPongForm. There is a ticker on PongForm and another one on ObstPongForm. Is it possible to get ObstPongForm to use the code from PongForm's 'tick' event in it's own 'tick' event? Maybe by letting ObstPongForm inherit from PongForm?
You can simply assign it by code (as long as you have access to both instances):
ObstPongForm.Ticker.OnTick := PongForm.TickerTick;
Yes, forms are just classes like any other, and Delphi supports visual inheritance, so you can call inherited methods normally.
If ObstPongForm is a specialized version of PongForm then inheritance makes sense, but be careful as ObstPongForm will inherit all visual controls from the PongForm, including whatever you may add in the future.
Also since I assume you already have both forms, making one inherit from another is doable but requires some manual DFM editing, mainly changing the
Object ObstPongForm: TObstPongForm
to
Inherited ObstPongForm: TObstPongForm
If the code you want to reuse may be needed in several unrelated forms, then moving the code to a common unit used by these forms may be the best solution
It would be better style to have both of the forms call another class that implements the logic used by both. If you're writing all your program logic in your OnTimer event handler, you're heading down a bad road that many delphi programmers take years to realize was a bad idea
So one form needs to call your method, it does it like this:
procedure TForm1.DoSomething;
begin
DataModule1.LogicMethod;
end;
Elsewhere there is a timer...
procedure TForm2.Timer1Timer(Sender:TObject);
begin
DataModule1.LogicMethod;
end;
And then the method itself:
procedure TDataModule1.LogicMethod;
begin
// Everything that you used to have in Timer1Timer goes here, except the setting of
// UI properties in Form1 which is kept in Form1:
Inc(FCounter);// stupid example.
//
if Assigned(FOnResults) then
FOnResults(Self, FCounter, FDataObject1);
// Form2 is connected to FOnResults event, and stores the
// result in the UI somewhere.
end;
Event handlers are just normal procedures. If your ObstPongForm tick handler has additional code that it needs to run in addition to the PongForm's code, then you can call the PongForm's tick handler manually when needed, eg:
uses
..., PongForm;
procedure ObstPongForm.TickHandler(Sender: TObject);
begin
...
PongForm.TickHandler(Self);
...
end;

How to register a component and property editor at run-time?

After much searching, it looks like I have to assign RegisterComponentsProc and RegisterPropertyEditorProc, which I have done.
However, I thought that I could call my design time Register function, i.e. <myComponentUnit>.Register();.
When I do I get stack overflow, because, well ...
procedure myComponentUnit.Regiter;
begin
RegisterPropertyEditor(TypeInfo(Integer),
TMyComponent, 'myProperty', TMyProperty);
end;
procedure RegisterPropertyEditor(PropertyType: PTypeInfo;
ComponentClass: TClass; const PropertyName: string;
EditorClass: TPropertyEditorClass);
begin
if Assigned(RegisterPropertyEditorProc) then
RegisterPropertyEditorProc(PropertyType, ComponentClass, PropertyName,
EditorClass);
end;
So, I call .Register();
which calls RegisterPropertyEditor()
which call RegisterPropertyEditorProc()
which calls RegisterPropertyEditor() <=== aaargh!!
So, what should I have in the body of my RegisterPropertyEditorProc ?
After further searching, it looks like I want to call DesignEditors.RegisterPropertyEditor() directly, but it is not in the interface section ...
There is no point in trying to register a property editor at run-time, as it is not usable at run-time to begin with. It is only usable within the IDE during design-time.
Delphi does not include the source for the DesignEditors unit; its implementation is provided solely in the DesignIDE package. That package has access to IDE internals, such as the list of registered property editors. The IDE assigns values to the RegisterComponentsProc and RegisterPropertyEditorProc callback functions. As you noticed, RegisterPropertyEditor calls RegisterPropertyEditorProc. The IDE provides its own function to handle that event.
If you want to register a property editor at run time, then your program plays the role of the IDE. You need to provide implementations for those callback functions to register the property-editor classes with your own property-editing framework. You could probably just keep everything in a simple list. Then, when you want to know what kind of editor to display for a certain type of property, consult the list to find the best match.
You're correct that you should call your units' Register procedures. But that's how you initiate the registration process, not how you implement it. That part's up to you; Delphi doesn't provide any of this for you.

Resources