Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Funktionsaufruf innerhalb With..do => access violation (https://www.delphipraxis.net/191943-funktionsaufruf-innerhalb-do-%3D-access-violation.html)

Hobbycoder 6. Mär 2017 10:52

Funktionsaufruf innerhalb With..do => access violation
 
Hi,

ich hänge mal wieder an eine möglicherweise recht simplen Problem.
Ich erzeuge in meinem Programm einige Forms dynamisch. Zwecks Formatüberprüfung für z.B. eine Faxnummer nutze ich eine Function, die in einer separaten Unit liegt, in 2 dynamisch erzeugen Formularen jeweils im OnExit-Event eine JvValidateEdit um eine Faxnummer automatisch richtig zu formatieren. So weit kein Problem, läuft fehlerfrei.
Bei den beiden Formularen handelt es sich um eine Adressliste und eine Formular zur Adressenerfassung.

Wird jetzt beim Editieren einer Adresse das Formular zur Adressenerfassung erzeugt, möchte ich (im Falle eines des Editieren bereits vorhandener Daten) auch gleich eine Validierung der Faxnummer vornehmen. Der Aufruf ist identisch mit dem im OnExit-Event der Erfassungsform.
Jedoch kommt beim Aufruf der Function bereits eine AccessViolation. Ich habe Probleme mir das zu erklären. Objekte sind alle erzeugt, Uses ist auch passig, Compiler hat nix zu meckern und ich kann über den Debugger auch darauf zugreifen. Aber per Einzelschritt komme ich nicht einmal in die Funktion.

Hier mal der Code:
Delphi-Quellcode:
procedure Tfrm_Adressbuch.btn_aendernClick(Sender: TObject);
var
  LKZ, ONKZ, RN: string;
  idxLKZ, idxONKZ: Integer;
  faxnummer: string;
begin
  if lv_adressen.Selected=nil then Exit;
  with Tfrm_Adresse.Create(self) do
  begin
    try
      edt_name.Text:=Adressbuch[lv_adressen.Selected.Index].Name;
      edt_vorname.Text:=Adressbuch[lv_adressen.Selected.Index].Vorname;
      edt_firma.Text:=Adressbuch[lv_adressen.Selected.Index].Firma;
      faxnummer:=Adressbuch[lv_adressen.Selected.Index].Faxnummer;
      faxnummer:=ValidateNumber(faxnummer, CountryList, ONKZList, Settings.OwnCountryPrefix, Settings.OwnCityPrefix, LKZ, ONKZ, RN, idxLKZ, idxONKZ); // <-- Hier kommt die Access Violation
      edt_faxnummer.Text:=faxnummer;
      if idxLKZ>-1 then lbl_LKZ.Caption:=CountryList[idxLKZ].CountryDE;
      if idxONKZ>-1 then lbl_ONKZ.Caption:=ONKZList[idxONKZ].Ort;
      CountryList:=Self.CountryList;
      ONKZList:=Self.ONKZList;
      Settings:=Self.Settings;
      if ShowModal=mrOK then
      begin
        Adressbuch[lv_adressen.Selected.Index].Name:=edt_name.Text;
        Adressbuch[lv_adressen.Selected.Index].Vorname:=edt_vorname.Text;
        Adressbuch[lv_adressen.Selected.Index].Firma:=edt_firma.Text;
        Adressbuch[lv_adressen.Selected.Index].Faxnummer:=edt_faxnummer.Text;
        Adressbuch.SortByName;
        Adressbuch.SaveToFile(AdressenFilename);
        BuildLV;
      end;
    finally
      Free;
    end;
  end;
end;
Und die Function sieht folgendermaßen aus:
Delphi-Quellcode:
function ValidateNumber(Number: string; CountryList: TCountryList; ONKZList: TONKZList;
  OwnCountryPrefix: string; OwnCityPrefix: string;
  var LKZ, ONKZ, RN: string; var idxLKZ, idxONKZ: integer): string;
Wie gesagt in den OnExit-Events innerhalb des Tfrm_Adresse-Formular kann ich die Funktion problemlos aufrufen.

Hat irgendeiner eine Idee woran das liegen kann? Ist sicher mein Fehler, aber ich verstehe nicht warum.
Gruß Hobbycoder

rweinzierl 6. Mär 2017 11:02

AW: Funktionsaufruf innerhalb With..do => access violation
 
Hallo

Niemals, wirklich niemals with verwenden, macht den Code nur schwer lesbar.

Weise deinem Formular eine Instanzvariable zu und lasse es nochmals durch den Debugger laufen.

Ohne with bekommst du auch im Debugger hints was in den Variablen drin steht.

Ändere deinen Code bitte ab und poste ihn dann nochmals, vielleicht findest du ihn so selber oder wir können dir besser helfen

mfg

Reinhold

Sherlock 6. Mär 2017 11:07

AW: Funktionsaufruf innerhalb With..do => access violation
 
Mehr gibts dazu zwar nicht zu sagen, aber der Vollständigkeit halber: With ist mindestens so schädlich wie Goto!

Sherlock

Hobbycoder 6. Mär 2017 11:08

AW: Funktionsaufruf innerhalb With..do => access violation
 
Der Erfolg gibt die Recht. So funktioniert es.

Kannst du mir auch erklären warum?

Delphi-Quellcode:
procedure Tfrm_Adressbuch.btn_aendernClick(Sender: TObject);
var
  LKZ, ONKZ, RN: string;
  idxLKZ, idxONKZ: Integer;
  faxnummer: string;
  Adresse: Tfrm_Adresse;
begin
  if lv_adressen.Selected=nil then Exit;
  Adresse:=Tfrm_Adresse.Create(self);
  try
    Adresse.edt_name.Text:=Adressbuch[lv_adressen.Selected.Index].Name;
    Adresse.edt_vorname.Text:=Adressbuch[lv_adressen.Selected.Index].Vorname;
    Adresse.edt_firma.Text:=Adressbuch[lv_adressen.Selected.Index].Firma;
    faxnummer:=Adressbuch[lv_adressen.Selected.Index].Faxnummer;
    faxnummer:=ValidateNumber(faxnummer, CountryList, ONKZList, Settings.OwnCountryPrefix, Settings.OwnCityPrefix, LKZ, ONKZ, RN, idxLKZ, idxONKZ);
    Adresse.edt_faxnummer.Text:=faxnummer;
    if idxLKZ>-1 then Adresse.lbl_LKZ.Caption:=CountryList[idxLKZ].CountryDE;
    if idxONKZ>-1 then Adresse.lbl_ONKZ.Caption:=ONKZList[idxONKZ].Ort;
    CountryList:=Self.CountryList;
    ONKZList:=Self.ONKZList;
    Settings:=Self.Settings;
    if Adresse.ShowModal=mrOK then
    begin
      Adressbuch[lv_adressen.Selected.Index].Name:=Adresse.edt_name.Text;
      Adressbuch[lv_adressen.Selected.Index].Vorname:=Adresse.edt_vorname.Text;
      Adressbuch[lv_adressen.Selected.Index].Firma:=Adresse.edt_firma.Text;
      Adressbuch[lv_adressen.Selected.Index].Faxnummer:=Adresse.edt_faxnummer.Text;
      Adressbuch.SortByName;
      Adressbuch.SaveToFile(AdressenFilename);
      BuildLV;
    end;
  finally
    Adresse.Free;
  end;
end;

bra 6. Mär 2017 11:33

AW: Funktionsaufruf innerhalb With..do => access violation
 
Vermutlich greift der bei irgendeinem der ValidateNumber-Parameter ins Leere. Man sieht halt bei dem With-Code nicht, woher die einzelnen Variablen kommen, aus Adresse oder aus Self. Darum möglichst With nicht verwenden.

nahpets 6. Mär 2017 11:39

AW: Funktionsaufruf innerhalb With..do => access violation
 
Ohne den vollständigen Quelltext und die vollständige Formulardefinition wird das konkrete Erkennen der Fehlerursache schwierig. Mal ein einfaches Beispiel, um auf eine mögliche Fehlerursache hinzuweisen:

Gegeben sei ein Formular (Form1) mit 'nem Label (Label1) drauf:
Delphi-Quellcode:
with Form1 do begin
  Caption := Label1.Caption;
end;

with Form1 do begin
  with Label1 do begin
    Caption := Caption;
  end;
end;

with Form1, Label1 do begin
  Caption := Caption;
end;
Diese Beispiele sind extrem verkürzt, machen aber hoffentlich klar, dass auch bei korrekter Syntax und Kompilierbarkeit von Quelltext bei der Verwendung von With "Namenskonflikte" auftreten können.

D. H.: Es kann sein, dass bei mehreren gleichnamigen Eigenschaften unterschiedlicher Objekte zwar eine syntaktisch korrekte Interpretation möglich ist, aber nicht zwingend vom Compiler die konkret gemeinte Eigenschaft genutzt wird, sondern die von ihm "vermutete" Eigenschaft. Die kann aber zur Laufzeit zu einem Objekt gehören, dass (noch) nicht erstellt wurde und dies führt zu dem von Dir beschriebenen Fehler.

Sprich: Es wird auf was anderes zugegriffen, als Du beim Schreiben und Lesen des Quelltextes meinst.

Hobbycoder 6. Mär 2017 12:45

AW: Funktionsaufruf innerhalb With..do => access violation
 
Alles klar :-)

