Mega Code Archive

 
Categories / Delphi / System
 

DLL+

Title: DLL+ Question: Export an object-reference from a DLL is one approach to get real OO-access to a DLL. The DLL must create and return the object, so the client gets the methods without encapsulating. Let's see how this framework, called DLL+, works: Answer: There is also an example uploaded with UML-Diagrams (*.tif) from ModelMaker. We always work with MM since we had to redesign a big project. First, we have to built an abstract class in a separate unit (see below the same with a real interface). You might consider this unit like an interface: unit income1; interface type IIncome = class public function GetIncome(const aNetto: Currency): Currency; virtual; abstract; procedure SetRate(const aPercent, aYear: integer); virtual; abstract; function queryDLLInterface(var queryList: TStringList): TStringList; virtual; abstract; end; Second we built the DLL in a new unit (*.dpr) with the corresponding class, which has to implement the methods from the interface: type TIncomeReal = class(IIncome) private FRate: Real; public constructor Create; function GetIncome(const aNetto: Currency): Currency; override; procedure SetRate(const aPercent, aYear: integer); override; ... 3. And now comes the export, cause objects in DLL+ are created by calling a global Constructor function, you can see that returning objects from the function that creates them is acceptable by the client: {-------------------------------------------------------------} function CreateIncome: TIncomeReal; stdcall; begin result:= TIncomeReal.Create; end; exports CreateIncome resident; begin {fake} end. {-------------------------------------------------------------} 4. At last we take a look at the client. In managing objects the client consider who owns the object and is responsible for freeing it up: Uses income1; private IncomeRef: IIncome; //member ... function CreateIncome:IIncome; stdcall; external('income.dll'); ... procedure TfrmIncome.FormCreate(Sender: TObject); begin IncomeRef:=createIncome; end; 5. So the access is easy, stable and improves maintanance of the DLL. It should be mandatory to implement a function called queryDLLInterface, in order to reproduce the interface and all the parameters in case of lost (see example). procedure TfrmIncome.BitBtnOKClick(Sender: TObject); begin incomeRef.SetRate(strToInt(edtZins.text), strToInt(edtJahre.text)); cIncome:= incomeRef.GetIncome(StrToFloat(edtBetrag.Text)); edtBetrag.text:= Format('%m',[cIncome]); end; See also: http://www.delphi3000.com/articles/article_1416.asp or the book: "UML mit Delphi" (in german) Calling an Interface ------------------------------------------------------------------- 1. Now the client calls an InterfaceReference: private incomeIntRef: IIncomeInt; procedure TfrmIncome.BitBtnOKClick(Sender: TObject); begin incomeIntRef:=createIncome; try with incomeIntRef do begin if QueryInterface(IIncomeInt, incomeIntRef) = S_OK then begin SetRate(strToInt(edtZins.text), strToInt(edtJahre.text)); cIncome:=strTofloat(edtBetrag.text); 2. The Unit Income1 is enlarged with the interface: IIncomeInt = interface (IUnknown) ['{DBB42A04-E60F-41EC-870A-314D68B6913C}'] function GetIncome(const aNetto: Currency): Currency; stdcall; function GetRate: Real; function queryDLLInterface(var queryList: TStringList): TStringList; stdcall; procedure SetRate(const aPercent, aYear: integer); stdcall; property Rate: Real read GetRate; end; 3. The DLL exports now a real Interface-Pointer: TIncomeRealIntf = class (TInterfacedObject, IIncomeInt) private FRate: Real; function Power(X: Real; Y: Integer): Real; protected function GetRate: Real; public constructor Create; destructor destroy; override; function GetIncome(const aNetto: Currency): Currency; stdcall; function queryDLLInterface(var queryList: TStringList): TStringList; stdcall; procedure SetRate(const aPercent, aYear: integer); stdcall; property Rate: Real read GetRate; end; function CreateIncome: IIncomeInt; stdcall; begin result:= TIncomeRealIntf.Create; end; 4. When n-classes implements one interface push a parameter to the export routine in the DLL: function CreateIncome(intfID: byte): IIncomeInt; stdcall; begin case intfID of 1: result:= TIncomeRealIntf.Create; 2: result:= TIncomeRealSuper.Create; 3: result:= TIncomeRealSuper2.Create; end; end; exports CreateIncome; client-calling looks like this: incomeIntRef:=createIncome(3);