Impossible to call Binarysearch function for TObjectList - delphi

If we look into the online help of XE2 or XE3 for TObjectList methods
, we see that the binarysearch function is accessible for the TObjectList. But if we try into XE3 it doesn't even compile.
For the example, the sort function is available also, but this one compile.
Any idea is welcome.
Sample code :
unit FM_Main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Contnrs, Vcl.CheckLst, System.Generics.Collections;
type
TTPRODData = class
private
FData1 : String;
FData2 : String;
FCount : Integer;
public
constructor Create; overload;
destructor Destroy; override;
end;
TTPRODDataList = class(TObjectList)
function GetItem(Index: Integer): TTPRODData;
procedure SetItem(Index: Integer; const Value: TTPRODData);
public
constructor Create; overload;
destructor Destroy; override;
property Items[Index: Integer]: TTPRODData read GetItem write SetItem; default;
procedure SortOnProductCode;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//
// Sort function.
//
function CompareProductCode(Item1, Item2: Pointer): Integer;
begin
Result := CompareStr(TTPRODData(Item1).FData1, TTPRODData(Item2).FData1);
end;
//
//
//
procedure TForm1.Button1Click(Sender: TObject);
var
aProdList : TTPRODDataList;
aDummy : TTPRODData;
aNdx : Integer;
begin
aProdList := TTPRODDataList.Create;
// This call works.
aProdList.Sort(CompareProductCode);
// This call doesn't even compile !
aProdList.BinarySearch(aDummy, aNdx);
end;
{ TTPRODData }
constructor TTPRODData.Create;
begin
inherited Create;
FData1 := '';
FData2 := '';
FCount := 0;
end;
destructor TTPRODData.Destroy;
begin
inherited;
end;
{ TTPRODDataList }
constructor TTPRODDataList.Create;
begin
inherited Create;
end;
destructor TTPRODDataList.Destroy;
begin
Clear;
inherited;
end;
function TTPRODDataList.GetItem(Index: Integer): TTPRODData;
begin
result := TTPRODData(inherited GetItem(index));
end;
procedure TTPRODDataList.SetItem(Index: Integer; const Value: TTPRODData);
begin
inherited setItem(index, value);
end;
procedure TTPRODDataList.SortOnProductCode;
begin
Sort(CompareProductCode);
end;
end.
As suggested by David Heffernan, here follow the code for the comparer for the sort function.
For those who are interested, here follow the code for the comparer method:
TTProdComparer = class(TComparer<TTPRODData>)
public
function Compare(const Item1, Item2: TTPRODData): Integer; override;
end;
And the code :
{ TTProdComparer }
function TTProdComparer.Compare(const Item1, Item2: TTPRODData): Integer;
begin
Result := CompareStr(Item1.FData1 , Item2.FData1 );
end;

The documentation that you have linked to is for the generic container TObjectList<T> from the Generics.Collections unit.
But the class that you have used in your code is the legacy non-generic container TObjectList from the Contnrs unit.
The BinarySearch method that you are trying to use only exists on the generic class.
If you switch to the generic container then you'll find that you can remove most of the boiler-plate code from your class. It becomes:
TTPRODDataList = class(TObjectList<TTPRODData>)
public
procedure SortOnProductCode;
end;
You don't need GetItem, SetItem and Items because the type-safe generic class already has that functionality sorted.
The only work you have to do is to adapt your sorting code to fit with the somewhat different interface used by the Delphi generic containers.

Related

Creating XML document with IXMLNodes

