Autor | Thema: Profan und DLL aus Object bzw. Virtual Pascal | | Datum:08.11.01 08:50 
(mail@stschnell.de) | |
Hallo Community,
habe folgendes Problem:
1. Erstelle eine DLL mit ASM auf die FPU die ungefähr wie folgt aussieht:
LIBRARY fpu;
CONST
semicircle : DOUBLE = 180.0;
{=Sinus============================================================}
{ Mit dieser Funktion wird der Sinus eines Winkels, dessen Eingabe
in Grad erfolgt, errechnet. }
FUNCTION fsin (angle : DOUBLE) : DOUBLE; STDCALL;
VAR
res : DOUBLE;
BEGIN
ASM
FINIT
FLDPI
FLD semicircle
FDIVP
FMUL angle
FSIN
FSTP res
END;
fsin := res;
END;
{=Cosinus==========================================================}
{ Mit dieser Funktion wird der Kosinus eines Winkels, dessen
Eingabe in Grad erfolgt, errechnet. }
FUNCTION fcos (angle : DOUBLE) : DOUBLE; STDCALL;
VAR
res : DOUBLE;
BEGIN
ASM
FINIT
FLDPI
FLD semicircle
FDIVP
FMUL angle
FCOS
FSTP res
END;
fcos := res;
END;
{=Sinus und Cosinus================================================}
{ Mit dieser Prozedur wird der Sinus und der Kosinus eines Winkels,
dessen Eingabe in Grad erfolgt, errechnet. Die Werte werden ber
die Variablen 'cos' und 'sin'ausgegeben. }
PROCEDURE fsincos (angle, cos, sin : DOUBLE); STDCALL;
ASM
FINIT
FLDPI
FLD semicircle
FDIVP
FMUL angle
FSINCOS
FSTP cos
FSTP sin
END;
{=Export=============================================================}
EXPORTS
fsin,
fcos,
fsincos;
{=Ende===============================================================}
BEGIN
END.
Die Compilierung funktioniert ohne Fehler mit DCC der Version 3.01 und 6 sowie VirtualPascal.
2. Nachdem die DLL erstellt ist, greife ich mit folgendem Profanprogramm darauf zu:
Declare Res!
Def @FSin(1) !"FPU.DLL", "fsin"
Let Res! = @FSin(45.0)
Print Res
WaitKey
End
Leider jedoch wird immer ein Ausnahmefehler beim Zugriff auf die Funktion @FSin erzeugt. Was mache ich falsch?
3. Jetzt noch eine Sache, eigentlich nur so, hat nichts mit Profan zu tun, aber vielleicht weiss ja einer eine Antwort darauf:
Nach der Compilierung der DLL habe ich mir den erzeugten Code einmal mit einem DisASM angeschaut und er brachte folgendes (erstaunliches) Resultat zu stande:
2BF1:ED32DBB6 55 push ebp
2BF1:ED32DBB7 8BEC mov ebp,esp
2BF1:ED32DBB9 83C4F0 add esp,FFFFFFF0
2BF1:ED32DBBC 9B wait
2BF1:ED32DBBD DBE3 fninit
2BF1:ED32DBBF D9EB fldpi
2BF1:ED32DBC1 DD05A0304000 fld qword ptr ds:[004030A0]
2BF1:ED32DBC7 DEF9 fdivrp st(1),st
2BF1:ED32DBC9 DC4D08 fmul qword ptr [ebp+08]
2BF1:ED32DBCC D9FE fsin
2BF1:ED32DBCE DD5DF8 fstp qword ptr [ebp-08]
2BF1:ED32DBD1 8B45F8 mov eax,[ebp-08]
2BF1:ED32DBD4 8945F0 mov [ebp-10],eax
2BF1:ED32DBD7 8B45FC mov eax,[ebp-04]
2BF1:ED32DBDA 8945F4 mov [ebp-0C],eax
2BF1:ED32DBDD DD45F0 fld qword ptr [ebp-10]
2BF1:ED32DBE0 8BE5 mov esp,ebp
2BF1:ED32DBE2 5D pop ebp
2BF1:ED32DBE3 C20800 retn 0008
Hier habe ich mal die FSIN-Funktion herausgegriffen, compiliert mit DCC 6, sieht eigentlich relativ gut aus, DCC 3 und Virtual Pascal haben einen noch deutlich anderen Code erzeugt. Woran liegt es, das die Compiler aus FINIT - FNINIT machen bzw. aus FDIVP - FDIVRP?
Vielen Dank für Eure Antworten.
Tschüss
Stefan Schnell
|
| | Datum: 08.11.01 11:38 
(rgh-soft@t-online.de) | |
PROFAN erwartet als Rückgabewert bei einem API- bzw. DLL-Aufruf grundsätzlich einen 32-Bit-Wert! (In der Windows-API gibt es nichts anderes.) Double ist aber 64 Bit breit. Deshalb kracht es bei der Rückkehr aus der Funktion. Ebenso können auch nur 32-Bit-Werte (Integer, Pointer) an eine API- bzw. DLL-Funktion übergeben werden.
Abhilfe: Benutze den Datentyp Single (32 Bit). Das dürfte für praktische Anwendungen immer noch genau genug sein. PROFAN kennt zwar diesen Datentypen nicht, aber in PROFAN 7.5 wird die Funktionen @Double und @Single haben, um die Werte entsprechend umzuwandeln. (Siehe hierzu die LIESMICH.TXT in der aktuellen Betaversion im Downloadbereich.) Die DIRECTX-API benutzt auch Single für Fließkommazahlen.
Eine andere Lösung ist der Umweg über Bereichsvariablen, in denen die Werte als String stehen. Das geht in allen PROFAN-Versionen, ist natürlich umständlicher und auch langsamer.
|
|
|