Programm gegen Fehlbedienung absichern

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Programm gegen Fehlbedienung absichern

    Hallo,
    ich möchte ein Programm schreiben welches die Daten von Messgeräten auslesen und dann anzeigen soll. Das Gerät soll dabei vom PC aus ferngesteuert werden. Die Kommunikation erfolgt über den Messgerätebuss GPIB und als zugehörige Bibliothek wird die VISA-Bibliothek von Keysight verwendet.
    Ich frage mich aber, wie der Code am besten gegen Fehlebedienung abgesichert werden kann. Hierzu bitte ich um Hilfe. Folgende Fehlersituationen kann ich mir vorstellen:
    - Notwendige Bibliotheken sind nicht installiert
    - Das Massgerät ist ausgeschaltet
    - Die falsche Messgeräteadresse wurde gewählt. Also irgendein Grund, bei dem Die Kommunikation fehlschlägt.
    Die Fehlermeldungen für zwei Fehlerzustände habe ich als Bild angehängt. Solche Fehler können passieren und müssen irgendwie abgefangen werden.

    Zur Information habe ich noch ein Bild angehängt, wie ich die Bibliotheken eingebundne habe. Ob das der elegante Weg ist, kann ich nicht abschätzen. Die Bibliothek sollten nur so eingebunden werden, dass das Programm auch dann läuft, wenn auf einem fremden Rechner die Bibliothekenüber die Herstellerroutine eingebunden installiert worden sind (So habe ich es auch gemacht - unter Win10).

    Hier zwei Unterprogramme. Im ersten wird nur die Herstellerkennung abgefragt In dem zweiten Unterprogramm wird von einem Spektrum Analyser (Hochfrequenzmessgerät zur Erfassung und Darstellung eines Signals im Frequenzbereich) eine Messung durchgeführt und die Messdaten eingelesen. In einem späteren Schritt werden sie dann grafisch dargestellt. Hierzu habe ich Bild von meinem Testprogramm hochgeladen.
    Rechnerumgebung: Windows 10 und Visual Studio 2019

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim ioMgr As Ivi.Visa.Interop.ResourceManager
    3. Dim instrument As Ivi.Visa.Interop.FormattedIO488
    4. Dim idn As String
    5. ioMgr = New Ivi.Visa.Interop.ResourceManager
    6. instrument = New Ivi.Visa.Interop.FormattedIO488
    7. instrument.IO = CType(ioMgr.Open("GPIB0::20::0::INSTR"), Ivi.Visa.Interop.IMessage)
    8. instrument.WriteString("*IDN?")
    9. idn = instrument.ReadString()
    10. MsgBox("The IDN String is: " & idn, vbOKOnly, "IDN Result")
    11. 'Muss hier nicht auch das "instrument" wieder geschlossen werden?
    12. End Sub
    13. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    14. Dim ioMgr As Ivi.Visa.Interop.ResourceManager
    15. Dim instrument As Ivi.Visa.Interop.FormattedIO488
    16. Dim idnItems As Object() 'Ist das richtig????
    17. Dim idnItem As Object 'Ist das richtig????
    18. Dim n As Integer
    19. Dim messwerte(1000) As String
    20. ioMgr = New Ivi.Visa.Interop.ResourceManager
    21. instrument = New Ivi.Visa.Interop.FormattedIO488
    22. instrument.IO = CType(ioMgr.Open("GPIB0::20::1::INSTR"), Ivi.Visa.Interop.IMessage)
    23. instrument.WriteString("SPECtrum:FREQuency:STARt ” + "5E+07")
    24. instrument.WriteString("SPECtrum:FREQuency:STOP ” + "1.5E+08")
    25. instrument.WriteString("INITIATE:SPECtrum”)
    26. instrument.WriteString("READ:ARRAY:SPECTRUM:CURRENT?”)
    27. idnItems = CType(instrument.ReadList(Ivi.Visa.Interop.IEEEASCIIType.ASCIIType_Any, “,”), Object())
    28. 'idnItems = CType(instrument.ReadList(), Object()) ' geht auch
    29. For Each idnItem In idnItems
    30. n = n + 1
    31. messwerte(n) = idnItem.ToString
    32. Next idnItem
    33. Dim sResult As String = ""
    34. For Each elem As String In messwerte
    35. sResult &= elem & " "
    36. Next
    37. MsgBox(sResult) 'Hier fehlt noch die Ausgabe im Diagramm
    38. End Sub

    Bilder
    • Fehlerzustände.png

      100,68 kB, 1.072×728, 97 mal angesehen
    • Libs2.png

      89 kB, 1.433×780, 91 mal angesehen
    • Testprogramm.png

      84,81 kB, 1.443×473, 87 mal angesehen
    Wenn Du die Fehler nicht durch einfache Boolean-Tests à la

    VB.NET-Quellcode

    1. If Not instrument.IsConnected Then MessageBox.Show("nicht verbunden"): Return
    abfangen kannst*, gibt es Try-Catch. Aber: nutze die auftretenden Compilermeldungen, um ganz konkret die angegebenen Exceptions abzufangen:

    VB.NET-Quellcode

    1. Try
    2. instrument.WriteString("*IDN?")
    3. Catch Ex As System.Runtime.InteropServices.COMException
    4. MessageBox.Show("nicht verbunden")
    5. Return
    6. End Try

    siehe auch: Fange nur Exceptions ab, die Du kennst und sinnvoll bearbeiten kannst.

    * da musst Du in der Bibliotheksdoku oder Objectbrowser schauen, ob es eine Möglichkeit gibt, den Verbindungsstatus abzufragen

    ##########

    Bevor Du weitermachst, bitte die empfohlenen VS-Einstellungen verwenden. Stichwort MsgBox. Welchen Typ gibt denn eigentlich ReadList wieder und sind es ggf. einfach nur Strings, was der weitere Code vermuten lässt?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    @egon Klasse Fragestellung. :!:
    Das allesa musst Du ausprobieren und dann im Programm feststellen, wo es klemmt,
    Und statt einer Exception kommen zu lassen musst Du eine sinnige MessageBox anzeigen.
    Wenn eine DLL fehlt sollte dsas Programm erst gar nicht starten.
    Die von Dir vorgestellten Fehlersituationen sind noch nicht mal die Spitze vom Eisberg.
    "Spiele" mindestens eine Woche mit dem Gerät und lass dabei alles mögliche weg und sorge dann dafür, dass Dein Programm sich sinnvoll verhält.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Danke für die schnellen Antworten. Ich werde versuchen alles umzusetzen. Wie test ich aber, ob eine Bibliothek überhaupt installiert ist. Ich vermut, dass es die Lizenzbedingungen es nicht zulassen, dass die Bibliothek meinem Programm beigefügt ist - daher nur der notwendige Test auf Exixtens.
    Meine Idee wäre "Try-Catch" mit einem unwichtigen Befehl der beiden Bibliotheken.

    Nun habe ich noch eine Frage, habe aber die richtigen Fachwörter wieder vergessen.
    Was mache ich an dieser Stelle genau:
    Dim ioMgr As Ivi.Visa.Interop.ResourceManager
    Dim instrument As Ivi.Visa.Interop.FormattedIO488
    Muss ich am Ende der Sub das "instrument" wieder schließen?
    Sobald ich einen Bibliotheksbefehl absetze, ohne die Bibliothek zu haben, kommt bei mir ne System.IO.FileNotFoundException. Von daher kannst Du hier tatsächlich Try-Catch nutzen. Oder eben ein einfacher IO.File.Exists(PfadZurBibliothek)-Test.

    Das Dim ioMgr As … ist ne Deklaration. Du machst dem Programmteil bzw. Compiler klar, dass es eine Variable namens ioMgr vom Typ soundso gibt. Aber ein konkreter Wert steckt in der Variable dabei noch nicht drin, sondern Nothing, also nix.
    Siehe auch Fachbegriffe.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    egon schrieb:

    ob eine Bibliothek überhaupt installiert ist.
    Probier es aus.
    Wenn die Datei fehlt, kriegst Du das gemeldet, wie @VaporiZed schreibt.
    Ein File.Exists() ist nur dann sicher, wenn diese Datei stets genau dort liegt. Kann sie auch woanders liegen, ist das nicht sinnvoll.
    Besser ist es, die Instanziierung selbst laufen zu lassen und dort die entsprechenden Exceptions und Fehler zu bedienen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. '[...]
    3. 'Muss hier nicht auch das "instrument" wieder geschlossen werden?
    4. End Sub
    Eine sehr richtige und wichtige Überlegung, auf die man keine Antwort geben kann, ohne Bibliothek und Doku zu kennen.
    Naja - die Bildle zeigen: Da passiert was über COM - das ist besonders heikel in der Resourcenbereinigung - da muss höchstwahrscheinlich was mit Mashal.ReleaseComObject passieren, möglicherweise sogar sehr viel.

    Soll das iwann produktiv eingesetzt werden?
    Dann würde ich dir empfehlen, iwie eine Zusammenarbeit mit einem Profi zu organisieren, der dir eine Rumpf-Anwendung schreibt, und sie dir detailliert auseinandersetzt.
    Es geht darum, die Zugriffe sinnig zusammenzufassen, und eben auch ordentlich zu bereinigen, was bereinigt werden muss.
    In deim Code werden an zwei Stellen die gleichen Objekte erzeugt - sowas ist - wenns sich fortsetzt - mittelfristig höchst problematisch.
    Und zur Bereinigung ist nix vorgesehen - da sollte man evtl. was zu basteln - eine Art Data-Access-Layer.
    Damit Code vereinfacht wird und nicht redundant an vielen Stellen auftritt.
    Vermutlich muss man den ResourceManager auch nur einmal erzeugen, und kann ihn dann für die Laufzeit des Proggis immer wieder verwenden und so Kram.
    Das .ReadList lässt sich evtl. auch in Double() Casten - wenn das möglich ist, wäre das deutlich sauberer.
    Wie gesagt: Mir schwebt eine Art Data-Access-Layer vor, der den Com-Kram abwickelt, sodass du in deim eigentlichen Programm mit "anständigen" .Net-Datentypen arbeitest.

    Womit du auf jeden Fall anfangen kannst solltest ist: Visual Studio - Empfohlene Einstellungen
    Ansonsten programmierst du garnet wirklich VB.Net.

    Und wie gesagt: Dich anfänglich an Hand nehmen lassen, dass du eine Art Einweisung erhälst, das Teil sauber zu programmieren.

    Worst-case mangelhafter Programmierung wäre, dass dein Proggi Resourcen-Leaks erzeugt, und nach gewisser Laufzeit nicht mehr weiter kann, oder gar den ganzen Rechner lahmlegt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades Jou.
    @egon Wahrscheinlich ist es das Beste, Du erzeugst das COM-Objekt bei Programmstart und zerstörst es bei Programmende.
    COM-Objekte müssen auf dem Rechner registriert sein, sonst kannst Du sie gar nicht instanziieren.
    Die Frage mit dem Test, ob eine DLL da ist oder nicht wäre damit erübrigt, ist das COM-Objekt nicht instanziierbar, ist es nicht korrekt installiert.
    Nächster Fehler.
    ...
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hui, da habe ich über viele Punkte nachzudenken.
    Hiernoch etwas zu den Rahmenbedingunen. Nein meine Software soll nicht beruflich eingesetzt werden. Letztlich ist die Beschäftigung mit der Materie "nur" Hobby.
    VaporiZed und ErfinderDesRades und RodFromGermany, ihr habt mir vor rund zwei Jahren bei ähnlichen Projekten zur Darstellung von Messdaten geholfen - nur ohne diese VISA-Messgeräte-Bibliothek. Ihr habt mit geholfen bei "Form-übergreifendes Databinding an ein typisiertes Dataset" und "Frage zu eigenen klassenübergreifenden Events" usw. Da ich in den vergangenen zwei Jahren doch recht viel wieder vergessen habe, werden ich diesen Beitrag und die alten Beiträge von mir wieder durchsehen. Auch meine alten Programm muss ich wieder verstehen, da ich die typisiertes Datasets und die klassenübergreifenden Events ganz sicher wieder verwenden werde. Da habe ich jetzt reichlich Hausaufgaben ;)

    Über einige Hinweise von euch muss ich noch etwas nachdenken, da ich sie noch nicht verstanden habe, z.B. alles zur Resourcenbereinigung und zu Mashal.ReleaseComObject.
    Wie erzeugt man auf die richtige Weise bei Programmstart das Com Objekt, so dass man darauf zugreifen kann und wie zerstört man es bei Programmende? Wie kann ich erkennen, ob sich bei mir wegen unsauberer Programmierung tote Resourcen anhäufen? Vermutlich werde ich es im realen Gebrauch niemals merken, da das Programm niemals so lange laufen wird, dass mein Arbeitsspeicher voll sein wird...

    Habe ich euch richtig verstanden, dass Dim ioMgr As Ivi.Visa.Interop.ResourceManager und Dim instrument As Ivi.Visa.Interop.FormattedIO488 nur einmal im Code auftauchen sollen? Die Kommunikation mit dem Messgerät ist letztlich so langsam, dass das Programm blockiert wird. Verstehe ich den Hinweis mit dem "Data-Access-Layer" richtig, dass dieser Messgeräte-Teil in einem parallelen unabhängigen Prozess stattfinden muss und ich wieder mit den Events arbeiten darf? Dann dürfte eure Kritik mit der Resourcenbereinigung vermutlich keine große Rolle mehr spielen.
    Sollte ich aus irgendeinem Grund die VISA-Bibliotheken ändern, wäre es auch leichter, da sich alles an einer Stelle befindet.

    Vermutlich sollte ich mir eine Liste mit wichtigen Beiträgen in diesem Forum anlegen, damit ich nach längerer Programmierpause zentrale Sachen schnell wiederfinden kann.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „egon“ ()

    @egon Wichtigster Punkt:
    Kommentiere Deinen Code, so dass Du ihn in 2 Jahren schnell wieder verstehst!
    COM-Objekte sind sehr eigen, suche Kontakt zum Hersteller dieses Dingens, was Dir der @ErfinderDesRades bereits geraten hat.
    Ich habe dienstlich mit ner Reihe unterschiedlichster Hardwaren zu tun (Kameras, Laser, Detektoren, AD-Karten usw.).
    Alles was da von externen Firmen reinkommt hat üblicherweise ne Beschreibung, Beispiel-Code und ne Service-Hotline. Letztere ist besonders wichtig.
    Wenn es das nicht gibt, lass die Finger von dieser Hardware!
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    egon schrieb:

    Habe ich euch richtig verstanden, dass Dim ioMgr As Ivi.Visa.Interop.ResourceManager und Dim instrument As Ivi.Visa.Interop.FormattedIO488 nur einmal im Code auftauchen sollen?
    Das wäre natürlich optimal. Das wäre ein Schritt in Richtung Wegkapselung von Klassen, die nicht in Deiner vollen Macht stehen. Wenn Du eine eigene Klasse um die Fremdklasse machst (= Wrapper), dann vereinfacht sich der Umgang in Deinem Hauptprogramm.

    egon schrieb:

    Die Kommunikation mit dem Messgerät ist letztlich so langsam, dass das Programm blockiert wird. Verstehe ich den Hinweis mit dem "Data-Access-Layer" richtig, dass dieser Messgeräte-Teil in einem parallelen unabhängigen Prozess stattfinden muss und ich wieder mit den Events arbeiten darf?
    Eine Möglichkeit, um die Blockade aufzuheben, wär die Verwendung von Async/Await. Events sind nutzbar, aber nicht zwingend nötig.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.