Why use an interface?
Here's an example: there's aTicket sales Service, the cinema can sell tickets, the Opera House can sell tickets, the bus terminal can also sell tickets, then whether we need to the cinema, Opera House and bus terminal aredesigned as a class architecture to provide ticket selling services? You know, even the manager can sell tickets, obviously not suitable for the manager to includeinheritance structure of ticket selling service, all we need is aCommon selling ticket service。 SoThe ticket service is an interface., cinemas, opera houses, whatever.Follow such a service definitionwill be able to interact and communicate with each other well (if needed).
How to use Interfaces in Delphi
1. Declaration Interface
IMyInterface = Interface (iinterface)//Instructions (1)
[' {63e072df-b81e-4734-b3cb-3c23c7fda8ea} ']//Instructions (2)
function GetName (const str:string): String; stdcall;
function QueryInterface (const IID:TGUID; out OBJ): HResult; stdcall; //Instructions (3)
function _addref:integer; stdcall; Adds 1 to the number of interface references.
function _release:integer; The stdcall;//causes the interface reference number to be reduced by 1, and the release action when it is less than or equal to 0.
End
Instructions (1): If there is an inheritance relationship, the parent interface is filled in parentheses, otherwise it is omitted, such as: IMyInterface = interface this is OK.
Instructions (2): thisGUIDOptional, if you want toImplementing a COM attributeinterface, you need to add, Delphi in the interface with the GUID at run time in the VMT table at the predetermined location to generate the interface information, such as the definition of interface methods, method parameter definition details.
Instructions (3): An interface must implement these three functions.
2, the implementation of the interface
the interface service is implemented by the class.
Tintfclass = Class (TObject, IMyInterface)
Private
Fcounter:integer;
Frefcount:integer;
Public
function QueryInterface (const IID:TGUID; out OBJ): HResult; stdcall;
...
End
3. Get the interface
A. Use type conversions. Such as:
var aintf:imyinterface;
Begin
Aobj: = tintfclass.create;
Try
aintf: = (IMyInterface (aobj);
...
B. Use the Delphi compiler built-in mechanism. such as: aintf: = Aobj.
C. Use the QueryInterface method of the object. such as Olecheck (Aobj.queryinterface (IID, aintf)); Only COM interfaces with GUIDs can be accessed.
D. Use the AS operator.
The following conditions must be met with the as operator:
1. The interface must be explicitly specified to be inherited from the IInterface interface.
2. Must have a GUID value
In the Delphi7implementation class of the interfacemust also beinherit from TinterfacedobjectDown, like:
Tintfclass = Class (Tinterfacedobject, IMyInterface)
4. Interface and Object lifetime
Because Delphi will check the interface itself, if it is not released after use, add the release code in the generated program, but also because of this problem, such as the following code:
Var
I:integer;
Aobj:tintfclass;
Aintf:imyinterface;
Begin
Aobj: = tintfclass.create;
Try
aintf: = Aobj;
Aintf.getname ...
Finally
aintf: = nil;
Freeandnil (Aobj);
End
The above code would generate an access violation error because the interface was disposed when nil was placed on the interface, and Freeandnil (aobj) would release aintf once, while the aintf
Nil when the object has been disposed. Solve this problem as long asdon't let the interface interfere with the life of the objectYes, inonly subtract reference count in releaseWithout doing the act of releasing.
function Tintfclass._release:integer;
Begin
Result: = InterlockedDecrement (Frefcount);
End
5, the interface of the delegation (Interface delegation)
are divided into two types:
1. Object Interface Delegation
2. Class object Delegate.
. Object interface delegate, assuming that the following interface definition is available:
Iimplinterface = Interface (iinterface)
function CONVERTTOUSD (const intd:integer): Double;
function CONVERTTORMB (const intd:integer): Double;
End
Then there is a class that implements the interface:
Timplclass = Class (TObject, Iimplinterface)
Private
Frefcount:integer;
Public
function CONVERTTOUSD (const intd:integer): Double;
...
End
Implementation
function timplclass.queryinterface (const IID:TGUID; out OBJ): HResult;
Begin
If GetInterface (IID, OBJ) Then
Result: = 0
Else
Result: = E_nointerface;
End
function Timplclass._release:integer;
Begin
Result: = InterlockedDecrement (Frefcount);
If Result = 0 Then
Destroy;
End
... ...
Now there is another class Tintfserviceclass to implement the Iimplinterface interface, without redefining it, just use the timplclass above to:
Tintfserviceclass = Class (TObject, Iimplinterface)
Private
Fimplservice:iimplinterface;
Fsrvobj:timplclass; If you're delegating with a class object,
Public
Constructor Create; overload;
destructor Destroy; Override
Constructor Create (Aclass:tclass); overload;
Property Myservice:iimplinterface read Fimplservice implements Iimplinterface;
Property Myservice:timplclass read Fsrvobj implements Iimplinterface; If you delegate with an object.
End
The implementation is as follows:
Constructor Tintfserviceclass.create;
Begin
Fimplservice: = timplclass.create;
End
Constructor Tintfserviceclass.create (Aclass:tclass);
Var
Instance:timplclass;
Begin
Instance: = Timplclass (aclass.newinstance);
Fimplservice: = instance. Create;
End
destructor Tintfserviceclass.destroy;
Begin
Fimplservice: = nil; Follow Timplclass use reference counting to control the object life cycle and see the destroy implementation of Timplclass.
inherited;
End
6. Interface and Rtti
In Delphi, the interface Gog pointer is defined at the VMT-72 Displacement: vmtintftable =-72.
Related functions:
Getinterfacecount; Gets the number of interfaces.
getinterfacetable; Gets the interface table.
Related structure:
Tinterfaceentry = Packed record
Iid:tguid;
Vtable:pointer;
Ioffset:integer;
Implgetter:integer;
End
pinterfacetable = ^tinterfacetable;
tinterfacetable = Packed record
Entrycount:integer;
ENTRIES:ARRAY[0..9999] of Tinterfaceentry;
End
Self is a pointer to the VMT pointer, so: Self.GetInterfaceTable.EntryCount is equivalent to:
Aptr: = Ppointer (Integeer (Pointer (self) ^) + vmtintftable) ^;
Simply use the m+/m-directive in the Declaration to add RTTI information to the program compiled in Delphi, such as:
{$M +}
Iinvokable = Interface (iinterface)
{$M-}
The RTTI information for an interface is defined by the TINTFMETADATA record structure:
Tintfmetadata = Record
name:string; Interface Name
unitname:string; The name of the program unit for the interface declaration
Mda:tintfmethentryarray; Dynamic array of method information in the storage interface
Iid:tguid; The GUID value of the interface
Info:ptypeinfo; A pointer describing the interface information
Ancinfo:ptypeinfo; A pointer that describes the parent information
Numanc:integer; The number of methods that this interface inherits from the parent interface
End
Tintfmethentryarray is defined as follows:
Type
Tcallconv = (Ccreg, cccdecl, ccpascal, Ccstdcall, Ccsafecall);
Tintfmethentry = Record
name:string; Method name
Cc:tcallconv; Invoke conventions
Pos:integer; Location of the method in the interface
Paramcount:integer; Number of parameters for the method
Resultinfo:ptypeinfo; Information pointer describing the method callback type
Selfinfo:ptypeinfo; Information pointers that describe the method itself
Params:tintfparamentryarray; Dynamic array describing the parameter information
Hasrtti:boolean; Whether this method has a Boolean value for Rtti information
End
Tintfmethentryarray = array of tintfmethentry;
Parameter information tintfparamentry definition:
Tintfparamentry = Record
Flags:tparamflags;
name:string;
Info:ptypeinfo;
End
Ttypeinfo = Record
Kind:ttypekind; Data type
name:shortstring; string format for type information
End
Introduction to Delphi-based interface programming