Forum: PC-Programmierung Suche C# Profi!


von Andy (Gast)


Lesenswert?

Guten Abend allerseits?

Ich suche einen C#-Profi, der mir vielleicht bei meinem Problem helfen 
kann. Und zwar geht es um einen virtuellen COM-Port, der von einem 
FDTI-Chip erzeugt wird. Eigentlich läuft alles einwandfrei, nur: Wenn 
ich während der Laufzeit des Programmes den FDTI-Chip vom USB-Port 
entferne, fange ich das mit der WndProc-Methode (die vom System zur 
Verfügung steht) ab. Schließe ich danach das Device wieder an, kann ich 
mich auch wieder mit der virtuellen Schnittstelle verbinden und damit 
arbeiten. Aber wenn ich dann mein Programm beende kommt eine 
Access-Violation (irgendwas mit "...auf Port kann nicht zugegriffen 
werden...). Diese Fehler passiert nur, wenn ich das Device im Betrieb 
einmal entfernt habe. Tue ich das nicht, beendet das Programm 
einwandfrei.
Das komische daran ist, dass ich das Port in der FormClosing-Methode 
(wie es sein soll) "close". Aber der Fehler passiert erst beim Beenden 
der "main"-Methode - keine Ahnung, was er da noch vom COM-Port will.

Ich weiß, dass ich diesen Fehler hier nicht ausführlich genug 
beschrieben habe, aber vielleicht gibt mir auf Anhieb helfen kann, oder 
einen der das gleiche Problem mal hatte und mir ein paar Ansätze geben 
kann!

Also, vielen Dank schon mal!

mfg
Andy

von Chris .. (dechavue)


Lesenswert?

Hi,

So direkt kann ich dir leider auch nicht sagen worans liegt, aber poste 
doch mal deinen Code zum zwischenzeitlichen Trennen bzw. neu aufbauen 
der Verbindung und den Stacktrace der Exception, eventuell kann ich dir 
dann helfen.

greets

(Eine schmutzige Lösung wäre, die Access-Violation-Exception zu fangen 
und zu ignorieren. Das beseitigt dann zwar die Symthome aber nicht die 
Ursache)

von Andy (Gast)


Lesenswert?

Hallo,

Danke für deine Antwort. Bin gerade nicht in der Firma - werden 
versuchen, morgen eine Code-Schnippsel zu posten.

Die Exception zu fangen habe ich auch schon versucht, aber das blöde 
ist, dass der Fehler passiert, wenn die "main"-Methode verlassen wird, 
d.h. wenn die schließende geschwungene Klammer erreicht ist. Und dort 
kann ich leider keinen Code mehr ausführen.
Keine Ahnung, was da los ist!

mfg

von Markus (Gast)


Lesenswert?

Für den Fall, daß Du die SerialPort-Klasse verwendest, rufst Du nach dem 
Close und vor dem Reconnect die Dispose-Methode auf? Ich hatte mal ein 
ähnlich gelagertes Problem mit (fehlendem) Graphics.Dispose.

Gruß
Markus

von Chris .. (dechavue)


Lesenswert?

Markus wrote:
> Für den Fall, daß Du die SerialPort-Klasse verwendest, rufst Du nach dem
> Close und vor dem Reconnect die Dispose-Methode auf?
Dispose sollte nicht nötig sein wenn Close() verwenet wird, da Close() 
auch den Internen Stream Disposed (siehe MSDN).
Ich vermute eher, dass kein Close aufgerufen wird, sondern beim 
Reconnecten einfach ein neues Serialport-Objekt angelegt wird, und das 
andere undisposed im Speicher bleibt. Wenn ein Event (z.B. DataReceived) 
aboniert ist, wird es auch nicht von der GarbageCollection eingesammelt 
bist das Programm beendet wird.

von Andy (Gast)


Lesenswert?

