関数テーブルにあるプロシージャまたは関数を動的に呼び出す機能を試しています。特定のアプリケーションは、関数テーブルへのポインターを引数の数と型に関する情報と共にエクスポートする DLL です。ホスト アプリケーションは、DLL に問い合わせて関数を呼び出すことができます。それらがオブジェクト メソッドである場合、Rtti を使用してそれらを呼び出すことができますが、それらは通常の手順と関数です。DLL は C、Delphi などを含む任意の言語で記述できるため、DLL はオブジェクトではなく通常の関数ポインタをエクスポートする必要があります。
たとえば、DLL で宣言および入力されたレコードがあります。
TAPI = record
add : function (var a, b : double) : double;
mult : function (var a, b : double) : double;
end;
PAPI = ^TAPI;
次のように宣言されたこのレコードへのポインターを取得します。
apiPtr : PAPI;
プロシージャの名前、引数の数、およびレコード内の各エントリの引数の型にもアクセスできるとします。
add 関数を呼び出したいとします。追加する関数ポインタは次のようになります。
@apiPtr^.add // I assume this will give me a pointer to the add function
asm を使用して必要な引数をスタックにプッシュし、結果を取得する以外に方法はないと思いますか?
最初の質問です。プロシージャを cdecl として宣言するのに最適な呼び出し規約は何ですか? 呼び出しの前にスタックを組み立てるのが最も簡単なようです。
2 番目の質問ですが、実際にこれを行うオンラインの例はありますか? http://www.swissdelphicenter.ch/torry/showcode.php?id=1745 (DynamicDllCall)に遭遇しましたが、これは私が望むものに近いものですが、以下のように単純化すると、結果へのポインター (EAX) が返されるようになりました。
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;
終わり;
結果ではなく、最初のパラメーターの値を返します。呼び出し規約が間違っているか、EAX で結果を取得する方法を誤解している可能性があります。
次のように DynamicDllCall を呼び出します。
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^);
どんなアドバイスもありがたく受け取った。これを行うべき方法ではないと感じる人もいるかもしれませんが、少なくともそれが可能かどうかはまだ知りません.
更新 1 add 関数が加算を行うための正しい値を取得していることを確認できます。
更新 2 add の署名を次のように変更した場合:
add : function (var a, b, c : double) : double;
その結果を add 内の c に代入すると、parameters 配列で正しい答えを取得できます (2 ではなく 3 の要素をもう 1 つ追加すると仮定します)。したがって、問題は、関数から値が返される方法を誤解していることです。関数が値を返す方法と、それらを取得する最善の方法を誰か説明できますか?
更新 3答えがあります。私は推測したはずです。Delphi は、さまざまなレジスタを介してさまざまな型を返します。たとえば、整数は EAX を介して返されますが、double は ST(0) を介して返されます。ST(0) を結果変数にコピーするには、「MOV p, EAX」ではなく「FST 結果」を使用する必要があります。少なくとも、原則としてこれが可能であることはわかっています。それが賢明なことかどうかは、私が今考えなければならない別の問題です.