Hy! I want to add IXMLNodes to an XML document. My main procedure is btnXmlSaveToFileClick which Saves XML structure to a file. My problem is I cannot add IXMLNode as a child. Sorry for my English.
Any help or advice would be greatly appreciated.
Here is my example:
*
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
XMLDoc, XMLIntf, Vcl.StdCtrls;
type
IXMLDataSample1 = interface(IXMLNode)
['{D7B7E084-1BF8-4185-85D1-1C83B74EA651}']
function GetXmlDAtaSample1: WideString;
procedure SetXmlDAtaSample1(const Value: WideString);
property XmlDataSample1: WideString read GetXmlDataSample1 write SetXmlDataSample1;
end;
IXMLDataSample2 = interface(IXMLNode)
['{6D7CE38B-3F57-4F18-A337-8405E72637E6}']
function GetXmlDataSample2: WideString;
procedure SetXmlDataSample2(const Value: WideString);
property XmlDataSample2: WideString read GetXmlDataSample2 write SetXmlDataSample2;
end;
TXMLHandler<IXMLType: IXMLNode> = class
private
class function ConvertXMLNodeToXMLType(aNode: IXMLNode): IXMLType;
protected
class function GetXMLClass: TClass; virtual; abstract;
class function GetXMLRootElementName: WideString; virtual; abstract;
class function GetXMLIfType: TGUID; virtual; abstract;
class procedure SaveXMLToFile(aXML: IXMLType; const aFileName: string);
class function NewXML: IXMLType; virtual;
end;
TDataSampleXMLHandler1 = class(TXMLHandler<IXMLDataSample1>)
public
class function GetXMLClass: TClass; override;
class function GetXMLRootElementName: WideString; override;
class function GetXMLIfType: TGUID; override;
end;
TDataSampleXMLHandler12 = class(TXMLHandler<IXMLDataSample2>)
protected
class function GetXMLClass: TClass; override;
class function GetXMLRootElementName: WideString; override;
class function GetXMLIfType: TGUID; override;
end;
TForm3 = class(TForm)
btnXmlSaveToFile: TButton;
procedure btnXmlSaveToFileClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
type
TXMLSampleDataObj1 = class(TXMLNode, IXMLDataSample1)
private
function GetXmlDataSample1: WideString;
procedure SetXmlDataSample1(const Value: WideString);
end;
TXMLSampleDataObj2 = class(TXMLNode, IXMLDataSample2)
private
function GetXMlDataSample2: WideString;
procedure SetXmlDAtaSample2(const Value: WideString);
end;
procedure TForm3.btnXmlSaveToFileClick(Sender: TObject);
//Works well
vXML1 := TDataSampleXMLHandler1.NewXML;
vXML1.XmlDataSample1 := 'test data';
TDataSampleXMLHandler1.SaveXMLToFile(vXml1, 'C:\Teszt\XmlSample.XML');
//My problem here, cannot add IXMLNode to XMLDocument
vXMLDoc := NewXMLDocument;
vXMLDoc.ChildNodes.Add(vXML1);
//And add vXML2 and more...
vXMLDoc.SaveToFile('C:\Teszt\XmlDocSaveSAmple.XML');
end;
{ TXMLHandler<IXMLType> }
class function TXMLHandler<IXMLType>.ConvertXMLNodeToXMLType(
aNode: IXMLNode): IXMLType;
begin
Result := default(IXMLType);
try
Supports(aNode, GetXMLIfType, result);
finally
aNode := nil;
end;
end;
class function TXMLHandler<IXMLType>.NewXML: IXMLType;
begin
Result :=
ConvertXMLNodeToXMLType(NewXMLDocument.GetDocBinding(GetXMLRootElementName, GetXMLClass, ''));
end;
class procedure TXMLHandler<IXMLType>.SaveXMLToFile(aXML: IXMLType;
const aFileName: string);
begin
aXML.OwnerDocument.SaveToFile(aFileName);
end;
{ TDataSampleXMLHandler12 }
class function TDataSampleXMLHandler12.GetXMLClass: TClass;
begin
Result := TXMLSampleDataObj2;
end;
class function TDataSampleXMLHandler12.GetXMLIfType: TGUID;
begin
Result := IXMLDataSample2;
end;
class function TDataSampleXMLHandler12.GetXMLRootElementName: WideString;
begin
Result := 'Sample2'
end;
{ TDataSampleXMLHandler1 }
class function TDataSampleXMLHandler1.GetXMLClass: TClass;
begin
Result := TXMLSampleDataObj1;
end;
class function TDataSampleXMLHandler1.GetXMLIfType: TGUID;
begin
Result := IXMLDataSample1;
end;
class function TDataSampleXMLHandler1.GetXMLRootElementName: WideString;
begin
Result := 'Sample2';
end;
{ TXMLSampleDataObj1 }
function TXMLSampleDataObj1.GetXmlDataSample1: WideString;
begin
Result := ChildNodes['XmlDataSample1'].Text;
end;
procedure TXMLSampleDataObj1.SetXmlDataSample1(const Value: WideString);
begin
ChildNodes['XmlDataSample1'].NodeValue := Value;
end;
{ TXMLSampleDataObj2 }
function TXMLSampleDataObj2.GetXMLDataSample2: WideString;
begin
Result := ChildNodes['XmlDataSample2'].Text;
end;
procedure TXMLSampleDataObj2.SetXmlDataSample2(const Value: WideString);
begin
ChildNodes['XmlDataSample2'].NodeValue := Value;
end;
end.*
Saving a single XML node to a document is working well. But I want to add these nodes to an XML document the application stoppes, got no error.
My problem here is:
procedure TForm3.btnXmlSaveToFileClick(Sender: TObject);
//Works well
vXML1 := TDataSampleXMLHandler1.NewXML;
vXML1.XmlDataSample1 := 'test data';
TDataSampleXMLHandler1.SaveXMLToFile(vXml1, 'C:\Teszt\XmlSample.XML');
//My problem here, cannot add IXMLNode to XMLDocument
vXMLDoc := NewXMLDocument;
vXMLDoc.ChildNodes.Add(vXML1);
//And add vXML2 and more...
vXMLDoc.SaveToFile('C:\Teszt\XmlDocSaveSAmple.XML');
end;
My finally XML what I want to looks like:
<?xml version="1.0"?>
<Sample2>
<XmlDataSample2>test data</XmlDataSample2>
</Sample2>
<Sample1>
<XmlDataSample1>test data</XmlDataSample1>
</Sample1>
The XML standard allows only 1 top-level element in a document. You are going to have to make your <Sample... > elements be children of another top-level element, eg:
<?xml version="1.0"?>
<Samples>
<Sample2>
<XmlDataSample2>test data</XmlDataSample2>
</Sample2>
<Sample1>
<XmlDataSample1>test data</XmlDataSample1>
</Sample1>
</Samples>
procedure TForm3.btnXmlSaveToFileClick(Sender: TObject);
var
vXMLDoc: IXMLDocument;
vXML1: IXMLDataSample1;
vXMLSamples: IXMLNode;
begin
vXML1 := TDataSampleXMLHandler1.NewXML;
vXML1.XmlDataSample1 := 'test data';
vXMLDoc := NewXMLDocument;
vXMLSamples := vXMLDoc.AddChild('Samples');
vXMLSamples.ChildNodes.Add(vXML1);
//And add vXML2 and more...
vXMLDoc.SaveToFile('C:\Teszt\XmlDocSaveSample.XML');
end;

Reference counted object within a record not destroyed when record goes out of scope

I have a record that contains what I believe is a pointer to a reference counted object. I would expect that if I create the reference counted object within the record that when the record goes out of scope the reference count of the object would fall to zero, and the object would be destroyed. But this does not seem to be that case. Here is sample minimum code. My form happens to have some panels and a memo, but only the TButton (and specifically Button1Click) is important.
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TUserData = class( TInterfacedObject )
public
AData : integer;
constructor Create;
destructor Destroy; override;
end;
TTestRec = Record
AField : integer;
UserData : TUserData;
End;
TForm4 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Memo1: TMemo;
Button1: TButton;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.Button1Click(Sender: TObject);
var
iRec : TTestRec;
begin
iRec.UserData := TUserData.Create;
// stop too much optimisation
Button1.Caption := IntToStr( iRec.UserData.AData );
end; // I would expect TTestRec and hence TTestRec.UserData to go out of scope here
procedure TForm4.FormShow(Sender: TObject);
begin
// show leaks on exit
ReportMemoryLeaksOnShutdown := TRUE;
end;
{ TUserData }
constructor TUserData.Create;
begin
inherited Create;
AData := 4;
end;
destructor TUserData.Destroy;
begin
inherited;
end;
end.
I confess I don't really understand how reference counting works in detail, although I do understand the principle. What am I missing? Am I expecting too much and if so, is there any way to avoid memory leaks, not in this specific case (where obviously I could destroy UserData on exit) but in general, since records do not support destructors.
Automatic reference counting is performed through interface variables. You don't have any. Instead of a variable of type TUserData you need a variable that is an interface.
You could use IInterface here but that would be a little useless. So you should define an interface that exposes the public functionality you need the object to support and then have your class implement that interface.
This program demonstrates what I mean:
type
IUserData = interface
['{BA2B50F5-9151-4F84-94C8-6043464EC059}']
function GetData: Integer;
procedure SetData(Value: Integer);
property Data: Integer read GetData write SetData;
end;
TUserData = class(TInterfacedObject, IUserData)
private
FData: Integer;
function GetData: Integer;
procedure SetData(Value: Integer);
end;
function TUserData.GetData: Integer;
begin
Result := FData;
end;
procedure TUserData.SetData(Value: Integer);
begin
FData := Value;
end;
type
TTestRec = record
UserData: IUserData;
end;
procedure Main;
var
iRec: TTestRec;
begin
iRec.UserData := TUserData.Create;
end;
begin
Main;
ReportMemoryLeaksOnShutdown := True;
end.
This program does not leak. Change the variable declaration in the record type to UserData: TUserData and the leak returns.