Das mit dem Close() habe ich mir auch schon gedacht und auch probiert! 
Hat leider nichts genützt. Kann ja auch nicht funktionieren, weil ja 
kein COM-Port mehr vorhanden ist, wenn ich den FDTI entferne, oder?? 
Dann kann ich ja auch keinen mehr "closen".
Liege ich da richtig??
Ich habe auch schon die Objektreferenz (mit "Serial=null") nach dem 
Entfernen des Devices gelöscht, ohne Erfolg!

Vielleicht noch eine Idee?

von Chris .. (dechavue)


Lesenswert?

Andy wrote:
> Ich habe auch schon die Objektreferenz (mit "Serial=null") nach dem
> Entfernen des Devices gelöscht, ohne Erfolg!

Das entfernt das Objekt nicht, das bleibt aus oben genannten Grund noch 
vorhanden. Du musst das Serialport-Objekt Closen/Disposen auch wenn die 
eigentliche Schnittstelle nicht mehr vorhanden ist.
Eventuell provozierst du damit direkt die AccessViolationException, aber 
dann ist es denke ich legitim sie hier einfach zu Fangen und zu 
ignorieren.

von Andy (Gast)


Lesenswert?

Wie gesagt, das hab ich auch schon probiert - werds aber nochmal 
versuchen!
Fangen kann ich sie aus dem Grund nicht, weil der Fehler erst beim 
Verlassen der "main"-Methode passiert, d.h. die schließende geschwungene 
Klammer erreicht wird. Komischerweise ist das auch keine übliche 
Fehlermeldung, weil die Schaltfläche "Weiter" auf der Fehlermeldung 
angezeigt wird. Wird diese geklickt, läuft der Code ganz normal weiter. 
Vielleicht ist das ein nützlicher Hinweis.
In der fertige exe wirkt sich der Fehler durch die berühmte "Anwendung 
musste geschlossen werden ... Bericht senden ...") aus.

von Chris .. (dechavue)


Lesenswert?

Ich hatte gehofft, das durch das Close/Dispose die Exception sofort 
provoziert wird, dann hätte man eine Stelle an dem man sie abfangen 
kann.

von Chris .. (dechavue)


Lesenswert?

Was du noch veruchen könntest:
1
try{
2
  port.DataRecieved -= DataRecFunc; //selbiges für alle abonierten Events
3
  port.Dispose();
4
  port = null;
5
  GC.Collect(); //Sofortiges aufräumen erzwingen um Exception zu provozieren
6
} catch (AccessVioltionException) {}

von Andy (Gast)


Lesenswert?

Hallo,

Hab deinen Code-Schnippsel probiert - hat leider auch nichts genutzt. 
Aber ich bin draufgekommen, dass es kein "AccessViolationException" ist, 
sondern eine "UnauthorizedAccessException". Vielleicht hilft das weiter!

