Hope someone can help, I've trawled these pages and nothing so far works, very simple at this stage, a few lines trying to initialise the HIKVision camera by calling NET_DVR_Init, the call when creating the form to 'NET_DVR_Init'returns an error message.
All DLLs are in the same folder as the EXE so paths should not be an issue.
Using LoadLibrary only works on some DLLs, assuming dependence on other DLLs would be the cause of failure but with all HIK DLLs in the same folder surely this should not be the case ?
unit PTZFrm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms;
type
TPTZ_Test = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function NET_DVR_Init(): boolean; stdcall; external 'HCNetSDK.dll' name 'NET_DVR_Init';
var PTZ_Test : TPTZ_Test;
implementation
{$R *.dfm}
procedure TPTZ_Test.FormCreate(Sender: TObject);
begin
NET_DVR_Init();
end;
end.
Related
I am having a hard time implementing multi-tier inheritance from the basic TThread class.
Based on my knowledge of OOP it should be possible but maybe it just can't be applied to threads.
My goal is to use TMyBaseThread to implement all the code that will be common to descendent classes. This is what I have have tried:
TMyBaseThread = class(TThread)
private
procedure BuildBaseObjects(aParam : TParam);
procedure Execute; virtual; abstract;
protected
constructor Create(Param : TParam); reintroduce; virtual;
end;
TMyFileThread = class(TMyBaseThread)
private
procedure Execute; reintroduce;
public
constructor Create(OtherParam : TOtherParam); reintroduce; overload;
end;
TMyDBThread = class(TMyBaseThread)
private
procedure Execute; reintroduce;
public
constructor Create(aDB : TDatabase); reintroduce; overload;
end;
implementation
constructor TMyBaseThread.Create(Param : TParam);
begin
inherited Create(False);
Self.BuildBaseObjects(Param);
[do some stuff]
end;
constructor TMyFileThread.Create(OtherParam : TOtherParam);
var
param : TParam;
begin
inherited Create(param);
[do some other stuff]
end;
procedure TMyFileThread.Execute;
begin
while not Terminated do
doWork(); <-- this is never called
end;
constructor TMyDBThread.Create(aDB : TDatabase);
var
param : TParam;
begin
inherited Create(param);
end;
procedure TMyDBThread.Execute;
begin
while not Terminated do
doDatabaseWork(); <-- this is never called
end;
I see in TThread's implementation that the Executed method is called automatically in the AfterConstruction but how can I have it point to the one declared in the derived classes?
Thanks!
First, I can't support more Craig's comment about using composition instead of inheritance for implementing the common functionality.
And although the architecture choice is under question, there is a lot to learn from your example.
Before inheriting a class, you should investigate the interface of the parent class that you want to inherit. To do that you can either look for the class definition in the interface section of the source code or look up the relevant documentation - System.Classes.TThread.
It seems you have already read the documentation, so let's take a look at an except from the class definition of TThread:
TThread = class
private
...
protected
procedure CheckThreadError(ErrCode: Integer); overload;
procedure CheckThreadError(Success: Boolean); overload;
procedure DoTerminate; virtual;
procedure Execute; virtual; abstract;
procedure Queue(AMethod: TThreadMethod); overload;
procedure Synchronize(AMethod: TThreadMethod); overload;
property ReturnValue: Integer read FReturnValue write FReturnValue;
property Terminated: Boolean read FTerminated;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure AfterConstruction; override;
procedure Resume;
procedure Suspend;
procedure Terminate;
function WaitFor: LongWord;
class procedure Queue(AThread: TThread; AMethod: TThreadMethod); overload;
class procedure RemoveQueuedEvents(AThread: TThread; AMethod: TThreadMethod);
class procedure StaticQueue(AThread: TThread; AMethod: TThreadMethod);
class procedure Synchronize(AThread: TThread; AMethod: TThreadMethod); overload;
class procedure StaticSynchronize(AThread: TThread; AMethod: TThreadMethod);
property FatalException: TObject read FFatalException;
property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
property Handle: THandle read FHandle;
property Priority: TThreadPriority read GetPriority write SetPriority;
property Suspended: Boolean read FSuspended write SetSuspended;
property ThreadID: THandle read FThreadID;
property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
end;
First, ignore anything that is in the private section of the class. If those fields and methods were marked as private, we are not supposed to be able to use them at all in descendant classes.
Then, look for any abstract methods. The implementation of abstract methods is left for descendant classes. So those are the methods you are expected to implement in your code. Abstract methods are usually called indirectly by using one of the methods from the parent class.
In your case the TThread class has only one abstract method:
procedure Execute; virtual; abstract;
The documentation says that you need to
Define the thread object's Execute method by inserting the code that
should execute when the thread is executed.
It's true that the documentation sounds a bit vague, but the right way to do that is to "override" the method in the interface, and not to "reintroduce" it:
TMyFileThread = class(TMyBaseThread)
...
protected
procedure Execute; override;
...
and then implement it in the implementation:
procedure TMyFileThread.Execute;
begin
while not Terminated do
Sleep(1); // do some other stuff
end;
You probably notice how we declared the overrided definition of Execute method in the protected section. This is required as the definition of the method in the parent class is also in the protected section, so we can only override it in a section with higher visibility (protected or public).
You rarely need to increase the visibility when overriding a method, so we just keep the same visibility.
We used the override keyword to tell the base class to use this variant of the method instead of its own. If you miss the override keyword the Execute method will not be called at all, and the base class will try calling it's own Execute method, if there is any.
Another thing to note is that you don't need to redeclare the Execute method in your base class as you are not implementing it there. That's why you should remove the following definition:
TMyBaseThread = class(TThread)
...
//procedure Execute; virtual; abstract; <- remove this
...
The execute method is already defined in the TThread class.
Now, let's look at the constructors. The base class has a regular constructor that is neither virtual, nor dynamic:
public
constructor Create(CreateSuspended: Boolean);
This means you cannot override those constructors and if you want to add additional logic on object creation, you should create your own constructors that wrap those.
The proper way to do that is to just declare a constructor with a different set of parameters, without reintroducing, overloading or overriding the base one:
public
//constructor Create(Param : TParam); reintroduce; virtual;
constructor Create(Param : TParam);
Also, remember that constructors should almost always be in the public section.
You also don't need to make the constructor virtual. You could do that if your TMyFileThread and TMyDBThread classes needed to add some logic inside the constructor, without changing the constructor parameters.
When you change the set of parameters all that is required is that you call the inherited constructor as first thing inside the new one:
constructor TMyFileThread.Create(OtherParam : TOtherParam);
var
param : TParam;
begin
inherited Create(param); // It is enough to call the base constructor at the top
// do some other stuff
end;
The definition requires no keywords:
TMyFileThread = class(TMyBaseThread)
...
public
constructor Create(OtherParam : TOtherParam);
Did you notice how we used inherited Create(param) to call the base constructor, but we did not use inherited Execute;? That's because the Execute method was marked as abstract and have no default implementation in the base class. Using inherited on an abstract method would cause an exception as there is no default method to call.
As a general rule calling inherited Create is a must if the base constructor you are calling is marked as virtual, but is almost always required even if it is not marked so.
Finally, I want to formulate a summary of the relevant keywords and their most common use:
virtual - declare a method that can be reimplemented in descendant classes. That is descendant classes can change the behaviour of the method. They can replace all the code inside it with their own, or can both call the base method and then add additional behaviour before/after that. This keyword is used only in the base class that defines the method for the first time. Descendant classes use the other keywords.
dynamic - consider it the same as virtual. Can save some memory resources, but only if the method is not reimplemented in all descendant classes and there are many objects created from such classes. Rarely used.
override - declare a method that reimplements the base class by providing code that replaces the default one in the base class. You use override in descendant classes. You can use the inherited keyword inside your implementation to call the base method.
overload - You declare an alternative variant of the method with another set of parameters. Note that overloading a method has nothing to do with inheritance. An overloaded version of the method is not executed when the base class is calling the original method. Usually overloaded methods normalize the parameters (converting them to other types, adding default values for some parameters) and then call one of the other overloaded methods. Again, this has nothing to do with inheritance and the virtual, override keywords. Although sometimes you can combine both effects.
reintroduce - This again is not inheritance. You use this keyword in descendant classes. The purpose is to make calls to the method from inside your class (and only calls from your class, not calls from the base class) to execute that reintroduced version of the method instead of the base one. Calls from the base class still execute the original version. Rarely used.
Having said that, here is my interpretation of your code:
interface
uses
Classes, SysUtils;
type
TParam = class
end;
TOtherParam = class
end;
TDatabase = class
end;
TMyBaseThread = class(TThread)
private
procedure BuildBaseObjects(aParam : TParam);
protected
public
constructor Create(Param : TParam);
end;
TMyFileThread = class(TMyBaseThread)
private
protected
procedure Execute; override;
public
constructor Create(OtherParam : TOtherParam);
end;
TMyDBThread = class(TMyBaseThread)
private
protected
procedure Execute; override;
public
constructor Create(aDB : TDatabase);
end;
implementation
{ TMyBaseThread }
constructor TMyBaseThread.Create(Param : TParam);
begin
inherited Create(False);
Self.BuildBaseObjects(Param);
// Do some stuff
end;
procedure TMyBaseThread.BuildBaseObjects(aParam : TParam);
begin
// Do some stuff
end;
{ TMyFileThread }
constructor TMyFileThread.Create(OtherParam : TOtherParam);
var
param : TParam;
begin
inherited Create(param); // Remember to initialize param somehow
// Do some other stuff
end;
procedure TMyFileThread.Execute;
begin
while not Terminated do
Sleep(1);
end;
{ TMyDBThread }
constructor TMyDBThread.Create(aDB : TDatabase);
var
param : TParam;
begin
inherited Create(param); // Remember to initialize param somehow
end;
procedure TMyDBThread.Execute;
begin
while not Terminated do
Sleep(1);
end;
PS. Actually using inheritance on TThread is mostly useful for plugin architectures or task workers. You can look up for examples on that.
I created a component, in which I use threads, something like this:
type
TEvent = procedure(sender:TObject) of object;
TMyComponent = class(TComponent)
protected
Fvar:String;
FMyEvent:TEvent;
public
Constructor Create(AOwner:TComponent);override;
published
property MyProperty:String read Fvar write Fvar;
property Event:TEvent read FMyEvent write FMyEvent;
end;
TMyThread = class(TThread)
procedure Execute; override;
end;
implementation
procedure TMyThread.Execute;
begin
if assigned (FMyEvent) then
FMyEvent(Self);
end;
As you can see, I'm accessing to FMyEvent which is a private variable, from another class, so this generates a compilation error (Undeclared Identifier),I know its illogic to access to private variable from another class but I REALLY need to use this! I need that event to happen when TMyThread is executed.
I tried this code:
type
TEvent = procedure(sender:TObject) of object;
TMyComponent = class(TComponent)
protected
Fvar:String;
FMyEvent:TEvent;
public
Constructor Create(AOwner:TComponent);override;
published
property MyProperty:String read Fvar write Fvar;
property Event:TEvent read FMyEvent write FMyEvent;
end;
TMyThread = class(TThread)
private
fev:TEvent;
protected
procedure Execute; override;
public
constructor Create(afev:TEvent);
end;
implementation
procedure TMyThread.Create(afev:TEvent);//when i call this one i send the real Event of the component.
begin
fev:=afev;
if assigned (FMyEvent) then
FMyEvent(Self); // it works here
end;
procedure TMyThread.Execute;
begin
if assigned (FMyEvent) then
FMyEvent(Self); //IT doesn't work here
end;
As you can see, when I create the thread I send the properties of the component as parameters, I called the event in two different places, so when I call it in the constructor it works well,but when I call it in the execute procedure nothing happens!! however the condition: if assigned (FMyEvent) is true in both cases ( I tried some tests to check this one). I guess the problem is relevant to "Self" should I replace by another owner? Why does the event work only when I call it in the create procedure?
FMyEvent is not private, it's protected.
It's also published as Event so accessible.
You need an instance to access the published event.
The error Undeclared Identifier actually comes from point 3 and not from the visibility.
It rather should be something like
procedure TMyThread.Execute;
begin
if assigned (Instance.Event) then
Instance.Event(Self);
end;
Or you could create the thread with an event as parameter.
TMyThread = class(TThread)
private
FMyEvent: TEvent;
public
constructor construct(ev: TEvent);
procedure Execute; override;
end;
constructor TMyThread.construct(ev: TEvent);
begin
FMyEvent := ev;
end;
procedure TMyThread.Execute;
begin
if assigned (FMyEvent) then
FMyEvent(Self);
end;
i'm having a bit of a problem here. I have a custom class that inherits TPersistent class, inside(private section) this custom class, i have a custom made TThread with overriden Execute method which fires every (1000 ms). Everything works great, until i move my 2 custom classes to a new Unit...
type
TMyThread= class(TThread)
protected
procedure Execute; override;
end;
TMyClass = class(TPersistent)
private
T: TMyThread;
protected
constructor Create;
public
destructor Destroy; override;
end;
implementation
procedure TMyThread.Execute;
begin
while not Self.Terminated do begin
Sleep(1000);
MessageBox(0, 'test', nil, MB_OK)
end;
end;
constructor TMyClass.Create;
begin
inherited Create;
t := TMyThread.Create(False);
end;
destructor TMyClass.Destroy;
begin
t.Terminate;
t.WaitFor;
FreeAndNil(t);
inherited Destroy;
end;
The above code works great in the main project unit, but when i move it to a new unit, the thread code no longer works, i get an AV, when i try to free a TMyClass object. I think the thread is not being constructed at all, and that's why i get an AV when i try to free it... but why? it shouldn't matter in which Unit the code is...
Unit1:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, unit2;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button2Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
p: TMyClass;
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
begin
p.Free; //Getting an AV
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
p := TMyClass.Create;
end;
end.
Unit2:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TMyThread = class(TThread)
protected
procedure Execute; override;
end;
TMyClass = class(TPersistent)
private
T: TMyThread;
protected
constructor Create;
public
destructor Destroy; override;
end;
implementation
procedure TMyThread.Execute;
begin
while not Self.Terminated do begin
Sleep(1000);
MessageBox(0, 'test', nil, MB_OK)
end;
end;
constructor TMyClass.Create;
begin
inherited Create;
t := TMyThread.Create(False);
end;
destructor TMyClass.Destroy;
begin
t.Terminate;
t.WaitFor;
FreeAndNil(t);
inherited Destroy;
end;
end.
The constructor TMyClass.Create is declared protected. That means it is not visible from another unit. Hence TMyClass.Create is not executed and instead you are calling TObject.Create. In turn that means that the thread is never created and you encounter a runtime error when the destructor runs because T is nil.
Declare the constructor with public visibility.
My thread class is auto starting although the suspended property is set to true.
I have a base class which as an array of the thread class. Here is my class declaration.
Type
cSolution = Class(TThread)
Private
procedure FindLocalMinimum;
procedure AddWorker;
procedure RandomSortCompressors;
procedure FindBestNetwork;
Public
Network : cNetwork;
Workers : array of cWorker;
Compressors : array of cCompressorData;
IsAllWorkersDone : boolean;
ID : integer;
Procedure CreateWorkers;
Constructor Create; overload; // This constructor uses defaults
Constructor Create(aNetwork : cNetwork; aCompressors : array of cCompressorData); overload; // Copy constructor
Destructor Destroy; override; //Destructor
procedure Execute; override;
end;
implementation
/// <summary>Default constructer
/// </summary>
constructor cSolution.Create;
begin
inherited;
IsAllWorkersDone := false;
Suspended := true;
ID := 99;
end;
I added breakpoints to the place where I call the execute function, and at the beginning of the execute function. The place where I call it is never triggered. But the break point in the execute function itself is triggered. When it is triggered the suspended property is false.
Is there something I am missing or why is the thread auto starting when I don't want it to auto start.
You need to call inherited Create(True) in your constructor. This will avoid starting the thread.
Setting Suspended to True after calling inherited Create() will still result in starting the thread (Delphi has a couple of bugs in that area...)
{ using Visual Studio 2010 , Win7 }
class Base
{
public:
Base() : terminateCondition(false)
{
//spawn new thread and set entry point to newThreadFunc()
}
virtual ~Base() // edited to say it's virtual.
{
terminateCondition=true;
//wait for thread to join
}
virtual void vfunc() = 0;
static void __stdcall newThreadFunc(void *args)
{
while(!terminateCondition)
pThis->vfunc();
}
volatile bool terminateCondition;
};
class Derived : public Base
{
public:
virtual void vfunc()
{
//Do Something
}
};
Derived* dPtr=new Derived; //now assume pThis is dptr
//later somewhere
delete dPtr;
This code crashes saying pure virtual called. Moving terminateCondition=true to the destructor of Derived prevents this crash. I think i partially get why. Destruction is in reverse order of construction so d'tor of Derived is executed 1st and all functionalities of Derived are destroyed before calling upon the d'tor of Base. In the meantime if pThis->vfunc() is encountered the application would crash. It crashes saying pure virtual called. I could not understand this part. Can someone please explain?
Your Base class destructor needs to be virtual, Since it is not this code invokes Undefined Behavior.
Reference:
C++03 standard: Section 5.3.5/3:
If the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
When you call a virtual function through constructor/destructor the dynamic dispatch does not work as you expect it to.
The type of this in constructor/destructor is of the type of the class who's constructor/destructor is being executed. While you expect the dynamic dispatch to call overidden derived class method Derived::vfunc(), it ends up in a call to Base::vfunc() which does not have a definition and hence results in Undefined Behavior.
Reference:
C++03 Standard 10.4/6:
"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."
This happens because in your code vfunc can be invoked while Base::Base() isn't finished yet or Base::~Base() already started. Both of these cases will invoke undefined behavior, usually manifested as "pure virtual call" error.
Reason for it being an error is that the "virtual" mechanism doesn't kick in until after the constructor of most derived object's class started running, and the "virtual" mechanism is no longer in effect after the destructor of most derived object's class finished running. So when you make a call to a virtual function while a constructor or destructor is executing on the object, the corresponding function of the class of which the constructor or destructor is executing will be called. And if that function happens to be pure virtual, the behavior is undefined.
ISO/IEC 14882:2003, 10.4/6:
Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making
a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or
destroyed) from such a constructor (or destructor) is undefined.