Wünsche und Anregungen | | | | H.Brill | Manchmal reichen die 15 Parameter ja nicht. siehe
aus der Glu32.dll
Wenn es technisch machbar wäre, könnte evtl. ein SET - Befehl, der die Anzahl angibt bzw. aus/einschaltet hilfreich sein :
SET("DLLParameters", x%)
SET("DLLParameters", 0/1)
Wenn oGL schon das Nutzen der API anbietet, sollten auch alle Funktionen nutzbar sein.
Oder weiß jemand, wie man obiger oGL-Funktion noch anders die 19 Parameter übergibt ? |
| | | Benutze XPROFAN X3 + FREEPROFAN Wir sind die XProfaner. Sie werden von uns assimiliert. Widerstand ist zwecklos! Wir werden alle ihre Funktionen und Algorithmen den unseren hinzufügen.
Was die Borg können, können wir schon lange. | 01.08.2023 ▲ |
| |
| | Jens-Arne Reumschüssel | Wir haben das Thema ausführlich in Paule's PC-Forum diskutiert - herausgekommen ist das hier. Auf diese Weise lassen sich beliebig viele Parameter für einen Funktionsaufruf nutzen. Sie werden Stück für Stück auf den Stack gepusht und dann wird die Funktion aufgerufen, die diese Parameter nutzt.
declare _params&[],_hGluDll&,_gluLookAtFuncAddr& declare eyeX!,eyeY!,eyeZ!,centerX!,centerY!,centerZ!,upX!,upY!,upZ!
ASM "LoopAndCall",3 'hier wird die Parameteranzahl mit übergeben und in einer Schleife abgearbeitet MOV ECX,Par1 // ECX=Count-Register für die Schleife mit der Anzahl Parameter im Array laden, wird bei jedem Loop um 1 verringert (Parameter-Nummer im Array, die Parameter müssen rückwärts auf den Stack gepusht werden [FILO]) // MOV EDX,Par2 // Offset des Array-Speichers in EDX laden - nicht nötig, EDX können wir für etwas anderes aufsparen (z.B. für eine Multiplikation) und stattdessen einfach Par2 benutzen Schleife: MOV EAX,ECX // aktuellen Schleifenzählerstand (=Nummer des aktuellen Paramters im Array) in EAX laden SUB EAX,1 // EAX=ECX-1 (Speicher-Offset im Array ist nullbasiert) ADD EAX,EAX // EAX=EAX+EAX --> im Endeffekt =EAX*2 ADD EAX,EAX // EAX=EAX+EAX --> im Endeffekt zusammen mit der Zeile davor =EAX*4 (das ist das Offset für den Parameter im Array-Speicher) // so ginge die Multiplikation auch: // MOV EDX,4 // MUL EDX // multipliziert den Inhalt des EAX-Registers mit dem Inhalt des EDX-Registers (4) und schreibt das Ergebnis ins EAX-Register zurück ADD EAX,Par2 //,EDX // Offset des Array-Speicherbereichs zu EAX dazuaddieren MOV EBX,EAX // Speicheradresse in EBX schreiben (eigentlich nicht nötig, aber so ist es klarer) MOV EAX,[EBX] // Parameter an der Speicheradresse in EAX laden - es ginge auch MOV EAX,[EAX] (damit würde man EBX für etwas anderes aufsparen und könnte sich die Zeile hiervor sparen) PUSH EAX // Parameter auf den Stack pushen LOOP Schleife // ECX um 1 verringern und zurückspringen, bis 0 erreicht ist CALL Par3 // Funktion aufrufen ENDASM
cls _hGluDll&=@usedll("glu32.dll") _gluLookAtFuncAddr&=@external("kernel32.dll","GetProcAddress",_hGluDll&,"gluLookAt") 'Adresse der aufzurufenden Funktion ermitteln _params&[1]=@long(@addr(eyeX!),0) _params&[2]=@long(@addr(eyeX!),4) _params&[3]=@long(@addr(eyeY!),0) _params&[4]=@long(@addr(eyeY!),4) _params&[5]=@long(@addr(eyeZ!),0) _params&[6]=@long(@addr(eyeZ!),4) _params&[7]=@long(@addr(centerX!),0) _params&[8]=@long(@addr(centerX!),4) _params&[9]=@long(@addr(centerY!),0) _params&[10]=@long(@addr(centerY!),4) _params&[11]=@long(@addr(centerZ!),0) _params&[12]=@long(@addr(centerZ!),4) _params&[13]=@long(@addr(upX!),0) _params&[14]=@long(@addr(upX!),4) _params&[15]=@long(@addr(upY!),0) _params&[16]=@long(@addr(upY!),4) _params&[17]=@long(@addr(upZ!),0) _params&[18]=@long(@addr(upZ!),4) print LoopAndCall(18,@addr(_params&[1]),_gluLookAtFuncAddr&) '1. Parameter: Anzahl Parameter, 2. Parameter: Adresse des Parameter-Arrays, 3. Parameter: Funktionsadresse waitinput freedll _hGluDll& end
Bitte verzeiht mir den Assembler-Code, ich habe noch nie (sic!) irgendetwas Sinnvolles in Assembler zustandebekommen, obwohl ich es oft versucht habe. Aus diesem Grund habe ich das so intensiv und vermutlich sehr laienhaft kommentiert. Wahrscheinlich würde jemand, der sich damit wirklich auskennt, das eleganter machen, aber es funktioniert.
Beste Grüße, Jens-Arne |
| | | XProfan X4 * Prf2Cpp * XPSE * JRPC3 * Win11 Pro 64bit * PC i7-7700K@4,2GHz, 32 GB RAM PM: jreumsc@web.de | 04.08.2023 ▲ |
| |
| | Jens-Arne Reumschüssel | So, und kann mir jetzt bitte irgendjemand erklären, wie es sein kann, dass gluLookAt in glu32.dll neun *Float*-Werte als Parameter erwartet, die 64 bit breit sind? Jeder 32-bit-Compiler übergibt 32-bit-Werte als Parameter auf den Stack. Wie soll denn sowas ohne unseren mühsamen Workaround-Murks oben bitte gehen? Das kann ich überhaupt nicht begreifen.
Siehe [...]
Gruß, Jens-Arne |
| | | XProfan X4XProfan X4 * Prf2Cpp * XPSE * JRPC3 * Win11 Pro 64bit * PC i7-7700K@4,2GHz, 32 GB RAM PM: jreumsc@web.de | 04.08.2023 ▲ |
| |
| | Sven Bader | Auch hier noch mal danke für deine tolle Assembler Funktion!
In der OpenGL DLL ist jede Funktion mehrfach enthalten für 2, manchmal 5 Datentypen. Das sieht das so aus:
glTranslatef() für 32 Bit Float glTranslated() für 64 Bit Float
Die Funktion entspricht dem XProfan ogl("move",x,y,z)
glu scheint dieses Anatz nicht zu verfolgen und nimmt dann im Zweifel eher mal Double, was natürlich im 3D-Kontext nicht falsch ist. |
| | | | |
| | Jens-Arne Reumschüssel | Ich habe die ASM-Funktion für die verschiedenen Calling-Conventions generalisiert, sodass damit jede erdenkliche 32-bit-DLL bedient werden kann. Außerdem habe ich sie in PushParamsAndCall umbenannt.
declare _params&[],_hGluDll&,_gluLookAtFuncAddr& declare eyeX!,eyeY!,eyeZ!,centerX!,centerY!,centerZ!,upX!,upY!,upZ!
def &stdcall 1 'Parameter absteigend auf den Stack, Funktion bereinigt den Stack def &cdecl 2 'Parameter absteigend auf den Stack, Aufrufer muss den Stack selbst bereinigen def &pascal 3 'Parameter aufsteigend auf den Stack, Funktion bereinigt den Stack
ASM "PushParamsAndCall",4 MOV ECX,Par1 'ECX=Count-Register für die Schleife mit der Anzahl Parameter im Array laden, wird bei jedem Loop um 1 verringert (Parameter-Nummer im Array, die Parameter müssen, außer bei Pascal-Calling-Convention, rückwärts auf den Stack gepusht werden [FILO]) MOV EDX,Par2 'Offset des Array-Speichers in EDX laden (ist schneller als der Zugriff über den Parameter, welcher auch ginge) MOV EAX,Par4 '1=stdcall, 2=cdecl, 3=Pascal CMP EAX,3 JZ PascalSchleife Schleife: MOV EAX,ECX 'aktuellen Schleifenzählerstand (=Nummer des aktuellen Paramters im Array) in EAX laden DEC EAX 'EAX=ECX-1 (Speicher-Offset im Array ist nullbasiert); SUB EAX,1 ginge auch ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt =EAX*2 ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt zusammen mit der Zeile davor =EAX*4 (das ist das Offset für den Parameter im Array-Speicher) ADD EAX,EDX 'Offset des Array-Speicherbereichs zu EAX dazuaddieren MOV EAX,[EAX] 'Parameter an der Speicheradresse in EAX laden PUSH EAX 'Parameter auf den Stack pushen LOOP Schleife 'ECX um 1 verringern und zurückspringen, bis 0 erreicht ist JMP CallFunction PascalSchleife: MOV EAX,Par1 SUB EAX,ECX 'Parameter in aufsteigender Reihenfolge auf den Stack legen (Pascal-Calling-Convention) ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt =EAX*2 ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt zusammen mit der Zeile davor =EAX*4 (das ist das Offset für den Parameter im Array-Speicher) ADD EAX,EDX 'Offset des Array-Speicherbereichs zu EAX dazuaddieren MOV EAX,[EAX] 'Parameter an der Speicheradresse in EAX laden PUSH EAX 'Parameter auf den Stack pushen LOOP PascalSchleife 'ECX um 1 verringern und zurückspringen, bis 0 erreicht ist CallFunction: CALL Par3 'Funktion aufrufen; ab hier EAX nicht mehr anfassen, da darin der Rückgabewert steht (oder EAX zwischenzeitlich sichern) MOV EBX,Par4 'jetzt prüfen, ob cdecl, dann muss der Stack manuell bereinigt werden CMP EBX,2 JNZ Ende 'stdcall & Pascal: Stack wurde bereits von der Funktion bereinigt MOV EBX,Par1 ADD EBX,EBX ADD EBX,EBX ADD ESP,EBX 'Stack bereinigen (cdecl) Ende: 'Return-Wert steht in EAX ENDASM
cls _hGluDll&=@usedll("glu32.dll") _gluLookAtFuncAddr&=@external("kernel32.dll","GetProcAddress",_hGluDll&,"gluLookAt") 'Adresse der aufzurufenden Funktion ermitteln _params&[1]=@long(@addr(eyeX!),0) _params&[2]=@long(@addr(eyeX!),4) _params&[3]=@long(@addr(eyeY!),0) _params&[4]=@long(@addr(eyeY!),4) _params&[5]=@long(@addr(eyeZ!),0) _params&[6]=@long(@addr(eyeZ!),4) _params&[7]=@long(@addr(centerX!),0) _params&[8]=@long(@addr(centerX!),4) _params&[9]=@long(@addr(centerY!),0) _params&[10]=@long(@addr(centerY!),4) _params&[11]=@long(@addr(centerZ!),0) _params&[12]=@long(@addr(centerZ!),4) _params&[13]=@long(@addr(upX!),0) _params&[14]=@long(@addr(upX!),4) _params&[15]=@long(@addr(upY!),0) _params&[16]=@long(@addr(upY!),4) _params&[17]=@long(@addr(upZ!),0) _params&[18]=@long(@addr(upZ!),4) print PushParamsAndCall(18,@addr(_params&[1]),_gluLookAtFuncAddr&,&stdcall) '1. Parameter: Anzahl Parameter, 2. Parameter: Adresse des Parameter-Arrays, 3. Parameter: Funktionsadresse, 4. Parameter: Calling-Convention waitinput freedll _hGluDll& end
|
| | | XProfan X4 * Prf2Cpp * XPSE * JRPC3 * Win11 Pro 64bit * PC i7-7700K@4,2GHz, 32 GB RAM PM: jreumsc@web.de | 05.08.2023 ▲ |
| |
| | Jens-Arne Reumschüssel | ...und hier die Assembler-Funktion für XProfan bis X3 (also ohne Inline-Assembler):
declare _cPushParamsAndCall#,_a%,_b% dim _cPushParamsAndCall#,75 'bis XProfan 9: muss auf long aligned sein, ggf. Ende mit nullen auffüllen (hier ist es nicht aligned, wird unten erledigt; vor XProfan 10 auf 76 dimensionieren und ein weiteres $00 anhängen) 'Opcodes in Bereich schreiben: long _cPushParamsAndCall#,0=$5589E58B,$4D088B55,$0C8B4514,$83F80374,$1089C848,$01C001C0,$01D08B00,$50E2F2EB,$108B4508,$29C801C0,$01C001D0,$8B0050E2,$F0FF5510,$8B5D1483,$FB027509,$8B5D0801,$DB01DB01,$DC89EC5D byte _cPushParamsAndCall#,72=$C2,$10,$00 'auf long alignen (geht erst ab XProfan 10, weil es vorher kein "re"dim gab): if ((@sizeof(_cPushParamsAndCall#)) mod 4)<>0 dim _cPushParamsAndCall#,@sizeof(_cPushParamsAndCall#)+(4-((@sizeof(_cPushParamsAndCall#)) mod 4)) endif 'Bytes in jedem long umdrehen: whileloop 0,@sizeof(_cPushParamsAndCall#)-4,4 _a%=@long(_cPushParamsAndCall#,&loop) whileloop 0,3 byte @addr(_b%),&loop=@byte(@addr(_a%),3-&loop) endwhile long _cPushParamsAndCall#,&Loop=_b% endwhile '... '... hier Parameterarray füllen etc. '... print @call(_cPushParamsAndCall#,18,@addr(_params&[1]),_gluLookAtFuncAddr&,&stdcall) '1. Parameter: Anzahl Parameter, 2. Parameter: Adresse des Parameter-Arrays, 3. Parameter: Funktionsadresse, 4. Parameter: Calling-Convention dispose _cPushParamsAndCall#
|
| | | XProfan X4 * Prf2Cpp * XPSE * JRPC3 * Win11 Pro 64bit * PC i7-7700K@4,2GHz, 32 GB RAM PM: jreumsc@web.de | 07.10.2023 ▲ |
| |
| | Jens-Arne Reumschüssel | Und, weil es so schön ist, das ganze nochmal für JRPC3 mit FreeBasic, weil man sich damit das sonst bei jedem Aufruf von gluLookAt notwendige manuelle Setzen des Parameter-Arrays mit einem Makro vom Hals schaffen kann und das ganze ebenfalls ohne den XProfan-Inline-Assembler funktioniert (also für Versionen vor X4) - voll funktionsfähiges Beispiel:
declare _params&[],_hGluDll&,_gluLookAtFuncAddr&,_retval& declare eyeX!,eyeY!,eyeZ!,centerX!,centerY!,centerZ!,upX!,upY!,upZ!
def &stdcall 1 'Parameter absteigend auf den Stack, Funktion bereinigt den Stack def &cdecl 2 'Parameter absteigend auf den Stack, Aufrufer muss den Stack selbst bereinigen def &pascal 3 'Parameter aufsteigend auf den Stack, Funktion bereinigt den Stack
fbPROC PushParamsAndCall(byval AnzParams as long,byval pArray as long,byval pFunc as long,byval CallingConv as long) as integer export dim as ulong ReturnValue ASM MOV ECX,[AnzParams] 'ECX=Count-Register für die Schleife mit der Anzahl Parameter im Array laden, wird bei jedem Loop um 1 verringert (Parameter-Nummer im Array, die Parameter müssen, außer bei Pascal-Calling-Convention, rückwärts auf den Stack gepusht werden [FILO]) MOV EDX,[pArray] 'Offset des Array-Speichers in EDX laden (ist schneller als der Zugriff über den Parameter, welcher auch ginge) MOV EAX,[CallingConv] '1=stdcall, 2=cdecl, 3=Pascal CMP EAX,3 JZ PascalSchleife Schleife: MOV EAX,ECX 'aktuellen Schleifenzählerstand (=Nummer des aktuellen Paramters im Array) in EAX laden DEC EAX 'EAX=ECX-1 (Speicher-Offset im Array ist nullbasiert); SUB EAX,1 ginge auch ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt =EAX*2 ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt zusammen mit der Zeile davor =EAX*4 (das ist das Offset für den Parameter im Array-Speicher) ADD EAX,EDX 'Offset des Array-Speicherbereichs zu EAX dazuaddieren MOV EAX,[EAX] 'Parameter an der Speicheradresse in EAX laden PUSH EAX 'Parameter auf den Stack pushen LOOP Schleife 'ECX um 1 verringern und zurückspringen, bis 0 erreicht ist JMP CallFunction PascalSchleife: MOV EAX,[AnzParams] SUB EAX,ECX 'Parameter in aufsteigender Reihenfolge auf den Stack legen (Pascal-Calling-Convention) ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt =EAX*2 ADD EAX,EAX 'EAX=EAX+EAX --> im Endeffekt zusammen mit der Zeile davor =EAX*4 (das ist das Offset für den Parameter im Array-Speicher) ADD EAX,EDX 'Offset des Array-Speicherbereichs zu EAX dazuaddieren MOV EAX,[EAX] 'Parameter an der Speicheradresse in EAX laden PUSH EAX 'Parameter auf den Stack pushen LOOP PascalSchleife 'ECX um 1 verringern und zurückspringen, bis 0 erreicht ist CallFunction: CALL [pFunc] 'Funktion aufrufen; ab hier EAX nicht mehr anfassen, da darin der Rückgabewert steht (oder EAX zwischenzeitlich sichern) MOV EBX,[CallingConv] 'jetzt prüfen, ob cdecl, dann muss der Stack manuell bereinigt werden CMP EBX,2 JNZ Ende 'stdcall & Pascal: Stack wurde bereits von der Funktion bereinigt MOV EBX,[AnzParams] ADD EBX,EBX ADD EBX,EBX ADD ESP,EBX 'Stack bereinigen (cdecl) Ende: MOV [ReturnValue],EAX 'Rückgabewert der aufgerufenen aus EAX setzen ("MOV [Function],EAX" funktioniert nicht, weil JRPC3 automatisch ein "return 0" am Ende der fbPROC ergänzt, wenn kein return-Wert angegeben ist, um eine entsprechende Compilerwarnung zu vermeiden) END ASM return ReturnValue ENDPROC 'PushParamsAndCall
MACRO mcrGluLookAt(#p1#,#p2#,#p3#,#p4#,#p5#,#p6#,#p7#,#p8#,#p9#) _params&[1]=@long(@addr(#p1#),0) _params&[2]=@long(@addr(#p1#),4) _params&[3]=@long(@addr(#p2#),0) _params&[4]=@long(@addr(#p2#),4) _params&[5]=@long(@addr(#p3#),0) _params&[6]=@long(@addr(#p3#),4) _params&[7]=@long(@addr(#p4#),0) _params&[8]=@long(@addr(#p4#),4) _params&[9]=@long(@addr(#p5#),0) _params&[10]=@long(@addr(#p5#),4) _params&[11]=@long(@addr(#p6#),0) _params&[12]=@long(@addr(#p6#),4) _params&[13]=@long(@addr(#p7#),0) _params&[14]=@long(@addr(#p7#),4) _params&[15]=@long(@addr(#p8#),0) _params&[16]=@long(@addr(#p8#),4) _params&[17]=@long(@addr(#p9#),0) _params&[18]=@long(@addr(#p9#),4) _retval&=@PushParamsAndCall(18,@addr(_params&[1]),_gluLookAtFuncAddr&,&stdcall) '1. Parameter: Anzahl Parameter, 2. Parameter: Adresse des Parameter-Arrays, 3. Parameter: Funktionsadresse, 4. Parameter: Calling-Convention ENDMACRO 'mcrGluLookAt
cls _hGluDll&=@usedll("glu32.dll") _gluLookAtFuncAddr&=@external("kernel32.dll","GetProcAddress",_hGluDll&,"gluLookAt") 'Adresse der aufzurufenden Funktion ermitteln mcrGluLookAt(eyeX!,eyeY!,eyeZ!,centerX!,centerY!,centerZ!,upX!,upY!,upZ!) print _retval& waitinput freedll _hGluDll& end
|
| | | XProfan X4XProfan X4 * Prf2Cpp * XPSE * JRPC3 * Win11 Pro 64bit * PC i7-7700K@4,2GHz, 32 GB RAM PM: jreumsc@web.de | 07.10.2023 ▲ |
| |
|
AntwortenThemenoptionen | 1.980 Betrachtungen |
ThemeninformationenDieses Thema hat 3 Teilnehmer: |