von Andy (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch ein detailierter Auszug der Fehlermeldung!

von Andy (Gast)


Lesenswert?

Keiner vielleicht noch eine Idee??

von Christian A. (cau) Flattr this


Lesenswert?

geb doch mal deinen Code an, der nicht funktioniert... sonst müssen wir 
Raten, was sein könnte.

von Stefan (Gast)


Lesenswert?

Hallo,
ich habe genau das gleiche Problem, auch in C#. Ich habe einen FTDI, der 
mir über USB einen RS232 Port zur Verfügung stellt. Wird nun die 
Verbindung vom USB unterbrochen, stürzt das Programm ab, sobald der 
Garbage Collector versucht, die von der Klasse des seriellen Ports 
belegten Resourcen wieder freizugeben. Die Exception lässt sich nicht 
fangen.
Es scheint so, als würde meinem Programm während des Betriebs das Handle 
von Windows aus der Hand gerissen.
Auf das nötigste reduziert sieht die Anwendung so aus:
Es handelt sich einfach um ein Fenster mit zwei Schaltflächen. Wird die 
erste betätigt, wird der COM-Port geöffnet. Bei Betätigung der zweiten 
Schaltfläche wird er wieder geschlossen. Es werden in der Zeit 
dazwischen keine Daten ausgetauscht. Öffnet und schließt man den Port 
lediglich, funktioniert alles ohne Probleme. Trennt man zwischenzeitlich 
die USB Verbindung, entfernt also den COM-Port, dann stürzt das Programm 
ab, sobald man den Garbage Collector (GC.Collect()) aufruft. Dabei 
spielt es keine Rolle, ob das Gerät wieder angeschlossen wurde oder 
nicht. Ruft man den Garbage Collector nicht auf, dann stürzt das 
Programm einige Zeit später ab. Sicherlich, wenn der GC "etwas Zeit 
gefunden" hat. Spätestens jedoch, wenn das Programm beendet wird.

Schonmal vielen Dank,
Stefan
1
private void button1_Click(object sender, EventArgs e)
2
{
3
 if (ComPort == null)
4
 {
5
  ComPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
6
  ComPort.Open();
7
 }
8
}
9
10
private void button2_Click(object sender, EventArgs e)
11
{
12
 if (ComPort != null)
13
 {
14
  try
15
  {
16
   ComPort.Close();
17
//  ComPort.Dispose();
18
   oComPort = null;
19
   GC.Collect(); // <= Wenn der COM Port im System nicht mehr vorhanden ist/war, führt der Aufruf am Ende der Funktion zum Absturz des Programms.
20
  }
21
  catch (UnauthorizedAccessException) { } // übergangen
22
  catch (AccessViolationException) { } // übergangen
23
  catch (Exception) { } // übergangen
24
  catch { } // übergangen
25
 }
26
}

von Stefan (Gast)


Lesenswert?

Hallo,
unterdessen habe ich herausbekommen, dass man mit folgendem Code die 
Exception fangen kann. Leider wird das Programm aber zu schnell beendet, 
als dass man die MessageBox auch wirklich lesen, geschweige denn irgend 
eine Interaktion damit durchführen könnte. Entsprechend kann man das 
Beenden des Programms leider auch nicht verhindern.
Ich bin für alle Anregungen offen, die mir helfen, dieses Problem zu 
beheben.

Grüße,
Stefan
1
static class Program
2
{
3
 /// <summary>
4
 /// The main entry point for the application.
5
 /// </summary>
6
 [STAThread]
7
 static void Main()
8
 {
9
  AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
10
11
  Application.EnableVisualStyles();
12
  Application.SetCompatibleTextRenderingDefault(false);
13
  Application.Run(new Form1());
14
 }
15
16
 static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
17
 {
18
  if (e.ExceptionObject.GetType() == typeof(UnauthorizedAccessException))
19
  {
20
   UnauthorizedAccessException ex = (UnauthorizedAccessException)e.ExceptionObject;
21
   MessageBox.Show(ex.Message);
22
  }
23
 }
24
}

von Dave (Gast)


Lesenswert?

Hi Stefan,

hab das problem zwar noch nciht gehabt, hab aber einen Link gefunden der 
dir eventuell hilft:
http://www.switchonthecode.com/tutorials/csharp-tutorial-dealing-with-unhandled-exceptions

der Behandelt außerdem noch die ThreadException. vielleicht hilfts ja.

Grüße Dave

von Stefan (Gast)


Lesenswert?

Hallo Dave,
danke für den Link. Leider brachte dieser keine neuen Erkenntnisse. Der 
dort beschriebene Ansatz war mir bereits bekannt. Das Problem bei meiner 
Anwendung ist, dass eben wirklich das 
AppDomain.CurrentDomain.UnhandledException Event aufgerufen und die 
Software damit beendet wird. Damit habe ich mich auch bereits 
abgefunden. Ich kann den Nutzer nur leider nicht informieren, was denn 
eigentlich passiert ist, da die Anwendung zu schnell im Nirvana 
verschwindet.

Vielen Dank,
Stefan

von Dave (Gast)


Lesenswert?

Hi Stefan.

Wenn ich das richtig verstehe, dann bleibt deine Applikation icht stehen 
bei MessageBox.Show oder? Billige Möglichkeit für Zeit ist natürlich ein 
THread.Sleep. Ich nehm an du hast es schon probiert bzw. es bleibt nicht 
stehen, da ja auch deine Message Box im Nirvana verschwindet.

Ich kuck nochmalo bmir was einfaällt.
Grüße Dave

von Stefan (Gast)


Lesenswert?

Hallo Dave,
ja genau. Thread.Sleep(..) und die MessageBox.Show(..) haben keine 
Auswirkung auf das Beenden des Programms.

Grüße,
Stefan

von Arc N. (arc)


Lesenswert?

Stefan schrieb:
> Hallo,
> ich habe genau das gleiche Problem, auch in C#. Ich habe einen FTDI, der
> mir über USB einen RS232 Port zur Verfügung stellt. Wird nun die
> Verbindung vom USB unterbrochen, stürzt das Programm ab, sobald der
> Garbage Collector versucht, die von der Klasse des seriellen Ports
> belegten Resourcen wieder freizugeben. Die Exception lässt sich nicht
> fangen.
> Es scheint so, als würde meinem Programm während des Betriebs das Handle
> von Windows aus der Hand gerissen.
> Auf das nötigste reduziert sieht die Anwendung so aus:
> Es handelt sich einfach um ein Fenster mit zwei Schaltflächen. Wird die
> erste betätigt, wird der COM-Port geöffnet. Bei Betätigung der zweiten
> Schaltfläche wird er wieder geschlossen. Es werden in der Zeit
> dazwischen keine Daten ausgetauscht. Öffnet und schließt man den Port
> lediglich, funktioniert alles ohne Probleme. Trennt man zwischenzeitlich
> die USB Verbindung, entfernt also den COM-Port, dann stürzt das Programm
> ab, sobald man den Garbage Collector (GC.Collect()) aufruft. Dabei
> spielt es keine Rolle, ob das Gerät wieder angeschlossen wurde oder
> nicht. Ruft man den Garbage Collector nicht auf, dann stürzt das
> Programm einige Zeit später ab. Sicherlich, wenn der GC "etwas Zeit
> gefunden" hat. Spätestens jedoch, wenn das Programm beendet wird.

Das Problem ist MS schon länger bekannt (offizieller Fix in .NET 4)
Aktueller Workaround:
http://connect.microsoft.com/VisualStudio/feedback/Workaround.aspx?FeedbackID=140018
1
    public partial class SafeSerial : SerialPort {
2
        public SafeSerial() : base() {
3
        }
4
5
        public SafeSerial(System.ComponentModel.IContainer iC) : base(iC) { 
6
        }
7
 
8
        public SafeSerial(string portName) : base(portName) {
9
        }
10
11
        public SafeSerial(string portName, int baudRate)
12
            : base(portName, baudRate) {
13
        }
14
15
        public SafeSerial(string portName, int baudRate, Parity parity)
16
            : base(portName, baudRate, parity) {
17
        }
18
19
        public SafeSerial(string portName, int baudRate, Parity parity, int dataBits) 
20
            : base(portName, baudRate, parity, dataBits) {
21
        }
22
23
        public SafeSerial(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits) 
24
            : base(portName, baudRate, parity, dataBits, stopBits) {
25
        }
26
       
27
        public new void Open() {
28
            try {
29
                base.Open();
30
                // suppress finalize
31
                GC.SuppressFinalize(BaseStream);
32
            } catch {
33
            }
34
        }
35
36
        public new void Dispose() {
37
            Dispose(true);
38
        }
39
40
        protected override void Dispose(bool disposing) {
41
            if (disposing && (base.Container != null)) {
42
                Container.Dispose();
43
            }
44
45
            try {
46
                // try to finalize stream and catch all exceptions
47
                GC.ReRegisterForFinalize(BaseStream);
48
            } catch {
49
            }
50
            try {
51
                base.Dispose(disposing);
52
            } catch {
53
                // Prolific 
54
            }
55
        }
56
    }

von Stefan (Gast)


Lesenswert?

Hallo Arc Net,
Du bist mein heutiger Held des Tages. Deine Hilfe hat das Problem 
vollständig gelöst. Selbst der Kompromiss, dass die Applikation beendet 
wird, muss nun nicht mehr eingegangen werden.
Vielen Dank (auch an Dave).

Grüße,
Stefan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.