Newsgroup: it.comp.lang.visual-basic
Titolo: Gestione errori aiuto....

Qualcuno mi sa dire se esiste un sistema in visual basic per evitare di
ripetere in ogni sub o function l'istruzione ON ERROR GOTO. Cioč fare in
modo di realizzare una gestione errori standard per tutto il progetto.
Ciao
Veronica

Ti consiglio un programma di nome VBGuard che mette automaticamente la
gestione degli errori in tutte le routine del tuo progetto. Io lo uso da più
di un anno e devo dire che sono molto soddisfatto. Sfortunatamente non so se
esiste ancora in giro. Prova a cercarlo. Esistono comunque programmi
analoghi.
Dario Di Marino

Scusa eh, ma a che ti dovrebber servire una cosa del genere?
Puoi
gestire/creare un errore diverso in ogni sub/funzione, perchè mai vorreti
una gestione d' errori come dici te? Credo che invece sia giusto che ogni
errore viene gestito dove può nascere, e che ogni routine si preoccupi
delle sue cose.
Saluti :))
--------------------------------
Inviato via 
http://usenet.iol.it
 

Perchè si può semplicemente fare un sub..in un modulo che gestista tutti gli
errori (un case inzomma) e poi richiamare solo quel sub in tutte le routine.
In questo modo..quando devi cambiare una cosa....lo fai solo in quel Sub..e
poi non ci pensi +..senza andare a cercare in tutto il programma!


poi non ci pensi +..senza andare a cercare in tutto il programma!
Puoi semplicemente supplire con:
Private Function MiaFunzione(ByVal mioParametro As long) As long
    On Error GoTo eh
    ..... codice della funzione ....
ef:
    .... operazioni di pulizia,  chiusura handles ecc...
    Exit Function
eh:
     Select Case MainErrorHandler(TypeName(Me) & "[MiaFunzione]")     ' restituisce un Enum personalizzato con le opzioni possibili
             Case mehResumeNext : Resume Next
             Case mehResume : Resume
             Case mehExitFunction : Resume ef
            Case mehQuitApp : Call QuitMyApp()   ' tua routine di shutdown dell' applicazione
            Case mehWriteMail : .... manda una mail all' assistenza
             Case mehKillDeveloper:  ... meglio che non succeda :)
            ecc.
      End Select
End Function
Public Function MainErrorHandler (ByVal a_strNomeFunzione As String) As MainErrorHandlerEnum
        // qui dentro va la gestione centralizzata che desideri
End Function
ciao, hal

modo di realizzare una gestione errori standard per tutto il progetto.
Ma non ti si era già risposto a questa domanda?
Occhio, che una cosa come la vuoi tu non esiste, e qualsiasi accrocchio che
ci si avvicini è potenzialmente instabile e pericoloso.
Sono d'accordo con Skunk: ogni routine dovrebbe gestire i suoi errori a modo
suo (pur mantenendo il concetto di base: vedi mia risposta alla tua domanda
di qualche giorno fa).
Ciao

Sub..e poi non ci pensi +..senza andare a cercare in tutto il programma!
Bhè, perchè cercare in tutto il codice, aggiungi un file di risorse, li ci
metti tutti gli errori, a ognuno assegni un numero che vuoi te, dichiari
tante costanti quanti sono gli errori, in ogni routine usi la costante di
ua pertinenza e via. Una cosa tipo res_ErrOpenDatabase...
Se si genere aun
errore vai a vedere solo li, perchè te che crei gli errori dovresti farli
parlanti, se non per l' utente che li vede almeno per te che hai
programmato il tutto :)) L' errore Open Database non è che si può generare
alla pressione del tasto...iconizza il form :)) In questo caso invece,
eviti di doverti spulciare ogni volta per ogni errore un case, come dici
te...e se il tuo programma gestisce qualcosa tipo un centinaio di errori?
Per ogni errore devi leggerti cento condizioni quando te sai già a priori
qual'è quella giusta.
Secondo me non è un buon metodo fare una
funzione/case/sub o quel è generale a tutto il programma.
Saluti...


funzione/case/sub o quel è generale a tutto il programma.
Concordo.
Quello che e' utile generalizzare e' la reazione all' errore quando vengono
visualizzati i messaggi.
Cio' si rivela molto utile in fase di test perche' si possono mostrare messaggi molto circostanziati
che vengono facilmente sostituiti in produzione con messaggi piu' sintetici.
In ogni caso, ritengo che la gestione (e non la visualizzazione dei messaggi e l' eventuale produzione
di file di log) sia una storia se' per ogni funzione.
ciao, hal

 ci si avvicini è potenzialmente instabile e pericoloso.
Non sono d'accordo.
La gestione errori va decisa routine per routine quando hai le idee chiare
sul tipo di errore che ti può capitare. Ad esempio quando usi un
commondialog è giusto usare la gestione errori per intercettare l'eventuale
annulla.
Ma durante la normale esecuzione del codice ti possono capitare molte
tipologie di errore standard. Ad esempio può finire lo spazio su disco,
oppure può rovinarsi un MSB, oppure puo uscire dalla rete la macchina sul
cui disco condiviso stavi lavorando.
In questi casi è assurdo doversi scrivere una gestione degli errori per ogni
routine. Molto meglio avere una gestione errori standard che esegua delle
operazioni predefinite nei suddetti casi.
Altro problema sono gli errori imprevedibili. Per quante ne pensi, nel
codice possono nascondersi sempre bachi imprevisti. In questi casi è comodo
avere una gestione errori standard che trappi l'errore e ti scriva in un
logfile cosa è successo e dove.
Per entrambe queste esigenze, si usano normalmente dei programmi che ti
modificano il sorgente aggiungendo la gestione errori a posteriori. Io
stesso me ne ero scritto uno, che per ogni routine e funzione inserisce
all'inizio una On Erroro goto GestioneErroriStandard (e che corregge allo
stesso modo gli On Erroro Goto 0), e alla fine inserisce una label
GestioneErroriStandard che chiama una funzione di GestioneErroriGenerica
passandogli come parametro il nome della routine e l'errore.
Questa funzione scrive su di un file di log l'errore e, se l'errore non è
troppo grave, chiede all'utente se vuole riprovare o terminare il programma.
In questo modo l'utente può (nell'esempio del disco pieno) liberare spazio
su disco e continuare l'elaborazione, senza perdere il lavoro effettuato
fin'ora.
Ciao
*Roby*


[snip]
Sě, hai ragione.
Questo va bene, ma ciň non toglie che
(1) va fatto comunque routine per routine.
(2) la logica č la stessa che uso io.
(3) occorre comunque ricordarsi di "ripulire" la situazione prima di
chiamare la tua routine, e questo lo devi fare a mano!
Es.
On Error Goto Errore:
    Open miofile for binary as #1
        Get #1,0,a 'errore: numero di record non valido
    Close #1
Errore:
    Call MiaRoutineDiGestione
Una cosa del genere bloccerebbe definitivamente il file #1, e qualsiasi
altro tentativo di accesso andrebbe in errore a sua volta.
Va comunque fatto un minimo di manutenzione:
On Error Goto Errore:
    Open miofile for binary as #1
        Get #1,0,a 'errore: numero di record non valido
Errore:
    Close #1
    if (Err.Number <> 0) then
        Call MiaRoutineDiGestione
    end if
Ciao

 chiamare la tua routine, e questo lo devi fare a mano!
Riprendo il tuo esempio ed inserisco la gestione degli errori come la
metterebbe il mio programmino automatico:
- . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -
. - . - . - .
Function ApriFileConErrore (sNomeFIle as String) as boolean
On Error GoTo label_GestErrore ' automatico
     Open miofile for binary as #1
         Get #1,0,a 'errore: numero di record non valido
     Close #1
