Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi OnResize => AV, Wenn OnResize leer... (https://www.delphipraxis.net/70383-onresize-%3D-av-wenn-onresize-leer.html)

glkgereon 29. Mai 2006 16:43


OnResize => AV, Wenn OnResize leer...
 
Hi,

Ich habe ein sehr komisches Problem...

Ich habe ein Formular, in dem sich einige übliche Kompos befinden. (Genauer: TRadioGroup, TGroupBox, TButton, TJvDirectoryEdit, TJvFileNameEdit, TLabel, TProgressBar, TJvRichEdit, TRichEdit, TTimer, TPopupMenu, TJvTrayIcon).

Auf einmal (Ich habe keine Kompo geändert, hinzufügt oder gelöscht) wirft er beim Ändern der Fenstergröße eine Exception.
Zitat:

---------------------------
Benachrichtigung über Debugger-Problem
---------------------------
In Projekt G:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio-Projekte\VPlan\VPlan.exe trat ein Problem mit folgender Meldung auf: 'access violation at 0x0040d971: write of address 0x00030fe8'. Prozess angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
Aber auch das nur unter bestimmten Umständen:
Das Programm analysiert ein paar dateien und lädt dann die daten hoch...die AV kommt erst nachdem dies getan wurde!
zudem kann man sie ebenfalls verhindern indem man im OnResize zB ein ShowMessage('Resizing...') einfügt...

für mich absolut unerklärbar.
Das einzige was während diesem Analysieren einfluss auf TForm_Main (Forumlar) einfluss nimmt, sind folgende Sachen:

Delphi-Quellcode:
procedure TForm_Main.ColorLog(ID, Len: Integer; Col: TColor);
//bestimmten Teil im Log färben
begin
  Rch_Log.SelStart:=ID;
  Rch_Log.SelLength:=Len;
  Rch_Log.SelAttributes.Color:=Col;
  Rch_Log.SelLength:=0;
end;

procedure TForm_Main.Log(Value, Msg, Level: String; Typ: TLogLevel);
//Ereignis in Log ablegen und färben
var S, Datum: String;
begin
  if FLogLevel>Typ then Exit;
  Datum:=DateTimeToStr(Now);
  if Level<>'' then Level:='['+Level+'] ';
  S:=Datum + DSep + Level + Value + VSep + cLogTypes[Typ].Desc + ' (' + Msg + ')';

  Rch_Log.Perform(WM_VSCROLL, SB_BOTTOM,0);
  Rch_Log.Refresh;
end;

procedure TForm_Main.InitProgress(Max: Integer; Action: String);
begin //Progressbar Initialisieren
  Prg_Progress.Max:=Max;
  Prg_Progress.Min:=0;
  Prg_Progress.Step:=1;
  Lbl_Status.Caption:=Action;
  Lbl_Status.Refresh;
  FLastAkt:=Now;
end;

procedure TForm_Main.SetProgress(Progress: Integer = -1);
begin //Progressbar weitersetzen
  if Progress=-1 then
    Prg_Progress.StepIt
  else
    Prg_Progress.Position:=Progress;
  Prg_Progress.Refresh;
  if MillisecondsBetween(FLastAkt,Now)>1000 then Application.ProcessMessages;
end;

procedure TForm_Main.UnInitProgress;
begin //Progressbar zurücksetzen
  Prg_Progress.Position:=0;
  Lbl_Status.Caption:='Bereit';
end;
Mir ist das verhalten absolut unerklärlich, ich hoffe irgendwer kann mir wenigstens sagen wo ich anfangen könnte nach einem fehler zu suchen

glkgereon 3. Jun 2006 11:25

Re: OnResize => AV, Wenn OnResize leer...
 
Weiss das echt keiner?

Es ist echt relativ wichtig :-/

SirThornberry 3. Jun 2006 11:39

Re: OnResize => AV, Wenn OnResize leer...
 
das ganze wird nix mit dem Onresize direkt zu tun haben sondern ist eine Folgeerscheinung. Du zerhaust irgendwo schon eher den Speicher. Und je nach dem was du anschließend machst bzw. ob was im OnResize steht verschiebt sich der Speicher. Und davon hängt es dann ab ob du das Glück hast das du die AV bekommst.

glkgereon 3. Jun 2006 11:41

Re: OnResize => AV, Wenn OnResize leer...
 
Zitat:

Zitat von SirThornberry
das ganze wird nix mit dem Onresize direkt zu tun haben sondern ist eine Folgeerscheinung. Du zerhaust irgendwo schon eher den Speicher. Und je nach dem was du anschließend machst bzw. ob was im OnResize steht verschiebt sich der Speicher. Und davon hängt es dann ab ob du das Glück hast das du die AV bekommst.

Also ich vermute das es mit einer Kompo zu tun hat. mein Eigener Code läuft definitiv ohne AV durch.

Ich habe atm das TJvFileNameEdit bzw TJvDirectoryEdit im Verdacht.

was kann man da ausprobieren?

Edit:
Wobei auffällig ist das es erst auftritt wenn ich einmal meinen Code ausgeführt hab...
ließe ja eigentlich darauf schließen das ich in speicherbereichen rumfummel wo ich nix zu suchen hab....
ich checke mal meinen code...

SirThornberry 3. Jun 2006 12:01

Re: OnResize => AV, Wenn OnResize leer...
 
das klingt wirklich so als ob du mit deinem Code irgendwo in falschen Speicherbereichen rumfummelst. Prüf am besten mal ob du Eventuell über Arraygrenzen hinaus gehst (0 basierend nicht beachtet), einen String aus einem Stream ausliest/scheibst mit
Delphi-Quellcode:
Stream.Read(DeinString, Len);
anstelle von
Delphi-Quellcode:
Stream.Read(DeinString[1], Len);
(vielleicht auch vorher setlength vergessen), etc.

glkgereon 3. Jun 2006 12:12

Re: OnResize => AV, Wenn OnResize leer...
 
Zitat:

Zitat von SirThornberry
das klingt wirklich so als ob du mit deinem Code irgendwo in falschen Speicherbereichen rumfummelst. Prüf am besten mal ob du Eventuell über Arraygrenzen hinaus gehst (0 basierend nicht beachtet), einen String aus einem Stream ausliest/scheibst mit
Delphi-Quellcode:
Stream.Read(DeinString, Len);
anstelle von
Delphi-Quellcode:
Stream.Read(DeinString[1], Len);
(vielleicht auch vorher setlength vergessen), etc.

Ha!!!

Ich habe einfach mal eine Importer-Klasse auskommentiert, und siehe da: es funkt.
Das heisst zwar immer noch nicht das ich den Fehler hab, aber die möglicherweise fehlerhaften Zeile reduzieren sich von mehreren Tausend auf gut 100 :-D

woran könnte es hier liegen?
Delphi-Quellcode:
TImport_Virtual = class(TObject)
  private //Basisklasse für ImportTyp
    FFileName: String;
    FFileExt: String;
    FMaxAge: TDateTime;
    FHasData: Boolean;
  public
    FData: TData;
    constructor Create; virtual; abstract;
    destructor Destroy; virtual; abstract;
    function OpenFile(var Err: String):Boolean; virtual; abstract;
    function CloseFile(var Err: String):Boolean; virtual; abstract;
    function Analyse(var Err: String):Boolean; virtual; abstract;
    function GetData(var Dat: TData):Boolean;
    property FileName: String read FFileName write FFileName;
    property MaxAge: TDateTime read FMaxAge write FMaxAge;
    property HasData: Boolean read FHasData write FHasData;
  end;

TMTTImport = class(TImport_Virtual)
  private //Import aus MTT-Datei
    S: TStringList;
    Datum: TDateTime;
  public
    constructor Create; override;
    destructor Destroy; override;
    function OpenFile(var Err: String):Boolean; override;
    function CloseFile(var Err: String):Boolean; override;
    function Analyse(var Err: String):Boolean; override;
  end;



constructor TMTTImport.Create;
begin
  inherited;
  FFileExt:='.mtt';
  FHasData:=True;
  S:=TStringList.Create;
end;

destructor TMTTImport.Destroy;
begin
  S.Free;
  inherited;
end;

function TMTTImport.OpenFile(var Err: String):Boolean;
var M,D: String;
    Y: Integer;
begin
  try
    Result:=True;
    if FileExists(FFileName) then
      if LowerCase(ExtractFileExt(FFileName))=LowerCase(FFileExt) then
        begin
        Result:=False;
        Err:='';
        S.LoadFromFile(FFileName);
        M:=ExtractFileName(FFileName);
        M:=Copy(M,1,Pos('.',M)-1);
        M:=Copy(M,Pos('-',M)+1);
        D:=ExtractFileName(FFileName);
        D:=Copy(D,1,Pos('-',D)-1);
        D:=Copy(D,Pos('X',D)+1);
        Y:=YearOf(Date);
        Datum:=EncodeDate(Y,StrToInt(M),StrToInt(D));
        if Datum>Now+FMaxAge then Datum:=EncodeDate(Y-1,StrToInt(M),StrToInt(D));
        S.Clear;
        end
      else
        Err:=cEFileExt
    else
      Err:=cEFileExists;
  except
    Result:=True;
    Err:=cEUnknown;
  end;
end;

function TMTTImport.CloseFile(var Err: String):Boolean;
begin
  S.Clear;
  Result:=False;
end;

function TMTTImport.Analyse(var Err: String):Boolean;
var Data: TStringDynArray;
    i:Integer;
begin
  try
    Data:=Explode(#$0D+#$0A+#$0D+#$0A,S.Text);
    SetLength(FData.MTData,Length(Data));
    for i:=0 to Length(Data)-1 do
      begin
      FData.MTData[i].Value:=Data[i];
      FData.MTData[i].Datum:=Datum;
      end;
    SetLength(Data,0);
    Result:=False;
  except
    Result:=True;
  end;
end;
PS: die TMTTImport ist nicht die einzige die von TImport_Virtual abgeleitet ist, aber die einzige die den Error fabriziert...
von daher sollten das eigentlich alle relevanten code-teile sein.

PS2: Könnte event daran liegen?
Denn TMTTImport ist die einzige klasse die was in FData.MTData reintut....
Delphi-Quellcode:
type
  TVTData = record //Datensatz
    Stunde: String;
    Fehlend: String;
    Vertretend: String;
    Klasse: String;
    Fach: String;
    Raum: String;
    BemerkungS: String;
    BemerkungL: String;
    Datum: String;
  end;
  TVTDataArray = array of TVTData;

  TMTData = record
    Datum: TDateTime;
    Value: String;
  end;
  TMTDataArray = array of TMTData;

  TData = record
    VTData: TVTDataArray;
    MTData: TMTDataArray;
  end;

var FData: TData;

function TImport_Virtual.GetData(var Dat: TData):Boolean;
begin
  try
    Move(FData,Dat,SizeOf(FData));
    Result:=False;
  except
    Result:=True;
  end;
end;

SirThornberry 3. Jun 2006 12:35

Re: OnResize => AV, Wenn OnResize leer...
 
ich vermute den Fehler hier:
Delphi-Quellcode:
  try
    Move(FData,Dat,SizeOf(FData));
    Result:=False;
  except
    Result:=True;
  end;
Dat und fData beinhalten dynamiche Arrays. Dynamische Arrays sind aber auch nur Pointer. Durch das Move lässt du die Arrays beider Records auf das gleiche zeigen. Wenn dann der erste Record frei gegeben wird würde der zweite ins nirvana zeigen (Vermutung nach erstem überfliegen des Ganzen)

glkgereon 3. Jun 2006 12:35

Re: OnResize => AV, Wenn OnResize leer...
 
Zitat:

Zitat von SirThornberry
ich vermute den Fehler hier:
Delphi-Quellcode:
  try
    Move(FData,Dat,SizeOf(FData));
    Result:=False;
  except
    Result:=True;
  end;
Dat und fData beinhalten dynamiche Arrays. Dynamische Arrays sind aber auch nur Pointer. Durch das Move lässt du die Arrays beider Records auf das gleiche zeigen. Wenn dann der erste Record frei gegeben wird würde der zweite ins nirvana zeigen (Vermutung nach erstem überfliegen des Ganzen)

Genau das vermute ich auch^^
wie würde ich das denn sauber und funktionierend schreiben?

Phistev 3. Jun 2006 13:23

Re: OnResize => AV, Wenn OnResize leer...
 
Delphi-Quellcode:
try
  Dat.VTData:= Copy(FData.VTData);
  Dat.MTData:= Copy(FData.MTData);
  Result:= false;
except
  Result:= true;
end;
So zum Beispiel


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:21 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