1) Per la unit relativa al package:
interface
.......
.......
TProva = class(TPersistent)
function ShowString: String;
end;
implementation
function TProva.ShowString: String;
begin
Result := 'Prova';
end;
initialization
RegisterClass(TProva);
2) Per la unit relativa al programma principale:
interface
......
......
implementation
procedure TForm1.Button1Click(Sender: TObject);
var
HandlePackage: HMODULE;
ProvaRef: TPersistentClass;
Prova: TPersistent;
begin
HandlePackage := LoadPackage('Package.bpl');
if (HandlePackage > 0) then
begin
ProvaRef := GetClass('TProva');
if Assigned(ProvaRef) then
begin
Prova := ProvaRef.Create;
try
Edit1.Text := Prova. ; // problema :-)
finally
UnloadPackage(HandlePackage);
end;
end;
end
else
ShowMessage('File Package.bpl not found !!!');
end;
Praticamente ciò che vorrei ottenere è la visualizzazione della stringa
'Prova' in una casella di testo, ma per far ciò devo accedere al metodo
ShowString della classe TProva esportata, ma non riesco ad accedervi. Come
fare quindi? Grazie a tutti in anticipo.
--- posted by geoForum on http://www.delphiedintorni.it
La prima cosa che mi viene in mente è creare una classe superiore dove
definire le funzioni/procedure esportare nel pck, dichiararle virtual e
da questa far derivare la classe inserita dentro il pck con le
funzioni/procedure implementate, nel programma linkare solo la classe
principale con le funzioni virtual.
La seconda potrebbe essere l'uso di interfacce, ma non ricordo bene il
funzionamento, se vai sul sito di Marco Cantu' dovrebbero esserci degli
esempi proprio sull'uso di interfacce nei pck (se la memoria funziona
ancora).
Goblin
--
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/
Potresti gentilmente spiegarmi meglio quello che hai detto con qualche
breve esempio se non ti disturbo troppo?
>La seconda potrebbe essere l'uso di interfacce, ma non ricordo bene il=20
>funzionamento, se vai sul sito di Marco Cantu' dovrebbero esserci degli=20
>esempi proprio sull'uso di interfacce nei pck (se la memoria funziona=20
>ancora).
>
Veramente io possiedo il libro di Marco Cantù che spiega l'argomento delle
interfacce nei package(adatto ovviamente piu' per applicazioni
voluminose), ma nell'esempio riporta una unit generica dove è dichiarata
l'interfaccia da implementare nelle relative unit che rappresentano i vari
package dell'applicazione. Ovviamente per implementare l'interfaccia
presente nella unit generica, bisogna usare la clausola uses nelle varie
unit il che significa(correggimi se sbaglio) che la unit generica viene
compilata insieme a tutte le altre. Ma il mio obiettivo era quello di
evitare di mettere clausole uses e una volta ottenuto il class reference
della classe presente nel package tramite l'istruzione GetClass (come
appena descritto), riuscire a creare un'istanza della classe e usare i
suoi metodi :-( ..... Chissà se con i puntatori è possibile ......
File Demo.dpr (progetto)
<
program Demo;
uses
Forms,
Main in 'Main.pas' {Form1},
UClassMain in 'UClassMain.pas';
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
>
file Main.pas
<
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs,UClassMain {Questa è la unit condivisa}, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
sPath: String;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var HandlePackage: HMODULE;
ProvaRef: TRMiaClass;
Prova: TMiaClasse;
sNome: String;
begin
//ATTENZIONE itemindex non gestito
sNome := ListBox1.Items[ListBox1.ItemIndex];
HandlePackage := LoadPackage(sPath+sNome);
if (HandlePackage > 0) then
begin
try
ProvaRef := TRMiaClass(GetClass('TMiaClassePck'));
if Assigned(ProvaRef) then
begin
Prova := ProvaRef.Create;
Edit1.Text := Prova.Test;
end;
finally
UnloadPackage(HandlePackage);
end
end
else
ShowMessage('File Pck.bpl not found !!!');
end;
procedure TForm1.FormCreate(Sender: TObject);
Var sr: TSearchRec;
begin
sPath := ExtractFilePath(Application.ExeName)+'Bpl\';
if FindFirst(sPath+'*.bpl', faAnyFile, sr) = 0 then
begin
repeat
if (sr.Name<>'.') and (sr.Name<>'..') then
ListBox1.Items.Add(sr.name);
until FindNext(sr) <> 0;
FindClose(sr);
end;
end;
end.
>
il file Main.dfm contiene 3 componenti Edit1: TEdit,
Button1: TButton, ListBox1: TListBox;
File .BPL definito con runtimeonly
<
package Pck;
{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$RUNONLY}
{$IMPLICITBUILD OFF}
requires
rtl;
contains
UPck1 in 'UPck1.pas';
end.
>
File UPck1.pas
<
unit UPck1;
interface
uses Classes, UClassMain;
type
TMiaClassePck = class(TMiaClasse)
private
{ Private declarations }
public
{ Public declarations }
Published
Function Test: String; Override;
end;
implementation
{ TMiaClasse }
function TMiaClassePck.Test: String;
begin
// sono nella classe figlia
Result := 'Rosso';
end;
initialization
RegisterClass(TMiaClassePck);
finalization
UnregisterClass(TMiaClassePck);
end.
>
File UClassMain.pas
<
unit UClassMain;
interface
uses Classes;
type
TMiaClasse = class(TPersistent)
private
{ Private declarations }
public
{ Public declarations }
Published
Function Test: String; Virtual;
end;
TRMiaClass = Class of TMiaClasse;
implementation
{ TMiaClasse }
function TMiaClasse.Test: String;
begin
// non fa niente vedere classe derivata
end;
end.
>
Spero di essere stato chiaro e di non aver scritto troppe cavolate
> ..... Chissà se con i puntatori è possibile ......
>
Con le DLL è possibile usare 'GetProcAddress', ma nei pck mi sembra che
sia sconsigliato
Goblin
^_Goblin_^ ha scritto:
>.......................
>.......................
>.......................
>Con le DLL è possibile usare 'GetProcAddress', ma nei pck mi sembra che
>sia sconsigliato
>
>Goblin
>
Grazie per la pazienza e il tempo che mi hai dedicato, esaminerò il tuo
codice domani. Comunque smanettandoci tutta la serata sull'Help di Delphi
alla fine sono riuscito ad ottenere quello che volevo senza usare ne il
primo approccio e ne il secondo. Praticamente la soluzione è questa: nella
unit ObjAuto, c'è una funzione che si chiama GetMethodInfo che restituisce
un puntatore a un packed record contenente informazioni su un metodo di un
oggetto generico TObject. La sintassi della funzione è la seguente:
function GetMethodInfo(Instance: TObject; const MethodName: ShortString):
PMethodInfoHeader; dove PMethodInfoHeader = ^TMethodInfoHeader da cui
TMethodInfoHeader = packed record
Len: Word; // lunghezza del metodo credo :-)
Addr: Pointer; // indirizzo o puntatore
Name: ShortString; // nome del metodo
end;
Da qui quindi la modifica del mio event handler è la seguente:
procedure TForm1.Button1Click(Sender: TObject);
type
// Poichè il campo del record(Addr) è un indirizzo e quindi un
// puntatore al metodo dell'oggetto(classe) dichiaro:......
TFuncShowString = function: String of object;
var
HandlePackage: HMODULE;
ProvaRef: TPersistentClass; Prova: TPersistent;
MethodInfo: PMethodInfoHeader; // memorizzo le info della funzione
FuncShowString: TFuncShowString; // variabile funzione
begin
HandlePackage := LoadPackage('Package.bpl');
if (HandlePackage > 0) then
begin
ProvaRef := GetClass('TProva');
if Assigned(ProvaRef) then
begin
Prova := ProvaRef.Create;
try
MethodInfo := GetMethodInfo(Prova, 'ShowString');
// calcolo l'indirizzo del metodo puntando ad esso....
@FunShowString := MethodInfo.Addr;
// visualizzo il risultato della funzione sulla casella
// di testo cioè la stringa 'Prova'
Edit1.Text := ' ' + FunShowString;
finally
FreeAndNil(Prova); UnloadPackage(HandlePackage);
end;
end;
end
else
ShowMessage('File Package.bpl not found !!!');
end;
Come lo vedi questo approccio? Non è piu' sbrigativo? Da principiante però
mi chiedo se puo' essere professionale.....che ne pensi?
> Come lo vedi questo approccio? Non è piu' sbrigativo? Da principiante però
> mi chiedo se puo' essere professionale.....che ne pensi?
>
>
>
Mi considero un buon hobbista non mi sento in grado di giudicare lascio
questo incarico a chi ci capisce un po' piu' di me :)
Cmq lo vedo molto simile al mio, in fondo "il prototipo" della funzione
da usare da qualche parte la devi dichiarare, io uso una classe base, tu
un puntatore ... non so dirti quale sia "il migliore".
>Mi considero un buon hobbista non mi sento in grado di giudicare lascio=20
>questo incarico a chi ci capisce un po' piu' di me :)
>Cmq lo vedo molto simile al mio, in fondo "il prototipo" della funzione=20
>da usare da qualche parte la devi dichiarare, io uso una classe base, tu =
>
>un puntatore ... non so dirti quale sia "il migliore".
>
Beh, di sicuro neanche io posso permettermi di giudicare i vari approcci,
anche se penso che in generale(posso sbagliarmi visto che sono un
principiante) che l'uso dei puntatori sia un'ottima alternativa anche per
la gestione dinamica della memoria e la sua ottimizzazione, ma d'altronde
come si dice....tutte le strade portano a Roma :-) (anche se questo detto
non penso sia valido per progetti complessi dove bisogna sicuramente
decidere l'approccio migliore da usare). Bisognerebbe chiedere a qualche
guru :-)......Comunque grazie di nuovo ciao alla prossima.