Dynamically assigning anonymous generic functions in pascal

I have the following class hierarchy
I would like to be able to dynamically assign anonymous methods which operate on objects of both types TB and TC.
So here is a simple contrived example:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TNotifyEventWrapper = class
private
FProc: TProc<TObject>;
public
constructor Create(Proc: TProc<TObject>);
published
procedure Event(Sender: TObject);
end;
IA = interface
procedure Foo;
end;
TA = class(TInterfacedObject)
procedure Foo;
end;
TB = class(TA, IA)
procedure Foo;
end;
TC = class(TA, IA)
procedure Foo;
end;
TControl = class
strict private
public
class var NEW : TNotifyEventWrapper;
class var Foo : TNotifyEvent;
class function GetWrapper<T:TA, IA, constructor>(D: T): TNotifyEventWrapper;
class procedure AssignFooHandler<T:TA, IA, constructor>;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TC.Foo;
begin
ShowMessage('TC.Foo');
end;
class function TControl.GetWrapper<T>(D: T): TNotifyEventWrapper;
begin
Result :=
TNotifyEventWrapper.Create
(
procedure (S : TObject)
begin
T(D).Foo;
end
);
end;
class procedure TControl.AssignFooHandler<T>;
var
X : T;
begin
X := T.Create;
try
TControl.NEW := TControl.GetWrapper<T>(X);
TControl.Foo := TControl.NEW.Event;
finally
FreeAndNil(X);
end;
end;
procedure TA.Foo;
begin
ShowMessage('TA.Foo');
end;
procedure TB.Foo;
begin
ShowMessage('TB.Foo');
end;
constructor TNotifyEventWrapper.Create(Proc: TProc<TObject>);
begin
inherited Create;
FProc := Proc;
end;
procedure TNotifyEventWrapper.Event(Sender: TObject);
begin
FProc(Sender);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
TControl.Foo(Sender);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
TControl.AssignFooHandler<TC>; //TB
end;
end.
I would like to be able to call
TControl.AssignFooHandler<TC>;
And have the TControl.Foo(Sender); method invoke TC.Foo
Also I want TControl.AssignFooHandler<TB>; to result in TControl.Foo(Sender); invoking TB.Foo
Unfortunately, when I run this, it always invokes the base class method TA.Foo.
I'm not sure how to get around this.
Your Generic is constrained to descendants of TA and IA. TA.Foo is not declared as virtual, and T(B|C).Foo() are not declared to override it. That is why TA.Foo() is being called every time. You need to make TA.Foo() virtual and T(B|C).Foo override it, then T(B/C).Foo will get called as expected.
Also, you are freeing the T(A/B/C) object that you are passing to TControl.GetWrapper() before TControl.Foo() ever gets a chance to invoke the Foo() method of that object. In this particular example, it is OK since none of the Foo() methods access any object member fields, but once you start doing that in actual production code, it is likely to crash. You need to keep the T(A/B/C) object alive until you are done using the TNotifyEventWrapper object.

