Prüfen, ob eine Adresse auf eine Procedure zeigt

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von Kiffi »

NicTheQuick hat geschrieben:Da muss man eben noch ein bisschen was drum herum bauen.
Nun gut, dann brechen wir an dieser Stelle ab. Hätte ja auch sein können, dass eine IsProcedure() - Funktion mit einem Zwei- oder Dreizeiler abgehandelt werden kann. Wenn es allerdings so aufwändig ist, muß in diesem Fall der Programmierer selber dafür Sorge tragen, dass er die korrekte Prozedur angibt.

Danke nochmal an alle Beteiligten & Grüße ... Peter
a²+b²=mc²
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von Bisonte »

Kiffi hat geschrieben:
NicTheQuick hat geschrieben:....muß in diesem Fall der Programmierer selber dafür Sorge tragen, dass er die korrekte Prozedur angibt. ...
Soviel Wissen um seinen eigenen Code sollte der Programmierer eigentlich haben!

/OT
Was ist denn aus dem "in Unterhose Bier trinken" geworden ... Hat die Signatur zuviel Privatfernsehen der unteren Bildungsschicht beim Trinken gesehen ? :mrgreen:
OT/

Edit:

Das Problem bei CallFunctionFast, sind die bis zu 20 möglichen Parameter.
Ich hatte gerade die Idee, einen Prototype zu nehmen, " Prototype my_CallF(Arg1 = 0, Arg2 = 0.... Arg20) " ,
diesen dann in eine List() per einer Procedure "RegisterProc" und am Ende ein eigenes CallFF um dann in der
Liste zu suchen und bei einem Treffer auszuführen.

Aber was, wenn eine Funktion nur 5 Parameter hat, ich sie aber mit 20 Parametern (die zwar alle 0 sind, aber halt im Aufruf sind)
aufrufe.... Da knallts ;)

Ich grüble noch ein wenig an der List() - Idee....
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von Kiffi »

Bisonte hat geschrieben:
Kiffi hat geschrieben:
NicTheQuick hat geschrieben:....muß in diesem Fall [...]
oh, Quoting-Inception mit leicher Phasen-Verschiebung. :-)
Bisonte hat geschrieben:Soviel Wissen um seinen eigenen Code sollte der Programmierer eigentlich haben!
IsProcedure() würde ich ähnlich wie IsGadget(), IsWindow() & Co als eine Art Komfort-Funktion sehen.
Bisonte hat geschrieben:/OT
Was ist denn aus dem "in Unterhose Bier trinken" geworden ... Hat die Signatur zuviel Privatfernsehen der unteren Bildungsschicht beim Trinken gesehen ? :mrgreen:
OT/
Bier ist alle. "Frauentausch" ist langweilig. Deshalb sitze ich jetzt wieder (in Unterhose) an der Tastatur. ;-)
a²+b²=mc²
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von Bisonte »

Da wäre jetzt (reine Fleissarbeit ^^) folgendes Modul im Angebot, wobei man in der Main.pb halt nicht nur der Variablen eine Prozedureadresse zuweist,
sondern halt die Procedure noch einmal mit Paramater Zählung "registriert".

Kann man mit Sicherheit verfeinern... unter Umständen Nic's Beispiel um zu testen ob es überhaupt eine Prozedur ist....
Oder wenn man die maximale Anzahl der Parameter eingrenzen kann (z.B. keine Prozedur hat mehr als 7 Parameter)
kann man natürlich die Select Case Geschichte kürzen...

Wäre das etwas ?

Code: Alles auswählen

; Main

DeclareModule cm_FunctionCall
  
  EnableExplicit
  
  Declare RegisterFunction(*Function, ParamCount = 0)
  Declare myCallFunctionFast(*Function, Arg1 = 0, Arg2 = 0, Arg3 = 0, Arg4 = 0, Arg5 = 0, Arg6 = 0, Arg7 = 0, Arg8 = 0, Arg9 = 0, Arg10 = 0, Arg11 = 0, Arg12 = 0, Arg13 = 0, Arg14 = 0, Arg15 = 0, Arg16 = 0, Arg17 = 0, Arg18 = 0, Arg19 = 0)
  
