USB-Serial Port Systemressourcen werden nicht freigeben

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von andrax.

    USB-Serial Port Systemressourcen werden nicht freigeben

    Hallo zusammen,

    ich bin neu hier im Forum und praktisch ein Einsteiger in VB.Net.
    Mein Name ist André und arbeite gerade an einem Tool, zur Überwachung von 2 "Rohde & Schwarz HMP4040" Netzgeräten.
    Die Netzgeräte sind per USB mit dem Rechner gekoppelt. Der Serial-Port wird wird vom Treiber emuliert.
    Die Programmfunktion ist relativ einfach gehalten. Es soll nur der Status der Kanäle abgefragt werden, mit der Möglichkeit diese ein und auszuschalten.
    Ich benutze zur Programmierung Visual Studio Express.
    Den Code hab ich mir über die Suchfunktion hier im Forum soweit erarbeitet.

    Ich stehe allerdings vor einem Problem wo ich nicht weiter komme.

    Zunächst, die Konfiguration der Serialports wird von einer .ini File gelesen.
    Der gesamte Code für die Kommunikation habe ich in eine Class gepackt.

    Hier ein Auszug:

    VB.NET-Quellcode

    1. Public Class Ports1
    2. Public Port2 As New System.IO.Ports.SerialPort()
    3. Public Eingangsstring As String = ""
    4. Public startbit2 As Boolean = False
    5. Public err As Exception
    6. Private Sub initalisieren()
    7. 'Port Konfigurieren und öffnen
    8. Try
    9. Me.Port2.BaudRate = Preferences.COM2Baudrate
    10. Me.Port2.DataBits = Preferences.COM2Databits
    11. Me.Port2.Parity = Preferences.COM2Parity
    12. Me.Port2.PortName = Preferences.COM2Name
    13. Me.Port2.StopBits = Preferences.COM2Stopbit
    14. Me.Port2.ReadTimeout = Preferences.COM2ReadTimeout
    15. Me.Port2.WriteTimeout = Preferences.COM2WriteTimeout
    16. Port2.Open()
    17. Catch err As Exception
    18. Port2.Close()
    19. Port2.Dispose()
    20. Form1.Netzteil1_text.Clear()
    21. Form1.InfoBox1.AppendText(err.ToString)
    22. Form1.InfoBox1.AppendText(Environment.NewLine)
    23. End Try
    24. End Sub
    25. .
    26. .
    27. .


    Code-Tag korrigiert. Das ist kein AutoIt ;) ~Thunderbolt

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

    @andrax Willkommen im Forum. :thumbup:
    Wie geht es weiter im Code?
    Was für Probleme treten auf?
    Wie äußert sich der von Dir genannte Effekt?
    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!
    Oh Sorry, hab ich hier Probleme bei der Bearbeitung eines Themas.
    Hier noch mal das ganze Problem:

    Hallo zusammen,

    ich bin neu hier im Forum und praktisch ein Einsteiger in VB.Net.
    Mein Name ist André und arbeite gerade an einem Tool, zur Überwachung von 2 "Rohde & Schwarz HMP4040" Netzgeräten.
    Die Netzgeräte sind per USB mit dem Rechner gekoppelt. Der Serial-Port wird wird vom Treiber emuliert.
    Die Programmfunktion ist relativ einfach gehalten. Es soll nur der Status der Kanäle abgefragt werden, mit der Möglichkeit diese ein und auszuschalten.
    Ich benutze zur Programmierung Visual Studio Express.
    Den Code hab ich mir über die Suchfunktion hier im Forum soweit erarbeitet.

    Ich stehe allerdings vor einem Problem wo ich nicht weiter komme.

    Zunächst, die Konfiguration der Serialports wird von einer .ini File gelesen.
    Der gesamte Code für die Kommunikation habe ich in eine Class gepackt.
    In der Vergangenheit habe ich die Erfahrung gemacht, das Serialports nicht stabil sind.
    Daher ist der Code so gestaltet, das immer die Verbindung geprüft wird.

    Hier ein Auszug:
    Port öffnen:

    VB.NET-Quellcode

    1. Public Class Ports1
    2. Public Port2 As New System.IO.Ports.SerialPort()
    3. Public Eingangsstring As String = ""
    4. Public startbit2 As Boolean = False
    5. Public err As Exception
    6. Private Sub initalisieren()
    7. 'Port Konfigurieren und öffnen
    8. Try
    9. Me.Port2.BaudRate = Preferences.COM2Baudrate
    10. Me.Port2.DataBits = Preferences.COM2Databits
    11. Me.Port2.Parity = Preferences.COM2Parity
    12. Me.Port2.PortName = Preferences.COM2Name
    13. Me.Port2.StopBits = Preferences.COM2Stopbit
    14. Me.Port2.ReadTimeout = Preferences.COM2ReadTimeout
    15. Me.Port2.WriteTimeout = Preferences.COM2WriteTimeout
    16. Port2.Open()
    17. Catch err As Exception
    18. Port2.Close()
    19. Port2.Dispose()
    20. Form1.Netzteil1_text.Clear()
    21. Form1.InfoBox1.AppendText(err.ToString)
    22. Form1.InfoBox1.AppendText(Environment.NewLine)
    23. End Try
    24. End Sub
    25. .
    26. .
    27. .


    Zusätzlich wird vor jedem Schreibbefehl der Port zusätzlich geprüft

    VB.NET-Quellcode

    1. Private Function checkport() As Boolean
    2. 'wird bei jedem Schreibvorgang ausgeführt, ob der Comport noch offen ist
    3. Try
    4. If (Port2 Is Nothing OrElse Port2.IsOpen = False) Then
    5. Port2.Open()
    6. Port2.WriteLine("*idn?")
    7. Me.EmpfangeDaten()
    8. Form1.Netzteil2_text.Clear()
    9. Form1.Netzteil2_text.Text = Eingangsstring
    10. Me.GeraeteStatus()
    11. End If
    12. Return True
    13. Catch err As Exception
    14. Port2.Close()
    15. Port2.Dispose()
    16. Form1.Netzteil2_text.Clear()
    17. Form1.InfoBox1.AppendText(err.ToString)
    18. Form1.InfoBox1.AppendText(Environment.NewLine)
    19. Return False
    20. End Try
    21. End Function


    Jetzt zu meinen Problem:
    Der Code für ein Netzteil funktionierte einwandfrei.
    Bei Verlust der Verbindung wurde dies angezeigt und die Verbindung wieder hergestellt.
    Nun habe ich den Code für das 2. Netzteil geklont und in eine 2. Class gepackt.
    Der Verbindungsaufbau funktioniert einwandfrei. ABER, bei einem Verlust der Verbindung, ist eine
    Wiederverbindung nun nicht mehr möglich. Der jeweilige Port ist blockiert, da hilft auch nicht das Programm zu beenden und neu zu starten.
    Erst wenn ich in der Systemsteuerung den jeweiligen Port umbenenne, bekomme ich zunächst eine Fehlermeldung dass ein Prozess auf den Port zugreift. Danach funktioniert das Ganze wieder.

    Was mache ich Falsch ?
    Wie gebe ich die Systemresourcen in VB.Net richtig frei.

    Gruß

    Andre

    Code-Tags korrigiert. ~Thunderbolt

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

    andrax schrieb:

    Was mache ich Falsch ?
    Zunächst bleibt eine Verbindung zu einem Port während der Programmlaufzeit offen, bei Beendigung des Programms wird das Port geschlossen.
    Nur wenn Du während der Kommunikation ein Problem hast (das ist mir noch nicht vorgekommen) wird das Port geschlossen und wieder geöffnet.
    =====
    Was hat es mit der geclonten Klasse auf sich?
    Wenn Du mit mehreren Ports mit praktisch identischen Gegenstellen kommunizierst, erstell dafür eine Klasse und übergib dieser im Konstruktor einfach die Portnummer.
    Feddich.
    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!
    Hallo,

    erst mal Danke für die schnelle Rückantwort.
    Zunächst, ich hatte in der Vergangenheit ständig Probleme mit der Stabilität der Seriellen Schnittstellen.
    Dies betraf vor allem SPS gesteuerte Anlagen. Ich hatte hier eine RS232 Datenkommunikation mit einem angeschlossenen PC.
    Ständig hatten wir Kommunikationsfehler und Verlust der Verbindung und keiner wusste warum.
    Ich bin daher ein so genanntes gebranntes Kind und will die dieses Problem gleich mit berücksichtigen.

    So ich habe gerade nochmal das Programm getestet.
    In der normalen Funktion ohne Portverlust, werden wirklich die Ports bei Beendigung geschlossen und freigegeben.
    Nur im Fehlerfall, kann ja auch sein dass jemand mal das Kabel abzieht, bleiben die Ports offen und sind blockiert.
    Da hilft noch nicht einmal Port2.Dispose()
    Mit geclont meine ich folgendes.
    Ich habe den gesamten Code zu Ansteuerung des Netzteils in eine Class geschrieben.
    Für das 2. Netzteil hab ich den Code Dupliziert und in eine neue Class geschrieben.
    Das sieht in etwa so aus:

    VB.NET-Quellcode

    1. Class1
    2. Public Class Ports1
    3. Public Port1 As New System.IO.Ports.SerialPort()
    4. .
    5. .
    6. .
    7. End Class

    VB.NET-Quellcode

    1. Public Class Ports2
    2. Public Port2 As New System.IO.Ports.SerialPort()

    Ich habe im Prinzip nur die Namen geändert.
    Ja ich weiß, das macht man so nicht aber ich bin noch ein Absoluter newbi.


    Bitte verzeiht mir

    Code-Tags korrigiert. ~Thunderbolt

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

    @andrax OHa.
    Das ganze ist leider sau blöd, da lässt sich von Ferne nicht so richtig helfen, wegen der fehlenden Hardware.
    Spiele ein wenig rum und versuch, den Ausfall der Verbindung gezielt herbeizuführen (RS232-Stecker ziehen, SPS ausschalten, ...).
    So bekommst Du die Möglichkeit, Deinen Code effektiv zu testen.
    Und wenn Du dann die Umstände präzise beschreiben kannst, können wir versuchen, das ganze nachzustellen.
    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!
    Guten Morgen,

    vielen Dank für die Unterstützung.
    Das Problem ist mir beim Testen aufgefallen. Ich beschreibe die ganze Konstellation mal etwas näher.
    Ich habe hier einen Arbeitsplatz mit Visualstudio Express. Mir steht 1 Netzteil zum Programieren/Testen zur Verfügung.
    Ich habe zunächst den Code für ein Netzteil geschrieben. Bis auf das Einlesen der Config steht alles in einer Class.
    Das Verhalten habe ich ausführlich getestet, incl. abziehen des Kabels während der Programmlaufzeit. Erwartungsgemäß bekomme ich
    einen Fehler durch den Verlust der Verbindung. Wenn ich das Kabel reinstecke, wird die Verbindung wieder aufgebaut und das Prog. läuft normal weiter.

    Da es mir noch an Erfahrung fehlt, habe ich das Prog. aus der Class in eine neue Class Kopiert und alle Variablen mit einen neuen Namen versehen, so dass es keine Überschneidungen gibt.
    Ab diesen Zeitpunkt funktionierte der Reconnect nicht mehr.
    Nach intensiven Suchen und konnte ich die Fehlerursache soweit eingrenzen.

    VB.NET-Quellcode

    1. Public Port2 As New System.IO.Ports.SerialPort()


    Es scheint an diesen Aufruf zu liegen.
    Ich definiere Port1 und Port2, da ich ja 2 Netzgeräte überwachen möchte.
    Solange ich nur Port1 definiert hatte um das Prog. zu erstellen klappte alles.
    Mit der Definition von Port2 nicht mehr.
    Irrwitzigerweise muss noch nicht mal port2.open() aufgerufen werden um das Problem zu Verursachen.
    Es reicht die alleinige Definition.

    Gruß

    Andre

    Code-Tags korrigiert. ~Thunderbolt

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

    andrax schrieb:

    Es reicht die alleinige Definition.
    Das ist eine Instanziierung, keine Definition.

    VB.NET-Quellcode

    1. Public Port2 As System.IO.Ports.SerialPort
    wäre eine Deklaration.
    Dass die Instanziierung allein zum Absturz führt, kann ich mir nicht vorstellen.
    Kann es sein, dass Du beiden die selbe Port-Nummer zuweist?
    Das geht natürlich nicht.
    Oder:
    Wieviele RS232-Verbindungen (egal ob RS232 oder USB) verwaltest Du in Deinem Programm?
    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!
    Ähm nein ich verwende 2 Instanzen und verwalte 2 Ports.

    Public Port1 As System.IO.Ports.SerialPort und Public Port2 As System.IO.Ports.SerialPort

    Wenn ich nur eine Instanz verwende, sprich nur mit einem Netzteil arbeite, kann die USB Verbindung während der Programmlaufzeit mal wegbrechen.
    Dies kann versehentliches abziehen des Kabels sein oder das Netzteil fällt mal aus.
    Wenn dann die Verbindung wieder aufgebaut wird, verbindet sich das Programm mit dem Netzteil und arbeitet normal weiter.
    Mit der Bildung der 2. Instanz funktioniert das komischerweise nicht mehr. Bei einer möglichen Unterbrechung bleibt der Port blockiert und eine Verbindung ist nicht mehr möglich. Da hilft auch kein Programmneustart.
    Mein Dilemma ist, dass es auf dem betreffenden Zielrechner wo das Prog mal laufen wird. keine Adminrechte gibt.
    Ich kann dann nicht im Gerätemanager den Port umbenennen um Ihn frei zu bekommen.
    Dies bedeutet, ich müsste den Rechner neu starten, was aber auch nicht geht, weil da noch andere Software läuft, die auf keinen Fall beendet werden darf.
    Ich suche eine Möglichkeit den Port sicher freizugeben.
    Dispose() funktioniert leider nicht.

    Gruß

    Andre

    (Inline-)Code-Tags eingefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    @andrax Missverständnis.
    Ich meine .PortName = "COM1" und .PortName = "COM2".
    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!
    Guten Morgen,

    hier mal der Code für die Instanzenbildung der beiden Serialports.
    Evtl. ist da generell ein Fehler drin.
    Port1:

    VB.NET-Quellcode

    1. Public Class Ports1
    2. Public Port1 As New System.IO.Ports.SerialPort
    3. Public Eingangsstring As String = ""
    4. Public startbit As Boolean = False
    5. Private Sub initalisieren()
    6. 'Port Konfigurieren und öffnen
    7. Try
    8. Me.Port1.BaudRate = Preferences.COM1Baudrate
    9. Me.Port1.DataBits = Preferences.COM1Databits
    10. Me.Port1.Parity = Preferences.COM1Parity
    11. Me.Port1.PortName = Preferences.COM1Name
    12. Me.Port1.StopBits = Preferences.COM1Stopbit
    13. Me.Port1.ReadTimeout = Preferences.COM1ReadTimeout
    14. Me.Port1.WriteTimeout = Preferences.COM1WriteTimeout
    15. Port1.Open()
    16. Catch err As Exception
    17. Port1.Close()
    18. Port1.Dispose()
    19. Form1.Netzteil1_text.Clear()
    20. 'Form1.Netzteil1_text.Text = Preferences.COM1Name & "ist nicht verfügbar"
    21. Form1.InfoBox1.AppendText(err.ToString)
    22. Form1.InfoBox1.AppendText(Environment.NewLine)
    23. End Try
    24. End Sub
    25. Private Function checkport() As Boolean
    26. 'wird bei jedem Schreibvorgang ausgeführt, Prüfung ob der Serialport noch offen ist
    27. Try
    28. If (Port1 Is Nothing OrElse Port1.IsOpen = False) Then
    29. Port1.Open()
    30. Port1.WriteLine("*idn?")
    31. Me.EmpfangeDaten()
    32. Form1.Netzteil1_text.Clear()
    33. Form1.Netzteil1_text.Text = Eingangsstring
    34. Me.GeraeteStatus()
    35. End If
    36. Return True
    37. Catch err As Exception
    38. Port1.Close()
    39. Port1.Dispose()
    40. Form1.Netzteil1_text.Clear()
    41. 'Form1.Netzteil1_text.AppendText(Preferences.COM1Name & "ist nicht verfügbar")
    42. Form1.InfoBox1.AppendText(err.ToString)
    43. Form1.InfoBox1.AppendText(Environment.NewLine)
    44. Return False
    45. End Try
    46. End Function
    47. .
    48. .
    49. .

    und für Port2:

    VB.NET-Quellcode

    1. Public Class Ports2
    2. Public Port2 As New System.IO.Ports.SerialPort()
    3. Public Eingangsstring As String = ""
    4. Public startbit2 As Boolean = False
    5. Private Sub initalisieren()
    6. 'Port Konfigurieren und öffnen
    7. Try
    8. Me.Port2.BaudRate = Preferences.COM2Baudrate
    9. Me.Port2.DataBits = Preferences.COM2Databits
    10. Me.Port2.Parity = Preferences.COM2Parity
    11. Me.Port2.PortName = Preferences.COM2Name
    12. Me.Port2.StopBits = Preferences.COM2Stopbit
    13. Me.Port2.ReadTimeout = Preferences.COM2ReadTimeout
    14. Me.Port2.WriteTimeout = Preferences.COM2WriteTimeout
    15. Port2.Open()
    16. Catch err As Exception
    17. Port2.Close()
    18. Port2.Dispose()
    19. Form1.Netzteil2_text.Clear()
    20. Form1.InfoBox1.AppendText(err.ToString)
    21. Form1.InfoBox1.AppendText(Environment.NewLine)
    22. End Try
    23. End Sub
    24. Private Function checkport() As Boolean
    25. 'wird bei jedem Schreibvorgang ausgeführt, Prüfung ob der Serialport noch offen ist
    26. Try
    27. If (Port2 Is Nothing OrElse Port2.IsOpen = False) Then
    28. Port2.Open()
    29. Port2.WriteLine("*idn?")
    30. Me.EmpfangeDaten()
    31. Form1.Netzteil2_text.Clear()
    32. Form1.Netzteil2_text.Text = Eingangsstring
    33. Me.GeraeteStatus()
    34. End If
    35. Return True
    36. Catch err As Exception
    37. Port2.Close()
    38. Port2.Dispose()
    39. Form1.Netzteil2_text.Clear()
    40. Form1.InfoBox1.AppendText(err.ToString)
    41. Form1.InfoBox1.AppendText(Environment.NewLine)
    42. Return False
    43. End Try
    44. End Function
    45. .
    46. .
    47. .


    Code-Tags korrigiert. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    andrax schrieb:

    Evtl. ist da generell ein Fehler drin.
    Mehrere.
    Wie ich Dir oben bereits schrieb, sind solch zwei Klassen in Zeiten der objektorientierten Programmierung Tinnef.
    Mach da eine Klasse draus.
    Deinen Preferences fügst Du statt der Einzelwerte zweier Ports zwei Instanzen mit je allen Einzelwerten eines Ports hinzu, diese übergibst Du an die Port-Instanz im Konstruktor.
    Auf die beiden Port-Klassen greifst Du dann per Index zu.
    Dein Zugriff auf die Properties von Form1 sind scheiß ranz alter steinkohlen VB6-Kompatibilitäts-Mist.
    Entweder die Instanzen senden Events oder die Form1 wertet die Rückgabewerte aus und macht das.
    Gugst Du auch hier: Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    Ansonsten empfehle ich Dir, Dich zunächst mit den Grundlagen der objektorientierten Programmierung zu befassen, bevor Du weitermachst.
    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!
    Boa,

    welch eine Arroganz von oben herab.
    Wie konnte ich es nur wagen, als Anfänger hier eine Frage zu Stellen.
    So verkault man Neulinge, die sich mit der Programmierung beschäftigen wollen,
    anstatt die fertige App aus dem Store zu laden.

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

    andrax schrieb:

    welch eine Arroganz von oben herab.
    Das ist keine Arroganz, sondern der Hinweis, wie man deinen Code besser schreiben kann, um Duplikate zu vermeiden. Natürlich ist es klar, dass man als Anfänger noch nicht alle Erfahrungen machen konnte.
    Mit freundlichen Grüßen,
    Thunderbolt
    Hallo,

    auch wenn ich es immer noch unfär finde, wenn man als unerfahrener Neuling so angeranzt wird,
    will ich es dennoch hier noch mal versuchen.

    Also das Problem, dass bei einer unterbrochenen Verbindund der Port nicht mehr geöffnet werden konnte ist erledigt.
    Es liegt an meinem Rechner. Auf einem anderen Rechner funktioniert es einwandfrei. K.a. was da Quer spielt.
    Ja, wie ich die Forms anspreche, ist nicht in Ordnung, das wird geändert. Auch wie ich den Code für die Ports gesplittet habe, ist ebenfalls nicht gut. Also, bevor ich meine Todo's abarbeite, will ich den Code in Ordnung bringen. Dazu will ich die Beiden Code für die Ports zusammenfassen, da die sich Doppeln
    Ist es möglich, die Port instanzen vorher zu bilden und dann zu übergeben?
    Ich mein in etwa so:

    VB.NET-Quellcode

    1. Dim Port1 As New System.IO.Ports.Serial
    2. Dim Port2 As New System.IO.Ports.Serial
    3. Ports.portopen(Port1)


    VB.NET-Quellcode

    1. Public Class Ports
    2. Private Sub portopen(parameterübernahme)
    3. parameterübernahme.open()
    4. '...


    Ist das möglich?

    Andre

    Code-Tags eingefügt. ~Thunderbolt

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