ich habs dann noch mal so probiert:
Delphi-Quellcode:
       faxnummer:=ValidateNumber(faxnummer, self.CountryList, self.ONKZList, self.Settings.OwnCountryPrefix, Self.Settings.OwnCityPrefix, LKZ, ONKZ, RN, idxLKZ, idxONKZ); // <-- Hier kommt die Access Violation
       edt_faxnummer.Text:=faxnummer;
       if idxLKZ>-1 then lbl_LKZ.Caption:=Self.CountryList[idxLKZ].CountryDE;
       if idxONKZ>-1 then lbl_ONKZ.Caption:=Self.ONKZList[idxONKZ].Ort;
Und nun eindeutigen Referenz mittels self greift er nun auf die richtigen Variablen zu.

Hätte mir klar sein müssen/sollen.
Fazit: with..do lohnt wirklich nur bei extrem kurzen Abschnitten, in denen keine Mehrdeutigkeiten auftreten können.

Danke an euch alle.

haentschman 6. Mär 2017 12:57

AW: Funktionsaufruf innerhalb With..do => access violation
 
Zitat:

Fazit: with..do lohnt wirklich nur bei extrem kurzen Abschnitten
...wie du siehst überhaupt nicht. :P Dann ergänze mal deinen Code z.B... Plötzlich kommt was anderes raus als früher. Es muß nicht immer eine AV sein. 8-)

himitsu 6. Mär 2017 14:04

AW: Funktionsaufruf innerhalb With..do => access violation
 
Zitat:

Zitat von nahpets (Beitrag 1363313)
Diese Beispiele sind extrem verkürzt, machen aber hoffentlich klar, dass auch bei korrekter Syntax und Kompilierbarkeit von Quelltext bei der Verwendung von With "Namenskonflikte" auftreten können.

D. H.: Es kann sein, dass bei mehreren gleichnamigen Eigenschaften unterschiedlicher Objekte .......

Delphi-Quellcode:
//var R: TRect;
with R do begin
  Width := Right - Left;
end;
Früher traf es Form.Width bzw. Self.Width und nun Delphi-Referenz durchsuchenTRect.Width :angle:


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