EndDeclareModule
Module cm FunctionCall
  
  Global NewMap LOP.i()
  
  Procedure RegisterFunction(*Function, ParamCount = 0)
    
    If ParamCount > 19
      ProcedureReturn #False
    EndIf
    
    If *Function
      LOP(Str(*Function)) = ParamCount
      ProcedureReturn #True  
    EndIf
    
    ProcedureReturn #False
    
  EndProcedure
  Procedure myCallFunctionFast(*Function, Arg1 = 0, Arg2 = 0, Arg3 = 0, Arg4 = 0, Arg5 = 0, Arg6 = 0, Arg7 = 0, Arg8 = 0, Arg9 = 0, Arg10 = 0, Arg11 = 0, Arg12 = 0, Arg13 = 0, Arg14 = 0, Arg15 = 0, Arg16 = 0, Arg17 = 0, Arg18 = 0, Arg19 = 0)
    
    Protected PC, Result = #False
    
    If FindMapElement(LOP(), Str(*Function))
      
      PC = LOP(Str(*Function))
      
      Select PC
        Case 0
          Result = CallFunctionFast(*Function)
        Case 1
          Result = CallFunctionFast(*Function, Arg1)
        Case 2
          Result = CallFunctionFast(*Function, Arg1, Arg2)
        Case 3
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3)
        Case 4
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4)
        Case 5
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5)
        Case 6
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)
        Case 7
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)
        Case 8
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)
        Case 9
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9)
        Case 10
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10)
        Case 11
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11)
        Case 12
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12)
        Case 13
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13)
        Case 14
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14)
        Case 15
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15)
        Case 16
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16)
        Case 17
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17)
        Case 18
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18)
        Case 19
          Result = CallFunctionFast(*Function, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18, Arg19)
      EndSelect
      
    EndIf
    
  EndProcedure
  
EndModule

UseModule cm_FunctionCall

Procedure myCallback()
  Debug "Piep!"
EndProcedure

RegisterFunction(@myCallback())
MachMalPiep = @myCallback()

SeiFleissig() 

; --- Include

Procedure SeiFleissig()
 ... TuDies()
 ... myCallFunctionFast(MachMalPiep)
 ... TuDas()
EndProcedure 
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von GPI »

Kiffi hat geschrieben:Ganz simpel: Ich habe eine Main.pb und eine Include.pbi. In der Main starte ich einen Vorgang innerhalb dessen ich eine Prozedur der Main.pb aufrufen möchte.
Kaum eine Chance. Wobei du hier auch aufpassen musst, das der Pointer global ist. Ich würde da sowieso eine "SetCallBack"-Funktion reinhauen.
Was du machen kannst: Überprüf den Pointer ob er Null ist, bevor du ihn aufrufst/benutzt.
Genauso wenn er nicht mehr gebraucht wird, den Pointer unbedingt auf Null setzen. Wenn er dann versehentlich verwendet wird, stürzt das Programm wenigstens sauber an der Stelle ab und verursacht nicht einen willkürlichen Fehler.

Ich weis ja nicht genau, was du programmieren willst, aber wenn es einen "open-aufruf" und einen "close-Aufruf" gibt, würde ich bei beiden den Pointer auf null setzen und nach Call (oder als optionalen Parameter bei ini) den Pointer zum callback setzen.

@Bisonte
Ich würde sagen bedingt. Der "Benutzer" muss hier die Parameteranzahl übergeben - und kann da schummeln. Zudem gibt es das Problem, das seine Funktion halt eine bestimmte Parameteranzahl verlangt. Mit mehr oder weniger Parameter kann sie nichts anfangen.

Wenn ein Benutzer vorgefertigten Code benutzt, sollte er schon die Dokumentation dazu durchlesen, was er da machen muss. Soviel kann man schon verlangen.
Hier ist es leider sehr schade, das PB keine Typenüberprüfung hat.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von RSBasic »

