Delphi access private function in VCL unit - delphi

How do I access private function in a VCL unit?
I need to call the function ColorToPrettyName from ExtCtrls.pas.
Now I copied this to my source but IMO nicer would be to use that function instead.
Some more details:
The function is used in TColorBox, but I only need the pretty name.
I tried to instantiate TColorBox and get the pretty name from it, but this is only possible when I have some TWinControl to assign to its Parent. But that TWinControl I don't have in the place where I want to use the pretty name and I don't want to do any hacks.

You cannot readily call this function from outside the unit since it is not exposed.
You could create an instance of the control that calls the function, and persuade it to do the dirty work. That's perfectly feasible as another another answer demonstrates.
You could use a disassembler to find the address of the function and call it using a procedural variable. The madExcept source code is a great source of examples of that technique.
On balance, copying the source to your code is, in my view, the best option. All of your available options have drawbacks and this seems the simplest.

You will find a sample how to access the ColorToPrettyName here:
https://github.com/project-jedi/jvcl/blob/master/donations/Colors/JvFullColorSpaces.pas
// (outchy) Hook of TColorBox to have access to color's pretty names.
// Shame on me but that's the only way to access ColorToPrettyName array in the
// ExtCtrls unit. Thanks Borland.
{$IFDEF COMPILER6_UP}
type
TJvHookColorBox = class (TCustomColorBox)
protected
function GetItemsClass: TCustomComboBoxStringsClass; override;
procedure DestroyWindowHandle; override;
public
constructor Create; reintroduce;
procedure CreateWnd; override;
procedure DestroyWnd; override;
end;
........
This is what you asked, though this is definitely not good practice.
A better solution would be to use the same function from JEDI (JvJCLUtils.pas), although this adds a dependency.
You will find JEDI here: http://jvcl.delphi-jedi.org/
It contains many more useful utilities and components.

Like David said; copying the source to your own unit will be the best.
I believe ColorToPrettyName will not be changed that often but if you are worried that it will and your copied code will be different upon an upgrade of Delphi then you can add a compiler directive to your code that checks the version and warns you about it. Then you can update your code and wait till the next time you upgrade your Delphi. Easy.

Related

Call a procedure of a class from DWScript

How can I call a procedure from a class that is created in main Form. Can it be done like this pseudo code shows?
type
TDemo = class
procedure test;
constructor Create;
destructor Destroy; override;
end;
var
Form28: TForm28;
Demo:TDemo;
implementation
{$R *.dfm}
procedure TForm28.Button1Click(Sender: TObject);
var
prog : IdwsProgram;
exec : IdwsProgramExecution;
begin
Demo := TDemo.Create;
prog := DelphiWebScript1.Compile('Demo.Test;');
exec := prog.Execute;
end;
There is a limited RTTI exposer and RTTI connector, which allow to access Delphi classes through RTTI.
These RTTI tools haven't been explored much however, as most of the Delphi classes are not "safe" to use for scripting. By that I mean that it's easy to crash the host or leak memory, and so "raw" Delphi classes are typically unsuitable for end-user scripting (ie. end users won't have a right to error, you won't be able to offer stable debugging, etc.).
An alternative to manual exposure and strengthening of the exposed classes in event handlers of a TdwsUnit is to expose your classes as OLE Automation objects, and then you can use the DWScript COM Connector to access them. Then benefits is that to expose the automation objects, you'll usually have had to do at least minimal strengthening vs memory leaks and dangling pointers, and your automation classes will be accessible from other COM-capable environments.
As an example of RTTI going wrong, consider a fully automatically-managed VCL classes like TComponent or TCollection, if you only have raw RTTI exposure, than a script doing something like:
item := myCollection.Add;
myCollection.Clear;
item.Caption := 'hello bug';
will result in a random memory overwrite in the host application, without any safe ways to notify the script user about the potential error.
The upcoming Delphi ARC compilers may offer a way to mitigate the memory overwrites for some classes (though not all, due to the way ARC is currently implemented/circumvented for TComponent and others). Also Delphi ARC compilers are currently unsupported (for a variety of reasons, the most prominent one being I currently don't have access to them).
To do this, you first have to expose your native class to the script engine. Have a look at the TdwsUnit component. It declares a script unit that interfaces with external code. You'd drop one on your form, define the class, define its methods, and hook up event handlers on the OnEval events that call the external routines.

how to define classes inside classes in delphi?

I am in the progress of trying to learn a few new tricks in order to better organize some of the sourcecode in my units in Delphi.
I have noticed that some functions or methods I access appear to be classes inside classes, but I have not yet been successful in making a working class inside a class, although it compiles fine, I still get error messages when executing the code.
What I would like to do is to make kind of a tree with functions, procedures and values to set or get. I would be grateful if somebody could help me out a little bit with an example.
I have today some classes that are Types.
I then assign the types to a variable:
something=TSomething
and Then for something to happen I write "something.action".
My aim is to go further, and define sub-functions or/and sub-procedures.
Lets say I have three or four classes. TSnippet, TAction1, TAction2, TSubAction1, Etc.
I would like to use or assign these to a single variable and use them like:
Snippet.Action1.SubAction1.Organize(param1,param2);
Snippet.Action2.SubAction2.Returns='SomeString';
Snippet.Action1.SubAction1.SomeProcedure;
Is anybody able to help me with a useful example as in how to write code for this approach to work?
And also.. does anybydy know how such an implementation of code will affect CPYCycles needed in order to execute code versus the old fashioned method of having thousands of procedures with all different names, but more direct access (it feels like more direct access).
As of my first text was maybe a bit unclear, this follows.
I would like to make use of the editors automatic suggestions of procedures/functions available in order to simplify programming a little bit.
I started to make a Class for this, and it works great.
Consider a classname "Data". What can we do with data? We can Edit, Add, Delete, Save and Load.
Ok. This is my first Class.
Consider then another Class: "Encrypt". We can do DES, DES3, HASH, BITSHUFFLE.
I can go on with a third Class: "Compress". We can do LZW, ZIP, RAR, MP3, MPG, MP4, etc.
Instead of using these as 3 different classes, I would like to combine them in one, yet keeping them separate.
I would like to make a kind of an OwnerClass for the other classes. We can call this "MyStuff"
Whenever I type "MyStuff." in the editor, I should get up a list of "Data, Encrypt, Compress". Further, When I then choose "Compress", the next list for that class' procedures and functions will list up.
The classes may have some local variables, but the main functionality will be towards global arrays.
Maybe there are other ways of achieving this. I don't know.
My basic aim is to be able to categorize and put together routines that belong together.
This is already done in Units, but this does not help with the automatic list from the editor.
Thank you in advance.
Morten.
I think I understand what it is you're asking, after your edit.
What you're calling "classes in classes" are called properties and methods; they're other classes, variables, or procedures/functions that are declared in their containing class. The "list" you're talking about is called Code Insight, and it shows you the available properties and methods of the class you're referencing in your code at that point.
This should do something like you describe, and give you an idea of how to implement it in your own code:
unit MyStuffUnit;
interface
uses
SysUtils;
type
TEncryptionType = (etDES, etDES3, etHASH, etBITSHUFFLE);
TMyStuffEncryption = class(TObject)
private
FEncryptType: TEncryptionType;
public
constructor Create;
published
property EncryptionType: TEncryptionType read FEncryptType
write FEncryptType;
end;
TCompressionType = (ctLZW, ctZIP, ctRAR, ctMP3, ctMPG, ctMP4);
TMyStuffCompression = class(TObject)
private
FCompressionType: TCompressionType;
public
constructor Create;
published
property CompressionType: TCompressionType read FCompressionType
write FCompressionType;
end;
TMyStuff = class(TObject)
private
FCompression: TMyStuffCompression;
FEncryption: TMyStuffEncryption;
public
constructor Create;
destructor Destroy; override;
published
property Compression: TMyStuffCompression read FCompression
write FCompression;
property Encryption: TMyStuffEncryption read FEncryption
write FEncryption;
end;
implementation
constructor TMyStuffEncryption.Create;
begin
inherited;
FEncryptType := etDES;
end;
constructor TMyStuffCompression.Create;
begin
inherited;
FCompressionType := ctLZW;
end;
constructor TMyStuff.Create;
begin
inherited;
FCompression := TMyStuffCompression.Create;
FEncryption := TMyStuffEncryption.Create;
end;
destructor TMyStuff.Destroy;
begin
FCompression.Free;
FEncryption.Free;
inherited;
end;
end.
If you create an instance of TMyStuff in your code, you should be able to type MyStuff. and get the option of choosing Compression or Encryption. Choosing Compression should allow you to set the CompressionType property.
This should be enough to get you going. :-) Remember that Delphi includes the source code for the VCL and RTL in almost all editions, so you always have that to look at for examples. (They're not always the very best examples, but they should give you ideas on how to do things.)

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.

getting around circular references in Delphi [duplicate]

This question already has answers here:
Delphi Enterprise: how can I apply the Visitor Pattern without circular references?
(4 answers)
Closed 8 years ago.
Is there a way of getting around circular unit references in Delphi?
Maybe a newer version of delphi or some magic hack or something?
My delphi project has 100 000+ lines of code mostly based on singleton classes. I need to refactor this, but that would mean several months of "circular reference" hell :)
I've been maintaining close to a million lines of legacy code for the past 10 years so I understand your pain!
In the code that I maintain, when I've encountered circular uses, I frequently have found that they are caused by constants or type definitions in unit A that are needed by unit B. (Sometimes it's also a small bit of code (or even, global variables) in Unit A that is also needed by unit B.
In this situation (when I'm lucky!) I can carefully extract those parts of the code into a new unit C that contains the constants, type definitions, and shared code. Then units A and B use unit C.
I post the above with some hesitance because I'm not an expert on software design and realize there are many others here who are far more knowledgeable than I am. Hopefully, though, my experience will be of some use to you.
It seems you have quite serious code design issues. Besides many signs of such issues, one is the circular unit reference. But as you said: you cannot refactor all the code.
Move all what is possible to the implementation section. They are allowed to have circular references.
To simplify this task you can use 3rd party tools. I would recommend
Peganza Pascal Analyzer - it will suggest what you can move to the implementation section. And will give you many more hints to improve your code quality.
Use the implementation section uses whenever possible, and limit what's in the interface uses clause to what has to be visible in the interface declarations.
There is no "magic hack". Circular references would cause an endless loop for the compiler (unit A requires compiling unit B which requires compiling unit A which requires compiling unit B, etc.).
If you have a specific instance where you think you cannot avoid circular references, edit your post and provide the code; I'm sure someone here can help you figure out how to get it fixed.
There is many ways to avoid circular references.
Delegates.
Way too often, an object will execute some code that should be done in an event instead than being done by the object itself. Whether it is because the programmer working on the project was too short on time(aren't we always?), didn't have enough experience/knowledge or was just lazy, some code like this eventually end up in applications. Real world exemple : TCPSocket component that directly update some visual component on the application's MainForm instead of having the main form register a "OnTCPActivity" procedure on the component.
Abstract Classes/Interfaces. Using either of them allow to remove a direct dependance between many units. An abstract class or an interface can be declared alone in its own unit, limiting dependancies to a maximum. Exemple: Our application has a debug form. It has uses on pretty much the whole application as it displays information from various area of the application. Even worse, every form that allows to show the debug form will also also end up requiring all the units from the debug form. A better approach would be to have a debug form which is essentially empty, but that has the capacity to register "DebugFrames".
TDebugFrm.RegisterDebugFrame(Frame : TDebugFrame);
That way, the TDebugFrm has no dependancies of its own (Except than on the TDebugFrame class). Any and all unit that requires to show the debug form can do so without risking to add too many dependancies either.
There are many other exemple... I bet it could fill a book of its own. Designing a clean class hierarchy in a time efficient fashion is pretty hard to do and it comes with experience. Knowing the tools available to achieve it and how to use them is the 1st step to achieve it. But to answer your question... There is no 1-size-fit-all answer to your question, it's always to be taken on a case by case basis.
Similar Question: Delphi Enterprise: how can I apply the Visitor Pattern without circular references?
The solution presented by Uwe Raabe uses interfaces to resolve the circular dependency.
Modelmaker Code Explorer has a really nice wizard for listing all the uses, including cycles.
It requires that your project compiles.
I agree with the other posters that it is a design issue.
You should carefully look at your design, and remove unused units.
At DelphiLive'09, I did a session titled Smarter code with Databases and data aware controls which contains quite few tips on good design (not limited to DB apps).
--jeroen
I found a solution that doesn't need the use of Interfaces but may not resolve every issues of the circular reference.
I have two classes in two units: TMap and TTile.
TMap contains a map and display it using isometric tiles (TTile).
I wanted to have a pointer in TTile to point back on the map. Map is a class property of TTile.
Class Var FoMap: TObject;
Normaly, you will need to declare each corresponding unit in the other unit... and get the circular reference.
Here, how I get around it.
In TTile, I declare map to be a TObject and move Map unit in the Uses clause of the Implementation section.
That way I can use map but need to cast it each time to TMap to access its properties.
Can I do better? If I could use a getter function to type cast it. But I will need to move Uses Map in the Interface section.... So, back to square one.
In the Implementation section, I did declare a getter function that is not part of my class. A Simple function.
Implementation
Uses Map;
Function Map: TMap;
Begin
Result := TMap(TTile.Map);
End;
Cool, I thought. Now, every time I need to call a property of my Map, I just use Map.MyProperty.
Ouch! Did compile! :) Did not work the expected way. The compiler use the Map property of TTile and not my function.
So, I rename my function to aMap. But my Muse spoke to me. NOOOOO! Rename the Class Property to aMap... Now I can use Map the way I intented it.
Map.Size; This call my little function, who typecast aMap as TMap;
Patrick Forest
I gave a previous answer but after some thinking and scratching I found a better way to solve the circular reference problem. Here my first unit who need a pointer on an object TB define in unit B.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, b, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
FoB: TB;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
FoB := TB.Create(Self);
showmessage(FoB.owner.name);
end;
end.
Here the code of the Unit B where TB has a pointer on TForm1.
unit B;
interface
Uses
dialogs, Forms;
type
TForm1 = class(TForm);
TB = class
private
FaOwner: TForm1;
public
constructor Create(aOwner: TForm);
property owner: TForm1 read FaOwner;
end;
implementation
uses unit1;
Constructor TB.create(aOwner: TForm);
Begin
FaOwner := TForm1(aOwner);
FaOwner.Left := 500;
End;//Constructor
end.
And here why it compiles. First Unit B declare the use of Unit1 in the implementation section. Resolving immediately the circular reference unit between Unit1 et Unit B.
But to allow Delphi to compile, I need to give him something to chew on the declaration of FaOwner: TForm1. So, I add stub class name TForm1 who match the declaration of TForm1 in Unit1.
Next, when come the time to call the constructor, TForm1 is able to pass itself has the parameter. In the constructor code, I need to typecast the aOwner parameter to Unit1.TForm1. And voilĂ , FaOwner his set to point on my form.
Now, if the class TB need to use FaOwner internally, I don't need to typecast it every time
to Unit1.TForm1 because both declaration are the same. Note that you could set the declaration of to constructor to
Constructor TB.create(aOwner: TForm1);
but when TForm1 will call the constructor and pass itself has a parameter, you will need to typecast it has b.TForm1. Otherwise Delphi will throw an error telling that both TForm1 are not compatible. So each time you call the TB.constructor you will need to typecast to the appropriate TForm1. The first solution, using a common ancestor, his better. Write the typecast once and forget it.
After I posted it, I realized that I made a mistake telling that both TForm1 were identical. They are not Unit1.TForm1 has components and methods that are unknown to B.TForm1. Has long TB doesn't need to use them or just need to use the commonality given by TForm you're okay. If you need to call something particular to UNit1.TForm1 from TB, you will need to typecast it to Unit1.TForm1.
I try it and test it with Delphi 2010 and it compiled and worked.
Hope it will help and spare you some headache.

Get list of object's methods, properties and events?

When trying a new component for which there's no documentation, I need to go through its methods, properties, and events to try to figure out what it can do. Doing this through the IDE's Object Inspector is a bit tedious.
Is there a utility that presents this list in a more readable format?
Thank you.
When I want to know what something can do, I read the source code. The class declaration will contain a succinct list of all the methods and properties, unless there is a lot of inheritance. The definitions will tell you want the methods do.
Another thing is to declare a variable of the type you're interested in, type its name and a period, and then press Ctrl+Space to let Class Completion show you everything you can do.
As the others said, use the source. Also an UML tool will help.
But if you don't want to use this, you can use this procedure (you need Delphi 2010 for this, and be sure to add RTTI to your 'Uses' clause):
procedure DumpProps(aObject: TObject; aList: TStringList);
var
RttiContext: TRttiContext;
RttiType: TRttiType;
I: Integer;
n: integer;
props: TArray<TRttiProperty>;
begin
aList.Clear; //it must be <> nil
RttiType := RttiContext.GetType(aObject.ClassType);
props:=RttiType.GetProperties;
with aList do
begin
Append('');
Append('==========');
Append('Begin Dump');
Append('----------');
for I := Low(props) to High(props) do
begin
try
Append(props[i].Name+': '); //odd construction to see if the Getter blows
n:=Count-1;
Strings[n]:=Strings[n]+props[i].GetValue(aObject).AsString;
except
on E: Exception do
Strings[n]:=Strings[n]+' >>> ERROR! <<< '+E.Message;
end;
end;
end;
end;
The above you can use either at run-time, either if you build a Menu Wizard, you can have your info at design time.
HTH
You can use the Class Browser that comes with GExperts.
I would also recommend to build a Model diagram with the IDE or ModelMaker. It helps to see the visual relations.
In the immortal words of Obi Wan Kenobi -- "Use the source".
There is no substitute for reading and understanding the source code of a component (or anything) to understand what it does and what it is up to.
Source code is the Lingua Franca of programming.
Look at the .hpp that is generated for C++Builder support. It resembles the interface section of a Delphi unit.
I just use code completion. If you can't figure out what the component does from the names of the properties and methods, then it's probably poorly designed anyway, and you're better off not using it. Also, since you're asking the question, I'm guessing you do not have the source. If you don't, again, I wouldn't use the component. You're only storing trouble for yourself.
There is RTTI...

Resources