generic compare function for 2 class types

here come my definition of Vertex class and graph class using generic programming features of Delphi :
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
System.Math, System.Generics.Collections,
System.Generics.Defaults, Vcl.StdCtrls;
type
tvertex = class(TObject)
name: string;
function markme: tvertex;
function Compare(const v: TVertex): Integer;
constructor create;
destructor free;
end;
tvertex<T> = class(tvertex)
Userdata: T;
end;
TGraph <T : class > = class (Tobject)
vertexlist : TObjectList<T>;
procedure CompareLists(
var _V1: TObjectList<T>;
var _V2: TObjectList<T>);
end;
TForm1 = class(TForm)
Edit1: TEdit;
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
// helper function
function createVertexComparer(): IComparer <TVertex >;
implementation
// helper functions
function createVertexComparer(): IComparer<TVertex>;
begin
Result := TDelegatedComparer<TVertex>.Create(
function(const Left, Right: TVertex): Integer
begin
Result := Left.Compare(Right);
end);
end;
{$R *.dfm}
{ tvertex }
function tvertex.Compare(const v: TVertex): Integer;
begin
// ...
end;
constructor tvertex.create;
begin
// ...
end;
destructor tvertex.free;
begin
// ...
end;
function tvertex.markme: tvertex;
begin
// ...
end;
procedure TGraph<T>.CompareLists(
var _V1: TObjectList<T>;
var _V2: TObjectList<T>);
begin
_V1 := TObjectList<T>.Create(createVertexComparer(), False); /// line which does not compile ....
end;
end.
How to modify the code that he is willing to accept TVertex and TVertex<T> class types as arguments ....
I would say that the main problem that you have is that you declared the graph class like this:
type
TGraph<T: class>
...
end;
And this means that the compiler will accept any class as T. Consequently the graph class knows nothing about T, beyond that it is a class.
It's hard to be sure, but I think that you intend T to be a vertex. So you need to constraint the graph class appropriately.
type
TGraph<T: TVertex>
...
end;
And then you have another problem with this function:
function createVertexComparer(): IComparer<TVertex>;
You pass the result of that to
TObjectList<T>.Create
But that expects a parameter of type IComparer<T> and you are supplying IComparer<TVertex>. That's the type mismatch that the compiler reports.
You'll need to make createVertexComparer be a method of TGraph<T> so that it can be generic. Its implementation would be:
function TGraph<T>.createVertexComparer(): IComparer<T>;
begin
Result := TDelegatedComparer<T>.Create(
function(const Left, Right: T): Integer
begin
Result := Left.Compare(Right);
end);
end;
Also, do note that
destructor free;
is a disaster waiting to happen. You must use
destructor Destroy; override;
In fact, the rest of your code troubles me. For instance:
procedure TGraph<T>.CompareLists(var _V1, _V2: TObjectList<T>);
begin
_V1 := TObjectList<T>.Create(createVertexComparer(), False);
end;
The method's name does not match what it does. It only returns one value, so why have two var parameters? It's very hard to discern intent when viewing code like this.

Delphi Class Parameter

