Sto sperimentando la possibilità di richiamare dinamicamente procedure o funzioni che si trovano in una tabella di funzioni. L'applicazione specifica è una DLL che esporta un puntatore a una tabella di funzioni insieme alle informazioni sul numero di argomenti e tipi. L'applicazione host ha quindi la capacità di interrogare la DLL e chiamare le funzioni. Se fossero metodi oggetto, potrei usare Rtti per invocarli, ma sono normali procedure e funzioni. La DLL deve esportare normali puntatori a funzione non oggetti perché la DLL può essere scritto in qualsiasi lingua, tra cui C, Delphi, eccCome richiamare dinamicamente una procedura o una funzione denominata in Delphi
Per esempio, ho un record di dichiarata e compilato in una DLL:
TAPI = record
add : function (var a, b : double) : double;
mult : function (var a, b : double) : double;
end;
PAPI = ^TAPI;
ho recuperare il puntatore a questo record, ha dichiarato come:
apiPtr : PAPI;
Si supponga che ho anche l'accesso ai nomi delle procedure, il numero di argomenti e tipi di argomenti per ogni voce nel record.
Si supponga di voler chiamare la funzione di aggiunta. Il puntatore a funzione per aggiungere sarà:
@apiPtr^.add // I assume this will give me a pointer to the add function
Presumo non c'è altro modo diverso da quello di utilizzare alcuni asm per spingere gli argomenti necessari sullo stack e recuperare il risultato?
Prima domanda, qual è la migliore convenzione di chiamata per dichiarare la procedura come, cdecl? Sembra più semplice per assemblare la pila prima della chiamata.
Seconda domanda, ci sono esempi online che effettivamente lo fanno? Mi sono imbattuto in http://www.swissdelphicenter.ch/torry/showcode.php?id=1745 (DynamicDllCall) che è vicino a quello che voglio, ma ho semplificato come sotto, ora restituisce un puntatore (EAX) al risultato:
function DynamicDllCall(proc : pointer; const Parameters: array of Pointer): pointer;
var x, n: Integer;
p: Pointer;
begin
n := High(Parameters);
if n > -1 then begin
x := n;
repeat
p := Parameters[x];
asm
PUSH p
end;
Dec(x);
until x = -1;
end;
asm
CALL proc
MOV p, EAX <- must be changed to "FST result" if return value is double
end;
result := p;
fine;
ma non riesco a farlo funzionare, restituisce un valore per i primi parametri anziché il risultato. Forse ho sbagliato la convenzione di chiamata o forse ho frainteso come recuperare il risultato in EAX.
io chiamo DynamicDllCall come segue:
var proc : pointer;
parameters: array of Pointer;
x, y, z : double;
p : pointer;
begin
x:= 2.3; y := 6.7;
SetLength(parameters, 2);
parameters[0] := @x; parameters[1] := @y;
proc := @apiPtr^.add;
p := DynamicDllCall(proc, Parameters);
z := double (p^);
Qualsiasi consiglio ben accetto. Apprezzo che alcuni possano pensare che questo non è il modo in cui si dovrebbe fare per farlo, ma sono comunque curioso di sapere se è almeno possibile.
Aggiornamento 1 Posso confermare che la funzione di aggiunta sta ottenendo i valori corretti per fare l'aggiunta.
Update 2 Se cambio la firma di aggiungere:
add : function (var a, b, c : double) : double;
e assegnare il risultato a c all'interno aggiungere, quindi posso recuperare la risposta corretta nella matrice dei parametri (supponendo aggiungo uno più elemento ad esso, 3 invece di 2). Il problema quindi è che non capisco come vengono restituiti i valori dalle funzioni. Qualcuno può spiegare come funzioni restituiscono valori e come recuperarli al meglio?
Aggiornamento 3 Ho la mia risposta. Avrei dovuto indovinare. Delphi restituisce diversi tipi tramite diversi registri. ad es. gli interi ritornano tramite EAX, il doppio invece restituisce tramite ST (0). Per copiare ST (0) nella variabile risultato, devo usare "risultato FST" piuttosto che "MOV p, EAX". Almeno ora so che è possibile in linea di principio farlo. Se sia una cosa sensata da fare è un'altra questione che ora devo pensare.
C'era una bella introduzione a Delphi ASM all'indirizzo www.delphi3000.com (articoli/articolo_3766.asp), ma l'intero sito non è più disponibile ... –
Forse la documentazione su [Procedure e procedure di assemblaggio] (http : //docwiki.embarcadero.com/RADStudio/XE4/en/Assembly_Procedures_and_Functions) aiuterebbe. Vedi l'argomento 'Risultati delle funzioni'. –
Non c'è molto là fuori e i documenti ufficiali non sono terribili utili.Comunque ho messo insieme abbastanza informazioni da: http://stackoverflow.com/questions/15786404/fld-instruction-x64-bit e http://www.guidogybels.eu/docs/Using%20Assembler%20in% 20Delphi.pdf – rhody