Seite 2 von 4

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

Verfasst: 09.10.2015 00:00
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

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

Verfasst: 09.10.2015 08:55
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....

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

Verfasst: 09.10.2015 09:21
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. ;-)

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

Verfasst: 09.10.2015 09:43
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 

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

Verfasst: 09.10.2015 11:40
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.

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

Verfasst: 09.10.2015 11:49
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.

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

Verfasst: 09.10.2015 12:20
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.

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

Verfasst: 09.10.2015 12:27
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?

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

Verfasst: 09.10.2015 12:53
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)

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

Verfasst: 09.10.2015 13:01
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