ApriFileConErrore  = True
Exit Function
' Inizio gestione errori standard inserita in automatico
label_GestErrore:
Select Case GestioneErroriGlobale("ApriFileConErrore", _
                                                    Err.Number, _
                                                    Err.Description)
   Case vbIgnore
      Resume Next
   Case vbRetry
      Resume
   Case Else
      EsciDalProgramma
End Select
End function
Public Function GestioneErroriGlobale(NomeFunzione As String, _
                                              CodiceErrore As Long, _
                                              StringaErrore As String) As
Integer
Dim sErrore as string
Dim sErroreLog as string
   sErroreLog = "Routine: <" & NomeFunzione & "> - Errore: <" & _
                     CodiceErrore & ">"
   sErrore = "Routine: <" & NomeFunzione & _
                 "> - Codice problema = <" & CodiceErrore & ">"
   ScriviLogFile(ErroreLog)
   GestioneErroriGlobale = MsgBox(Errore, vbAbortRetryIgnore)
End function
- . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -
. - . - . - .
Per brevità non ho inserito la funzione ScriviLogFile (banale) e la
EsciDalProgramma (per semplicità potremmo considerarla un "end"). Manca
inoltre la gestione degli errori nella GestioneErroriGlobale e la gestione
di una eventuale rientranza per un errore (ad esempio) durante la
ScriviLogFile.
In ogni caso la logica è questa. A parte i casi specifici, questo approccio
copre tutte le esigenze.
Ciao
*Roby*


Mi lascia molto perplesso.
L'uso dei resume generalizzato intendo.
Poi in genere una routine o va in errore, o esce senza dire e fare niente.
Nel tuo esempio come faccio a dire: "va bene, non fare niente che voglio
fare altro"?
Mi sembra un retaggio di vecchi programmi dos+qbasic...
Ciao.

Mi sembra un retaggio di vecchi programmi dos+qbasic...
Supponi di mostrare all' utente un messaggio che spiega cosa sia successo
e di offrirgli diverse alternative.
Nei casi di file non trovato, floppy o cd-rom non inserito, linea telefonica occupata
(e altri ancora) l' istruzione Resume ha senso, eccome !
L' utente gradisce di poter rimediare a tali errori senza ripetere la successione di
operazioni che lo ha portato fino li'.
ciao, hal

operazioni che lo ha portato fino li'.
Sì, ma come dicevo, occorre distingure i livelli di lavoro.
Ciao

 imprevedibili e difficili da debuggare.
Ma tu come ti regoli per gestire eventi imprevisti come lo spegnimento di
una macchina che ha un disco condiviso su cui sta accedendo il tuo
programma, oppure la fine dello spazio su disco?
La maggior parte dei programmi che ho visto io, semplicemente ignorano
questi casi perchè li reputano improbabili e non meritevoli di gestirli ad
ogni accesso al disco. Con la gestione errori in automatico invece li
gestisco senza nessuno sforzo, e se mi chiama un cliente per dirmi che il
programma gli è uscito con errore, mi faccio mandare il log-file in modo da
sapere cosa ha combinato (se no di solito l'utente non si ricorda mai
esattamente l'errore).
Meglio di così... 8-)
Unico problema, l'eseguibile diventa un po' più grande perchè viene inserita
la parte di codice della gestione errori in ogni routine, anche in quelle da
una singola riga. Ma questo non è un gran problema.
Inoltre un altro vantaggio di far processare il proprio sorgente da un
postprocessore è la possibilità di cambiare al volo codice potenzialmente
pericoloso. Ad esempio io gli faccio modificare tutte le occorrenze di
Oggetto.setFocus con la chiamata ad una funzione SettaIlFocus(Oggetto) che
ignora il possibile errore che può capitare se l'oggetto è disabilitato o
invisibile. Questo è utile soprattutto quando il codice è scritto a più mani
e non tutti seguono le stesse regole.
Ciao
*Roby*