I am trying to compose my own ThreadManager unit in Delphi and I have this so far:
unit uThreadManager;
interface
uses
Classes,
Windows;
type
TCustomTThread = class (TThread)
public
TaskData : Pointer;
end;
type
TWorkerThread = class(TObject)
private
TaskDataList : TList;
TaskDataListCrit : TRTLCriticalSection;
function ReadTotalTasks : Integer;
public
constructor Create;
destructor Destroy; override;
property TotalTasks : Integer read ReadTotalTasks;
function AddTask(Thread: TCustomTThread; Data: Pointer) : Integer;
procedure Delete (Index : Integer);
end;
implementation
type
PTaskData = ^TTaskData;
TTaskData = record
Thread : TCustomTThread;
TaskPointer : Pointer;
end;
procedure TWorkerThread.Delete(Index: Integer);
var
TaskData : PTaskData;
begin
EnterCriticalSection(TaskDataListCrit);
TaskData := TaskDataList.Items[Index];
TaskDataList.Delete(Index);
LeaveCriticalSection(TaskDataListCrit);
TaskData^.Thread.Free;
Dispose(TaskData);
end;
function TWorkerThread.ReadTotalTasks;
begin
EnterCriticalSection(TaskDataListCrit);
result := TaskDataList.Count;
LeaveCriticalSection(TaskDataListCrit);
end;
destructor TWorkerThread.Destroy;
begin
DeleteCriticalSection(TaskDataListCrit);
TaskDataList.Free;
inherited;
end;
constructor TWorkerThread.Create;
begin
inherited;
InitializeCriticalSection(TaskDataListCrit);
TaskDataList := TList.Create;
end;
function TWorkerThread.AddTask(Thread: TCustomTThread; Data: Pointer) : Integer;
var
NewTask : PTaskData;
begin
EnterCriticalSection(TaskDataListCrit);
New(NewTask);
// I would like to create a new instance of TCustomTThread here!
//NewTask^.Thread := ...
NewTask^.TaskPointer := Data;
result := TaskDataList.Add (NewTask);
LeaveCriticalSection(TaskDataListCrit);
end;
end.
I came across the problem with the parameter from my AddTask procedure...
Here is an example on what I am trying to do:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uThreadManager;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
type
TTheCustomThread = class (TCustomTThread)
public
procedure Execute; override;
end;
implementation
{$R *.dfm}
procedure TTheCustomThread.Execute;
begin
// My Code
end;
procedure TForm2.Button1Click(Sender: TObject);
var
NewWorkerThread : TWorkerThread;
begin
NewWorkerThread := TWorkerThread.Create;
NewWorkerThread.AddTask(TTheCustomThread, NIL);
end;
end.
this code gives me the error:
[dcc32 Error] Unit2.pas(42): E2010 Incompatible types:
'TCustomTThread' and 'class of TTheCustomThread'
I could fix this by declaring a new TTheCustomThread var in the stack but I would like to avoid this cause I won't need it at all later and AddTask will create a new instance of TTheCustomThread. I could use TClass and then typecast to TCustomThread but I was wondering if there's anything else to make this work.
Thank you for your help.
Your function AddTask is defined as so:
function AddTask(Thread: TCustomTThread; Data: Pointer) : Integer;
The first parameter that you pass is of type TCustomTThread. That is an instance of TCustomTThread.
You call the function like this:
AddTask(TTheCustomThread, nil);
Here you pass the class rather than an instance. Hence the compiler error.
Now, it seems that what you want to do is pass the class. Inside AddTask you wish to receive a class and then create a new instance. Declare a class type like so:
type
TTheCustomThreadClass = class of TTheCustomThread;
Change AddTask to receive that type:
function AddTask(ThreadClass: TCustomTThreadClass; Data: Pointer) : Integer;
And inside the implementation, create an instance like this:
NewTask^.Thread := ThreadClass.Create;
Very likely you will want to declare the constructor of TTheCustomThread to be virtual to allow derived classes the freedom to define constructors that can be executed from your factory creation mechanism.

Resources