Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: [VB.NET] Virheiden tehokas käsittely

Sivun loppuun

ErroR++ [11.04.2012 17:26:36]

#

Moi!

Teen "virtuaalikonetta", joka tulkkaa binäärimuotoista "virtuaalikiintolevyä". Siinä on aika tehokas virheiden käsittely, mutta siinä on parantamisen varaa. Kun virhe jää kiinni Try-Catchissa, se hyppää virheenkäsittelijään joka tekee crashdumpin. Crashdumppiin tallentuu virtuaalikoneen muisti ja prosessorin tila. Muistin viimeisessä alkiossa on virheen tiedot sekä StackTrace. Siihen pitäisi saada myös virheen syy.

Miten tämä onnistuu vai onnistuuko millään?

Grez [11.04.2012 17:59:02]

#

Määrittele "virheen syy". Useinhan jos tietokoneessa ohjelma kaatuu, niin virheen syy on huonossa ohjelmoinnissa. Tämän tai muun varsinaisen syyn saaminen selville ei yleensä ole koneellisesti mahdollista. Eli minkälaista vastausta haetaan kysymykseen "mikä oli virheen syy"?

groovyb [11.04.2012 23:44:27]

#

argumentexception?

Käyt ensin läpi mahdolliset syyt, ja määrität virheelle oman tekstisi.

ErroR++ [12.04.2012 14:42:43]

#

Grez kirjoitti:

Määrittele "virheen syy".

Ainakin tuliko virhe virtuaalisessa tominnassa vai ihan oikeassa toiminnassa (eli vaikka koodissa bugi). Täytyypä määritellä oma exception-luokka...

groovyb kirjoitti:

Käyt ensin läpi mahdolliset syyt, ja määrität virheelle oman tekstisi.

Niin kai.

ErroR++ [13.04.2012 21:30:23]

#

Nyt tein oman exceptionin VCError. Tällä hetkellä crashdumppi näyttää tätä:

VCdmp@mem2790# ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||¿1±black;¿2±gray|

VCErr:
Number 0
Description General error: Object reference not set to an instance of an object.
Infodata Object reference not set to an instance of an object.<fmt>System.NullReferenceException: Object reference not set to an instance of an object.
   at VComputer.VComputer.Screen.keydown(Object sender, KeyEventArgs e) in C:\Users\Pauli\Documents\Visual Studio 2010\Projects\VB\VC\VC\VComputer.vb:line 581
   at System.Windows.Forms.Control.OnKeyDown(KeyEventArgs e)
   at System.Windows.Forms.Control.ProcessKeyEventArgs(Message& m)
   at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.Form.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.DoEvents()
   at VComputer.VComputer.Screen.ScrBIOS.Controller.Update() in C:\Users\Pauli\Documents\Visual Studio 2010\Projects\VB\VC\VC\VComputer.vb:line 631
@reg#0|0|0||

Eli pseudona:

dumppiheaderi, muistimerkintä, dumpin muistiosuuden koko ja muistin sisältöä (viimeiset ekalla rivillä on näyttömuistista eli näytönkontrollointikäskyt)
vika muistialue on errori:
numero 0
selitys virheelle
infodata eli additionaaliset tiedot
callstackki
prosessoritietojen headeri ja prossun rekisterit

Call Stackista näkee mitä kone on tehnyt. Se oli käynnistetty uudestaan ja sen jälkeen kaikki oli tyhjätty. Kun näyttöä päivitetään (viimeinen rivi callstackissa), kutsuttiin Application.DoEvents() -metodia ja se suoritti monimutkaisen toimintasarjan .NET-Frameworkissä. Lopulta päädyttiin näppäimistökäsittelijään, ja siellä yritettiin napsia keycode taullukkoon. Koska koneen uudelleenkäynnistyksessä kaikkiin muuttujiin on sijoitettu nothing, tulee exception.

groovyb [13.04.2012 22:16:42]

#

Eli teitkö näin?

Try

  //jotain


Catch Ex As Exception

  Dim sError = "VCErr: \r\nNumber 0 \r\nDescription General error: " + ex.ToString()
  Throw New ArgumentException(sError)


End Try

Nyt kun lähdetään loggeria tekemään (tai mitä tahansa virheenkäsittelijää/tallentajaa), Olisi aika näppärää saada tietoon mikä metodi/funktio virheen laukaisee (jotta saadaan tietoon missä vaiheessa itse virhe tapahtuu, jotta ei tarvitse sourcea tutkia joka kerta)

Esim tuo yllä oleva esimerkkisi ei kerro mikä virheen triggaa, joten virheen selvitys olisi aika hankalaa.

Catch ex as System.NullReferenceException

//Logger.Log(MyErrorCodes Errorcode, DateTime ErrorTime, string TriggeredBy, string SourceClass, string CallStack)
MyLogger.Log(ErrorCodeEnum.NullReference,DateTime.Now().ToString(),"MyGroovybClass","MyFunction()",ex.ToString())

Log.txt, eventlog, tekstiä ruudulla yms. mihin sitten logger tai virheenkäsittelijä kirjoittaakaan:

VcError: Code 0
Explanation: Null reference Exception Occurred
Source: MyFunction()
Trigged by: MyGroovybClass
TimeStamp: 13.14.2012 22:08
CallStack: Lorem Ipsum


Tästä seuraava porras on lokitustyyppien määrittäminen (esim Information,Warning, Error) ja lokitusasteiden käyttäminen ( Basic | Virheet tallennetaan, Advanced | Virheet ja varoitukset tallennetaan , All | Virheet, varoitukset ja metodi/funktiokutsut tallennetaan ), jotka otetaan käyttöön vaikka sovellusargumentteina.

MyProgram.exe -EnableLog All

13.4.2012 22:08 Information: Program started
13.4.2012 22:08 Information: Checking program settings
13.4.2012 22:08 Information: Entering CheckSettings()
13.4.2012 22:08 Warning: Resolution not set in Settings.ini
13.4.2012 22:08 Error:
VcError: Code 0
Explanation: Null reference Exception Occurred
Source: CheckSettings()
Trigged by: MySettings.Resolution
TimeStamp: 13.14.2012 22:08
CallStack: Lorem Ipsum
13.4.2012 22:08 Information: Exiting CheckSettings()
13.4.2012 22:08 Information: Exiting Program


MyProgram.exe -EnableLog Advanced

13.4.2012 22:08 Warning: Resolution not set in Settings.ini
13.4.2012 22:08 Error:
VcError: Code 0
Explanation: Null reference Exception Occurred
Source: CheckSettings()
Trigged by: MySettings.Resolution
TimeStamp: 13.14.2012 22:08
CallStack: Lorem Ipsum


MyProgram.exe -EnableLog Basic

13.4.2012 22:08 Error:
VcError: Code 0
Explanation: Null reference Exception Occurred
Source: CheckSettings()
Trigged by: MySettings.Resolution
TimeStamp: 13.14.2012 22:08
CallStack: Lorem Ipsum

ErroR++ [14.04.2012 10:45:49]

#

En aivan noin. Mutta tässä on jotakin koodia:

Private Shared Sub POST() 'biosin post-test joka käynnistetään omaan säikeeseensä
            On Error GoTo errHandler 'virheenkäsittely tällä kertaa näin
            'tässä välissä on koodi joka lataa laitteisiin oikeat tiedot filuista
            Memory.PutObject(1024, "POST") : If Not Memory.GetObject(1024) = "POST" Then Console.Beep(750, 250) : ErrorHandler(New VCError(1, "1<fmt>")) 'muistitesti
            Memory.PutObject(0, "init") 'muistiin prosessorin init-käsky joka onkin ainut ei-binäärikäsky
            Processor.Run(0) : If Processor.Initialized = False Then Console.Beep(750, 250) : Console.Beep(750, 250) : ErrorHandler(New VCError(2, "1<fmt>")) 'käsketään prosessorin suorittaa init-käsky
            If DiskCount = 0 Then Console.Beep(750, 2500) : Console.Beep(750, 250) : Console.Beep(750, 250) : ErrorHandler(New VCError(3, "1<fmt>")) 'jos kiintolevyjä 0, tulee virhe
            Memory.PutObject(1, Nothing) 'vlearataan muisti jossa post-testin delegaatti oli
            Data.Booting = True 'bootataan
            Do : Thread.Sleep(2500) : Loop Until Data.Booting = False 'odotetaan muita säikeitä (kello tms.)
            Memory.PutObject(1024, "¿1±black;¿2±gray") '1024 on näyttömuisti
            If Not Data.bdFound Then Memory.PutObject(0, " ") 'jos bootdiskiä ei löydy, haltataan kone
            Processor.Run(0) 'suoritetaan boottisektori/halt-käsky
            Exit Sub 'poistutaan
errHandler: 'jos sattuu jokin muu virhe
            ErrorHandler(New VCError(0, "'" & Err().Description & "' with code " & Err().Number & "<fmt>" & Err().Description)) 'lähetetään se errorHandleriin
        End Sub

Toinen esimerkki:

Public Shared Sub Update() 'Screen.ScrBIOS.Controller.Update()
                    Try
                        g = GetGraphics() 'haetaan graphicsit
                        If Not Processor.Initialized Then 'jos on haltattu
                            _frm.BackgroundImageLayout = ImageLayout.Tile
                            _frm.BackgroundImage = My.Resources.vclogo 'logo näyttöön
                        End If
                        Application.DoEvents()
                        If TypeOf Memory.GetObject(1024) Is Bitmap Then GoTo begindraw
                        If Not cursor Then 'kursori
                            g.DrawString("_", New Font("Courier", 36, FontStyle.Bold), New SolidBrush(clsClr), New Point(scrPos.X + 5, scrPos.Y + 5))
                        End If
begindraw: 'piirto
                        If TypeOf Memory.GetObject(1024) Is Bitmap Then 'bitmappi
                            g.DrawImage(CType(Memory.GetObject(1024), Bitmap), New Point(0, 0)) 'piirretään
                            _frm.Refresh() 'kaksi vähän turhaa kutstua
                            _frm.Update()
                        Else
                            If dt Then g.Clear(clsClr) : scrPos = New Point(5, 5)
                            Dim lines As String = Memory.GetObject(1024).ToString()
                            For Each cmd As String In Split(lines, ";") 'käskyt
                                If cmd = "¿0±" Then scrPos = New Point(5, scrPos.Y + 25) : Continue For 'uusi rivi
                                Select Case Left(cmd, 3)
                                    Case "¿1±" 'cls
                                        scrPos = New Point(5, 5)
                                        clsClr = Color.FromName(Right(cmd, cmd.Length - 3))
                                        g.Clear(clsClr) 'clear screen
                                    Case "¿2±" 'clr
                                        clr = Color.FromName(Right(cmd, cmd.Length - 3)) 'värin vaihto
                                    Case "¿3±" 'print
                                        g.DrawString(Right(cmd, cmd.Length - 3), New Font("Courier", 24), New SolidBrush(clr), scrPos) 'printataan
                                        scrPos = New Point(scrPos.X + cmd.Length * 12 + 12, scrPos.Y)
                                    Case "¿4±" 'dt
                                        dt = Not dt 'joku ihme-drawto-käsky
                                    Case Else
                                        BIOS.ErrorHandler(New VCError(9, cmd & "<fmt>" & cmd)) 'virhe
                                End Select
                            Next
                        End If
                        If TypeOf Memory.GetObject(1024) Is Bitmap Then GoTo enddraw
                        If cursor Then
                            g.DrawString("_", New Font("Courier", 36, FontStyle.Bold), New SolidBrush(clr), New Point(scrPos.X + 3, scrPos.Y)) 'kursori
                        End If
enddraw:
                        cursor = Not cursor
                        _frm.Refresh() 'päivitys
                    Catch ex As Exception 'virhe
                        BIOS.ErrorHandler(New VCError(0, ex.Message & "<fmt>" & ex.ToString())) 'virheenkäsittely
                    End Try
                End Sub

Errorhandleri:

Public Shared Sub ErrorHandler(VCerr As VCError) 'täällä on ehkä liikaa try-catcheja...
            Try
                Memory.PutObject(1025, " ") 'halt varmuuden vuoksi, ettei crashdumpin teko hidastu
                Processor.Run(1025)
            Catch
            End Try
            Try : Memory.PutObject(1025, VCerr.Message) : Catch : End Try 'errorin viesti
            Try
                Thread.Sleep(250)
                Data.RunClock = False 'määritetään kello pois päältä
            Catch
            Finally
                Try
                    Screen.GetForm().BackgroundImage = My.Resources.error_image 'errori-image
                    Screen.GetForm().BackgroundImageLayout = ImageLayout.Stretch 'venytetty kuva
                Catch : End Try
                Try
                    CreateCrashdump(Application.StartupPath & "\crashdump.mem") 'crashdumppi
                    Process.Start(Application.ExecutablePath, "report") 'virheraportti
                    ExitProgram = True 'poistutaan (pääsäie hoitaa homman)
                    Thread.CurrentThread.Suspend() 'pysähdytään
                Catch : End Try
            End Try

VCError -luokka:

Public Class VCError
    Inherits Exception 'exceptioni
    'virheet on listattu järjestyksessä:
    Public ReadOnly ERRs() As String = {"General error: {0}", "Step {0}: POSTErr - MemoryTest", "Step {0}: POSTErr - ProcessorTest", _
                                        "Step {0}: POSTErr - DiskTest", "Step {0}: POSTErr - DiskRWTest", "Step {0}: POSTErr - ScreenTest", _
                                        "ProcessorErr: '{0}' is not valid for the calculate command", "ProcessorErr: {0} is not a valid command", "ScreenErr: {0} is not a valid command"}
    Dim _num As Integer, _id As String 'numero ja infodata ("id")
    Protected msg As String 'viesti on suojattu
    Public Overloads ReadOnly Property Message As String
        Get
            Return msg
        End Get
    End Property
    Public Sub New(num As Integer, infodata As String) 'konstruktori
        MyBase.New()
        msg = "\n\nVCErr:\nNumber " & num & "\nDescription " & String.Format(ERRs(num), infodata.Split("<fmt>")(0) & "\nInfodata " & infodata & "\n" & StackTrace) 'muodostetaan viesti
        msg = Replace(msg, "\n", Global.Microsoft.VisualBasic.vbCrLf) 'korvataan \n:t rivinvaihdoilla
        _num = num
        _id = infodata
    End Sub
End Class

En kaikkea koodia tietenkään laita (niitähän on yli 700 riviä), toivottavasti tuosta ymmärtää oleellisimman :)

ErroR++ [26.04.2012 15:56:32]

#

Löysin yhdestä kirjasta, että virheiden käsittelyn voi tehdä delegaatin ja AppDomain.CurrentDomain.ErrorHandler tai jonkun muun vastaavan avulla.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta