| 
				
					|  | Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
 |  
 
	
		| Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |  
  | 
 
	  
		| Sind diese Makros nützlich? |  
		| 
			
			  | Ja |  | 100% | [ 3 ] |  
			  | Nein |  | 0% | [ 0 ] |  
			  | Ich verstehe ihren Sinn nicht |  | 0% | [ 0 ] |  |  
		| Stimmen insgesamt : 3 |  
 |  
		| Autor | Nachricht |  
		| Cherry 
 
 
 Anmeldungsdatum: 20.06.2007
 Beiträge: 249
 
 
 | 
			
				|  Verfasst am: 01.06.2009, 13:22    Titel: [Makro-Vorstellung] Fehlerbehandlung mit Try/Catch/Finally |   |  
				| 
 |  
				| Hallo! 
 Ich habe einige Makros erstellt, mit denen man Try/Catch/Finally-Blöcke umsetzen kann. Leider muss man für jeden Try-Block einen Namen vergeben, da ich keine Möglichkeit gefunden habe, einen Zähler und einen Stack mit dem Preprozessor umzusetzen...
 
 Falls es jemand nicht weiß: Try/Catch/Finally dient dazu, Fehler aufzufangen (entweder selbst erzeugte oder solche wie Access Violations (ungültige Speicherzugriffe) u.ä.). Wenn innerhalb eines Try-Blocks ein Fehler auftritt, wird zum entsprechenden Catch-Block gesprungen, oder, wenn kein passender existiert, zu dem des nächst höheren Try-Blocks. Beim Verlassen des Try-Blocks, egal ob ein Fehler auftrat oder nicht, wird der Finally-Code ausgeführt (z.B. zum Schließen von Dateien).
 
 Try(name) : Startet einen Try-Block
 
 Catch(name, exception codes) : Fängt einen oder meherere Fehler auf. Für "exception codes" können die Werte genauso wie bei "Case" von FreeBasic angegeben werden, allerdings muss statt einen Komma "__" (2x Unterstrich) verwendet werden.
 Beispiele:
 
  	  | Code: |  	  | Catch(name, EXCEPTION_ACCESS_VIOLATION) Catch(name, EXCEPTION_ACCESS_VIOLATION __ EXCEPTION_INT_DIVIDE_BY_ZERO)
 Catch(name, Is <> EXCEPTION_INVALID_INSTRUCTION)
 Catch(name, &hC0000000 To &hC000FFFF)
 Catch(name, Else) ; fängt alle anderen Fehler auf
 | 
 Eine Liste der Windows-Fehler gibt es hier: http://xurl.sh/exceptioncodes
 
 Finally(name) : Code ab dieser Stelle wird immer ausgeführt, auch wenn ein Fehler auftrat.
 
 EndTry(name) : Beendet einen Try-Block
 
 Leave(name) : Führt den Finally-Code aus. Leave kann z.B. aufgerufen werden, wenn mittels Return, Exit Sub o.ä. außerhalb des Try-Blocks gesprungen wird.
 
 ExitTry(name) : Führt den Finally-Code aus und verlässt den Try-Block
 
 Innerhalb des Catch-Codes können außerdem folgende Variablen genutzt werden:
 
 ECode : gibt den Exception Code zurück
 
 EAddress : gibt die Adresse, an der die Exception auftrat, zurück
 
 ENumParams : gibt die Anzahl der Parameter zurück
 
 EParamsPtr : Pointer auf das Parameter-Array
 
 EParams(i) : Gibt den Parameter Nummer i zurück (beginnt bei 0). Bei ungültigen Nummern wird 0 zurückgegeben. Bei dem Fehler EXCEPTION_ACCESS_VIOLATION enthält EParams(1) die Adresse, auf die zugegriffen wurde, und EParams(0) gibt an, ob gelesen (0) oder geschrieben (1) wurde.
 
 ERecord : Pointer auf den EXCEPTION_RECORD des Fehlers.
 
 EContext: Pointer auf den CONTEXT des Fehlers.
 
 Um selbst Exceptions zu erzeugen, können diese beiden Befehle genutzt werden:
 
 Raise(exception code) : Wirft eine Exception ohne Parameter
 
 RaiseParam(exception code, anzahl parameter, parameter) : Wirft eine Exception mit Parameter. Die Parameter (Integers) werden mit "__" getrennt.
 
 Zu Beachten ist, dass Bit 28 immer auf 0 gesetzt wird, da es von Windows intern verwendet wird. Der Exception Code sollte auch folgende Regeln befolgen:
 Bits 31-30 : 0=Erfolg, 1=Information, 2=Warnung, 3=Fehler
 Bit 29 : 0=Microsoft, 1=Eigenes Programm
 Bit 28 : Muss 0 sein
 Bit 27-0 : Eigentlicher Code
 Ein typischer Exception Code wäre z.B. &hE0000100 (Fehler, Eigenes Programm, Code &h100).
 
 Beispiel:
 
  	  | Code: |  	  | #Include "windows.bi" #Include "exceptions.bi"
 
 Declare Sub Test1()
 Declare Sub Test2()
 
 Print "Bevor Test1()"
 Test1()
 Print "Nach Test1()"
 
 Try(orange)
 Print "in Try(orange)"
 Print "Bevor Test2()"
 Test2()
 Catch(orange, &hE0012345 __ &hE0012346)
 Print "Fehler E0012345 oder E0012346 aufgetreten! Gefangen von orange."
 EndTry(orange)
 Print "Nach Test2()"
 
 Sleep
 
 Sub Test1()
 Try(apfel)
 Print "in Try(apfel)"
 Print "jetzt machen wir mal eine Access Violation!"
 Print "Zugriff auf ungültigen Pointer!"
 Dim x As Integer Ptr = 222
 *x = 0
 Print "Dies sollte nie erscheinen!"
 Catch(apfel, EXCEPTION_INT_DIVIDE_BY_ZERO)
 Print "Division durch 0! Dies sollte nie erscheinen!"
 Catch(apfel, EXCEPTION_ACCESS_VIOLATION)
 Print "Ohje, ein Fehler!"
 Print "Code: " & Hex(ECode)
 Print "an Adresse: " & Hex(EAddress)
 Catch(apfel, Else)
 Print "alle sonstigen Fehler würden hier aufgefangen werden"
 Finally(apfel)
 Print "Dieser Code wird immer ausgeführt, egal ob ein Fehler auftrat oder nicht."
 Print "Hier könnte z.B. ""Close #1"" stehen, oder ""Delete blub""."
 EndTry(apfel)
 
 Print "Nun außerhalb von Try(apfel)!"
 
 Do
 Try(birne)
 Print "in Try(birne)"
 Print "jetzt verlassen wir den Try- und den Do-Block rundherum, mit ""Exit Do""."
 Print "vorher führen wir noch ""Leave(birne)"" aus, so wird der Finally-Code auch ausgeführt."
 Leave(birne): Exit Do
 Print "Dies sollte nie erscheinen!"
 Finally(birne)
 Print "in Finally(birne)!"
 EndTry(birne)
 Loop
 
 Print "Nun wieder außerhalb von Try(birne)!"
 End Sub
 
 Sub Test2()
 Try(pfirsich)
 Print "in Try(pfirsich)"
 Print "nun werfen wir mal den Fehler E0012345"
 Print "pfirsich fängt aber nur EXCEPTION_INT_DIVIDE_BY_ZERO!"
 Print "also sollte es an orange weitergegeben werden"
 Raise(&hE0012345)
 Print "Dies sollte nie erscheinen!"
 Catch(pfirsich, EXCEPTION_INT_DIVIDE_BY_ZERO)
 Print "Division durch 0! Dies sollte nie erscheinen!"
 Finally(pfirsich)
 Print "in Finally(pfirsich)"
 EndTry(pfirsich)
 Print "Außerhalb von Try(pfirsich)"
 End Sub
 
 | 
 
 Hier nun die exceptions.bi:
 
  	  | Code: |  	  | #Ifndef EXCEPTION_RECORD #Error Please include windows.bi first!
 #EndIf
 #Ifndef __FB_WIN32__
 #Error Operating system not supported!
 #EndIf
 
 #Macro __trycheck(_name_)
 #Ifndef __eh_##_name_##_try_set
 #Error Undefined Try block name: _name_
 #EndIf
 #EndMacro
 
 #Macro Try(_name_)
 #Ifdef __eh_##_name_##_try_set2
 #Error Duplicated definition: _name_
 #EndIf
 #Define __eh_##_name_##_try_set
 #Define __eh_##_name_##_try_set2
 Scope
 Dim As Byte __eh_##_name_##_doret = 0
 Dim As Any Ptr __eh_##_name_##_ehesp = 0
 Dim As Byte __eh_##_name_##_ehandled = 0
 Dim As Byte __eh_##_name_##_wasincatch = 0
 Dim As EXCEPTION_RECORD Ptr __eh_##_name_##_erec = 0
 Dim As Byte __eh_##_name_##_erecarr(SizeOf(EXCEPTION_RECORD))
 Dim As Byte __eh_##_name_##_econarr(SizeOf(CONTEXT))
 Asm
 __eh_##_name_##_try:
 pushad
 mov esi, offset __eh_##_name_##_except
 push esi
 push dword ptr fs:[0]
 mov dword ptr fs:[0], esp
 End Asm
 Scope
 #EndMacro
 
 #Macro __catch_codestart(_name_)
 End Scope
 #Define __eh_##_name_##_except_set
 Asm
 jmp __eh_##_name_##_finally_continue
 __eh_##_name_##_except:
 mov eax, [esp + 4]
 mov eax, [eax + 4]
 cmp eax, 2
 jne __eh_##_name_##_nounwind
 mov byte ptr [__eh_##_name_##_doret], 1
 call __eh_##_name_##_finally
 mov eax, 1
 ret
 __eh_##_name_##_nounwind:
 mov eax, esp
 mov esp, [esp + 8]
 pop dword ptr fs:[0]
 mov [esp], eax
 add esp, 4
 popad
 mov eax, [esp - 36]
 mov [__eh_##_name_##_ehesp], eax
 mov edx, eax
 End Asm
 Scope
 Dim As EXCEPTION_RECORD Ptr ERecord
 Dim As CONTEXT Ptr EContext
 #Define ECode (ERecord->ExceptionCode)
 #Define EAddress (ERecord->ExceptionAddress)
 #Define ENumParams (ERecord->NumberParameters)
 #Define EParamsPtr CPtr(Integer Ptr, (@ERecord->ExceptionInformation(0)))
 Asm
 push edx
 mov edx, [edx + 8]
 mov [EContext], edx
 pop edx
 mov edx, [edx + 4]
 mov [ERecord], edx
 End Asm
 #Define __ersize (SizeOf(EXCEPTION_RECORD) + ERecord->NumberParameters * 4 - 4)
 #Define __erarrsize (UBound(__eh_##_name_##_erecarr) + 1)
 CopyMemory(Cast(Any Ptr, @__eh_##_name_##_erecarr(0)), Cast(Any Ptr, ERecord), IIf(__ersize <= __erarrsize, __ersize, __erarrsize))
 #Undef __erarrsize
 #Undef __ersize
 ERecord = Cast(EXCEPTION_RECORD Ptr, @__eh_##_name_##_erecarr(0))
 __eh_##_name_##_erec = ERecord
 CopyMemory(Cast(Any Ptr, @__eh_##_name_##_econarr(0)), Cast(Any Ptr, EContext), UBound(__eh_##_name_##_econarr) + 1)
 EContext = Cast(CONTEXT Ptr, @__eh_##_name_##_econarr(0))
 Select Case ECode
 #EndMacro
 
 #Define EParams(_i_) IIf(EParamsPtr <> 0 AndAlso _i_ < ENumParams, (EParamsPtr)[_i_], 0)
 
 #Macro __catch_next(_name_, _ecode_)
 #Define __ ,
 Case _ecode_
 #Undef __
 Asm mov byte ptr [__eh_##_name_##_ehandled], 1
 Asm mov byte ptr [__eh_##_name_##_wasincatch], 1
 #EndMacro
 
 #Macro Catch(_name_, _ecode_)
 __trycheck(_name_)
 #Ifdef __eh_##_name_##_finally_set
 #Error Using Catch after Finally not allowed!
 #EndIf
 #Ifndef __eh_##_name_##_except_set
 __catch_codestart(_name_)
 #EndIf
 __catch_next(_name_, _ecode_)
 #EndMacro
 
 #Macro Finally(_name_)
 #Ifdef __eh_##_name_##_finally_set
 #Error Multiple Finally statements not allowed!
 #EndIf
 __trycheck(_name_)
 #Ifndef __eh_##_name_##_except_set
 Catch(_name_, 0)
 __eh_##_name_##_ehandled = 0
 #EndIf
 End Select
 End Scope
 #Define __eh_##_name_##_finally_set
 Asm
 mov byte ptr [__eh_##_name_##_doret], 0
 __eh_##_name_##_finally:
 End Asm
 Scope
 Select Case 0
 Case 0
 #EndMacro
 
 #Macro Leave(_name_)
 __trycheck(_name_)
 Asm
 mov byte ptr [__eh_##_name_##_doret], 1
 call __eh_##_name_##_finally
 End Asm
 #EndMacro
 
 #Macro EndTry(_name_)
 __trycheck(_name_)
 #Ifndef __eh_##_name_##_except_set
 Catch(_name_, 0)
 __eh_##_name_##_ehandled = 0
 #EndIf
 #Ifndef __eh_##_name_##_finally_set
 Finally(_name_)
 #EndIf
 End Select
 End Scope
 Asm
 cmp byte ptr [__eh_##_name_##_doret], 0
 je __eh_##_name_##_noret
 ret
 __eh_##_name_##_noret:
 cmp byte ptr [__eh_##_name_##_ehandled], 0
 jne __eh_##_name_##_continue
 mov esp, [__eh_##_name_##_ehesp]
 End Asm
 RaiseException(__eh_##_name_##_erec->ExceptionCode, __eh_##_name_##_erec->ExceptionFlags, __eh_##_name_##_erec->NumberParameters, @__eh_##_name_##_erec->ExceptionInformation(0))
 Asm
 int3
 __eh_##_name_##_finally_continue:
 mov byte ptr [__eh_##_name_##_doret], 1
 call __eh_##_name_##_finally
 pop dword ptr fs:[0]
 add esp, 36
 jmp __eh_##_name_##_end_try
 __eh_##_name_##_continue:
 cmp byte ptr [__eh_##_name_##_wasincatch], 1
 je __eh_##_name_##_end_try
 pop dword ptr fs:[0]
 add esp, 36
 __eh_##_name_##_end_try:
 End Asm
 End Scope
 #Undef __eh_##_name_##_try_set
 #EndMacro
 
 #Macro ExitTry(_name_)
 __trycheck(_name_)
 Leave(_name_)
 Asm jmp __eh_##_name_##_end_try
 #EndMacro
 
 #Macro RaiseParam(_ecode_, _nump_, _params_)
 Scope
 #Define __ ,
 Dim __params(_nump_ - 1) As Integer = {_params_}
 #Undef __
 RaiseException(_ecode_, 0, _nump_, @__params(0))
 End Scope
 #EndMacro
 
 #Macro Raise(_ecode_)
 RaiseException(_ecode_, 0, 0, 0)
 #EndMacro
 
 | 
 
 Viel Spaß!
 
 mfG Cherry
 
 Zuletzt bearbeitet von Cherry am 02.01.2012, 21:44, insgesamt 2-mal bearbeitet
 |  |  
		| Nach oben |  |  
		|  |  
		| Cherry 
 
 
 Anmeldungsdatum: 20.06.2007
 Beiträge: 249
 
 
 | 
			
				|  Verfasst am: 10.06.2009, 17:44    Titel: |   |  
				| 
 |  
				| Wundert mich, dass das keinen interessiert. Falls man dachte, es handle sich um eine Anfrage, hab ich mal den Titel geändert. |  |  
		| Nach oben |  |  
		|  |  
		| nemored 
 
  
 Anmeldungsdatum: 22.02.2007
 Beiträge: 4710
 Wohnort: ~/
 
 | 
			
				|  Verfasst am: 10.06.2009, 18:01    Titel: |   |  
				| 
 |  
				| Muss ganz ehrlich sagen, dass ich noch nie wirklich mit Try/Catch gearbeitet habe (vom Abtippen einiger Testcodes abgesehen) und es daher bisher auch (noch?) nicht vermisse. 
 (Abgesehen davon interessieren mich windowsspezifische Fragen sowieso nicht so sehr
  ) _________________
 Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1.
 |  |  
		| Nach oben |  |  
		|  |  
		| St_W 
 
  
 Anmeldungsdatum: 22.07.2007
 Beiträge: 958
 Wohnort: Austria
 
 | 
			
				|  Verfasst am: 10.06.2009, 21:19    Titel: |   |  
				| 
 |  
				| Ich finde das Try-Catch-Finally einfach toll und hab in FB auch schon öfters eine ordentliche Fehlerbehandlung vermisst (das Programm läuft ja einfach weiter, wie wenn nichts gewesen wäre). 
 Ich habe jetzt deine Makros noch nicht ausprobiert, werde dies aber sicher in nächster Zeit einmal tun, wenn ich Zeit habe.
 
 Ich hoffe, dass der Compiler selbst einmal eine solche Fehlerbehandlungsroutine bietet - ohne zusätzliche Makros. Funktionen, die der Compiler nativ unterstützt sind mir nämlich meist lieber, als so halbe Lösungen (sorry Cherry, nichts gegen dich und dein Werk - das weiß ich natürlich zu schätzen).
 _________________
 Aktuelle FreeBasic Builds, Projekte, Code-Snippets unter http://users.freebasic-portal.de/stw/
 http://www.mv-lacken.at Musikverein Lacken (MV Lacken)
 |  |  
		| Nach oben |  |  
		|  |  
		| Cherry 
 
 
 Anmeldungsdatum: 20.06.2007
 Beiträge: 249
 
 
 | 
			
				|  Verfasst am: 10.06.2009, 22:38    Titel: |   |  
				| 
 |  
				| Hm, vllt sollte ich das noch erweitern, sodass es auch FreeBASIC-Fehler abfängt. |  |  
		| Nach oben |  |  
		|  |  
		| Cherry 
 
 
 Anmeldungsdatum: 20.06.2007
 Beiträge: 249
 
 
 | 
			
				|  Verfasst am: 06.09.2010, 21:00    Titel: |   |  
				| 
 |  
				| Ich hab grade bemerkt, dass das "+ &hC000" bei "Dim As Byte __eh_##_name_##_erecarr(SizeOf(EXCEPTION_RECORD) + &hC000)" sinnlos ist, und nur leichter zu einem Stack Overflow bei verschachtelten Try-Blöcken führt. Ich habe das damals irrtümlich eingebaut, weil ich nicht mitbekommen habe, dass die maximale Anzahl an Fehlerparametern sowieso fix ist. 
 Daher hab ichs jetzt entfernt.
 |  |  
		| Nach oben |  |  
		|  |  
		|  |  
  
	| 
 
 | Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten.
 Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
 Du kannst deine Beiträge in diesem Forum nicht löschen.
 Du kannst an Umfragen in diesem Forum nicht mitmachen.
 
 |  |