Jemand aus diesem Forum hat mal nach einer Try-Catch-Funktion gefragt. Soweit ich weiß gab es auch eine Lösung, die gepostet wurde.
Könnte man nicht einfach mit Hilfe der eigenen Try-Funktion überprüfen, ob auf eine ungültige Speicheradresse zugegriffen wird?
Wenn beim Aufruf von CallFunctionFast() ein IMA-Fehler auftritt, dann weiß man, dass die übergebene Speicheradresse entweder nicht vorhanden ist oder dass der Pointer nicht auf eine Prozedur zeigt.
Leider kann ich den Thread nicht mehr finden und kann deshalb den Code nicht testen und hier verlinken. Vielleicht findet ihr den Thread.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von NicTheQuick »

Ja, ein Try-Catch wäre Bombe. Ich glaube ganz früher zu PB V2.x Zeiten hatte Rings mal eine Try-Catch-Funktion implementiert. Oder war es Danilo? Ich weiß nicht mehr genau. Das hätte ich jedenfalls auch gerne wieder. Alternativ kann man hier nur noch mit OnError arbeiten.
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von RSBasic »

Ich glaube, bei OnError ist es schon zu spät oder? OnError tritt ja nur dann auf, wenn die Anwendung kurz vorm Abstürzen ist.
Man kann ja danach nicht mehr weiterarbeiten und den Fehler ignorieren.

\\Edit:
Es gibt doch ja schon Defined() und #PB_Procedure. Sowas braucht man nochmal als Funktion mit der Möglichkeit, eine beliebige Speicheradresse zu übergeben. Feature-Request @ PB-Team?
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von NicTheQuick »

Man kann Try-Catch schon simulieren mit OnError():

Code: Alles auswählen

Macro Try(label)
	OnErrorGoto(?label)
	If #True
EndMacro
Macro Catch(label)
	Else
	label:
EndMacro
Macro EndTry()
	EndIf
	OnErrorDefault()
EndMacro

Procedure a()
EndProcedure
Procedure b(a.i)
EndProcedure
Procedure c(a.i, b.s)
EndProcedure

q.q = 123457698123

Try(a)
	CallFunctionFast(@a())
	Debug "a() hat funktioniert."
Catch(a)
	Debug "a(): " + ErrorMessage() + "(@" + Str(ErrorAddress()) + ")"
EndTry()

Try(b)
	CallFunctionFast(@b(), 1)
	Debug "b(1) hat funktioniert."
Catch(b)
	Debug "b(1): " + ErrorMessage() + "(@" + Str(ErrorAddress()) + ")"
EndTry()

Try(c)
	CallFunctionFast(@c(), 1, 2)
	Debug "c(1, 2) hat funktioniert."
Catch(c)
	Debug "c(1, 2): " + ErrorMessage() + "(@" + Str(ErrorAddress()) + ")"
EndTry()

Try(q)
	CallFunctionFast(@q)
	Debug "q hat funktioniert."
Catch(q)
	Debug "q: " + ErrorMessage() + "(@" + Str(ErrorAddress()) + ")"
EndTry()
Wenn mir jetzt noch jemand beibringt, wie ich das mit anonymen Labels machen kann, ist die Library schon so gut wie fertig. :lol:
Ausgabe hat geschrieben:a() hat funktioniert.
b(1) hat funktioniert.
c(1, 2): Segmentation violation(@4406866)
q: Segmentation violation(@6597254)
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Prüfen, ob eine Adresse auf eine Procedure zeigt

Beitrag von ts-soft »

NicTheQuick hat geschrieben:Ja, ein Try-Catch wäre Bombe. Ich glaube ganz früher zu PB V2.x Zeiten hatte Rings mal eine Try-Catch-Funktion implementiert. Oder war es Danilo? Ich weiß nicht mehr genau. Das hätte ich jedenfalls auch gerne wieder. Alternativ kann man hier nur noch mit OnError arbeiten.
Die Try-Catch Lib war von Remi Meyer, in ASM geschrieben und die funktionierte wirklich gut. Es gibt noch weitere Try-Catch Routinen im engl. Forum, aber ich denke die Version von Danilo ist noch am ausgereiftesten, funktioniert leider nicht immer:
http://www.purebasic.fr/english/viewtop ... 39#p380239

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten