Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TComport - Access Violation beim wieder-öffnen (https://www.delphipraxis.net/190886-tcomport-access-violation-beim-wieder-oeffnen.html)

SearchBot 16. Nov 2016 14:06

TComport - Access Violation beim wieder-öffnen
 
Hallo

ich verwende die TComport-Komponente 4.11

Ich habe das Problem, daß es spätestens bei Programmende zu dieser Meldung kommt und abschließend mit dem Fensterchen "Runtime Error 216":
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt ***.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x0040a3bc: read of address 0x00000058' aufgetreten.
---------------------------

"Anhalten" bringt mich in ein für mich nichts sagendes CPU-Fenster, der Stack-Verlauf führt mich nicht in den Quelltext.

Dieses Verhalten habe ich immer dann, wenn ich Daten gelesen habe (RxBuf, siehe unten), den Comport schließe und danach wieder öffne - oder spätestens eben bei Programmende.

Es scheint auch keine Exception zu sein, die in der Komponente abgefangen werden kann (onException wird nicht angesprungen).

Vielleicht habe ich auch was in meinem Object (hier ein Auszug) falsch gemacht?!

Delphi-Quellcode:
  type TData = object
    Bytes: array[1..50] of byte;
    Len:byte;
    procedure Clear;
  end;


type ... // in einem Object
  private
   fReceived:AnsiString;
   procedure CleanReceived(const Value:Ansistring);
  public

   Data:TData;
   property received:AnsiString read fReceived write CleanReceived;
end;

procedure TData.Clear;
var I: Integer;
begin
  for I := 1 to 50 do begin
   Bytes[i]:=0;
   len:=0;
  end;
end;

procedure .. .CleanReceived(const Value:AnsiString);
begin
  setlength(fReceived,Length(Value));
  fReceived:=Value;
end;

procedure TForm1.ComPort1RxBuf(Sender: TObject; const Buffer; Count: Integer);
var
  I: Integer; Buf:Array[1..100] of AnsiChar; s:AnsiString; P:PansiChar;
begin
  setLength(s,count);

  p:=pAnsichar(@Buffer);
  for I := 1 to Count do begin
    if i<=100 then begin
     Buf[i]:=p^;
     Data.Bytes[i]:=ord(Buf[i]);
    end;
    inc(p);
  end;
  if count<=100 then
  s:=copy(Buf,1,count)
  else
  s:=copy(Buf,1,100);

  received:=s; //pur wie es kommt ins property

  s:=AsciiToHex(S);      //verschönern als lesefreundliche Hex-Ausgabe; aus JvCsvParse

  for I := 1 to length(s)*2 do
   if I mod 3=0 then insert(#32,s,i);

  if count>100 then s:=s+'...';

  lb_Answer.Caption:=s;
end;
Theoretisch könnte dieser Quelltext ursächlich sein, ich meine, es habe mal in TData.Clear geknallt, aber ich sehe darin keinen Fehler!?

Wo stimmt da was nicht?
Danke im Voraus fürs mitdenken.

Neumann 16. Nov 2016 19:14

AW: TComport - Access Violation beim wieder-öffnen
 
Warum nicht einfach den Event OnRXChar und dann die Funktion Readstr nehmen? Dann kann man sich die ganze die Sache extrem vereinfachen.
Das einzige Problem ist, dass OnRXChar mehrfach feuert, wenn Daten kommen. Man muss also einen Puffer (string) z.B. als Formvariable mit den Teilstücken befüllen. Wenn das Endzeichen oder die Länge der Sendung bekannt ist, ist es auch kein Problem zu erkennen wann die Sendung fertig eingelesen ist;

EmWieMichael 17. Nov 2016 06:55

AW: TComport - Access Violation beim wieder-öffnen
 
Inc(P); ??

SearchBot 17. Nov 2016 09:37

AW: TComport - Access Violation beim wieder-öffnen
 
Zitat:

Zitat von EmWieMichael (Beitrag 1353925)
Inc(P); ??

Weil ich zeichenweise den Inhalt aus dem typenlosen Buffer nach Buf-Array kopiere.
Wenn ich es weglasse, bleibe ich auf der Stelle stehen und bekomme immer das selbe Zeichen.

Oder wie meinst du das?

Zitat:

Zitat von Neumann (Beitrag 1353901)
Warum nicht einfach den Event OnRXChar und dann die Funktion Readstr nehmen? Dann kann man sich die ganze die Sache extrem vereinfachen.
Das einzige Problem ist, dass OnRXChar mehrfach feuert, wenn Daten kommen. Man muss also einen Puffer (string) z.B. als Formvariable mit den Teilstücken befüllen. Wenn das Endzeichen oder die Länge der Sendung bekannt ist, ist es auch kein Problem zu erkennen wann die Sendung fertig eingelesen ist;

Die Bytes, die eintreffen, haben kein spezielles Endzeichen.
Das Ende der Übermittlung ist ein CRC aus den zuvor eingetroffenen bytes.
Es kann aber auch sein, daß der Controller, der die Bytes sendet, spinnt und endlos unsinnige Daten liefert (dann muss man ihn stromlos setzen, um das zu beenden).


Was ich nicht verstehe ist (auch), wenn ich den Comport schließe, dann wird ja die "Datei" geschlossen, es werden auch Threads beendet und alles ist erstmal gut. Wenn ich den Comport wieder öffne, bekomme ich die Zugriffsverletzung, aber nur wenn ich zuvor Daten empfangen habe.
Kann es also sein, daß vom vorherigen Mal noch Daten herumgeistern und es deshalb knallt (wobei ich den Ort nicht finden kann)?

Die Komponente funktioniert an sich prima, bestimmt habe ich irgendwo Mist gebaut, aber ich finde es nicht :pale:

Neumann 17. Nov 2016 09:59

AW: TComport - Access Violation beim wieder-öffnen
 
Man muss den Comport nicht schließen. Es ist durchaus ok, beim Programmstart zu öffnen und beim Programmende zu schließen. Hat man Geräte, die 'ungefragt' senden geht das gar nicht anders.

Was für ein Gerät sendet da?

SearchBot 28. Nov 2016 14:49

AW: TComport - Access Violation beim wieder-öffnen
 
Ja, im Grunde mache ich das auch so: beim Start öffnen und am Ende schließen - und eben da wird dann mit der Zugriffsverletzung geworfen, oder eben dann, wenn ich den Port wieder öffne, nachdem ich ihn geschlossen habe.

Der Sender ist ein kleiner Mikrocontroller, der 4-6 Befehle kann. Sehr mikro eben.

samso 29. Nov 2016 11:14

AW: TComport - Access Violation beim wieder-öffnen
 
Die Länge von data.bytes ist nur 50, während die Länge von buf 100 ist. Das illegale Überschreiben von Speicher wird auch durch die Abfrage "if i<=100" nicht verhindert.

SearchBot 3. Dez 2016 10:44

AW: TComport - Access Violation beim wieder-öffnen
 
Zitat:

Zitat von samso (Beitrag 1354913)
Die Länge von data.bytes ist nur 50, während die Länge von buf 100 ist. Das illegale Überschreiben von Speicher wird auch durch die Abfrage "if i<=100" nicht verhindert.

Verrückt, aber der Fehler ist verschwunden! :thumb:
Danke samso :cheers:


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:43 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz