![]() |
Nicht erkärliche EAccessVoilation
Hallo,
Gestern habe ich sowohl meine eigenen Datensatzmaske als auch die eines DP Users, welche er mir freundlicherweise zur Verfügung gestellt hat, getesetet. Dabei erhalte ich eine EAccessviolation, wobei das Programm an der im Kommentar beschribenen Stelle anhält. Die Eigenschaft TWinControl.Parent existiert aber definitiv laut Delphi Hilfe. Wenn ich deshalb debugge, um die Ursache für die Exception zu finden, erhalte ich diese an jener Stelle, wo die Eigenschaft DataSoruce zugewiesen wird. In der Methode SetDataSource, wie im Listing unten zu sehen. Daraufhin habe ich meine eigenen Version der Datensatzmaske getestet und erhalte ebenfalls eine EAccessViolation an jener Stelle, wo
Delphi-Quellcode:
Da nund die Exception in beiden Versionen auftritt, muss ja ein generelles Problem vorliegen. Möglicherweise ist die Methode zur Zuweisung der Datenquelle falsch. Aber wie wird ed dann richtig gemacht?
function TCR_DB_Editor.GetRealParent : TWinControl;
var MYDBCtrlGrid : TMYDBCtrlGrid; tmp :TWinControl; Flag : boolean; begin Flag := false; tmp := self.Parent; result := tmp; //showmessage(result.Name); while ( tmp.Parent <> nil ) AND (Flag =false) do //Hier hält das Programm an und wirft die begin //Exception aus if Pos('dbctrl', lowercase(tmp.ClassName )) > 0 then begin MYDBCtrlGrid := TMYDBCtrlGrid(tmp); result := MYDBCtrlGrid.Panel; Flag := true; end; tmp := tmp.Parent; end; end; procedure TCR_DB_Editor.SeTDataSource(Value: TDataSource); begin if value <> nil then begin FDataLink.DataSource := Value; //Hier hält der Debugger an und wirft die Exception aus end; end; // Hier mein eigener Entwurf: procedure TDBInputMask.SetDataSource(ADataSource: TDataSource); var idx: Integer; obj: TObject; edit: TDBInputLine; chbox: TDBCheckBox; cobox: TDBComboBox; clbox: TDBLookUpComboBox; rdgrp: TDBRadioGroup; imemo: TMemo; irich: TRichEdit; image: TImage; begin if FEdits.Count > 0 then FEdits.Clear; if (ADataSource<>nil) and (FDataSource<>ADataSource) then begin //Hier erhalte ich die Exception, aber hier EAbstractError FDataSource := ADataSource; FDataSource.DataSet.GetFieldNames(FEdits); FCount := FDataSource.DataSet.FieldCount; for idx := 0 to FCount - 1 do begin SetLabels(idx, TDBText.Create(self)); //SetInputs(idx, TDBEdit.Create(self)); obj := FInputs[idx]; if obj is TDBInputLine then begin TDBInputLine(FInputs[idx]).DataSource := FDataSource; TDBInputLine(FInputs[idx]).DataField := FEdits[idx]; end; if obj is TDBCheckBox then begin TDBCheckBox(FInputs[idx]).DataSource := FDataSource; TDBCheckBox(FInputs[idx]).DataField := FEdits[idx]; end; end; end; procedure Tdbform.OpenDataBase; begin if dlgOpen.Execute then begin FFilename := dlgOpen.Filename; ClientDataSet.LoadFromFile(FFilename); ClientDataSet.Active := true; //CreateMask; FInputMask := TDBInputMask.Create(self); FInputMask.Top := 312; FInputMask.Left := 8; FInputMask.Width := 425; FInputMask.Height := 145; FInputMask.DataSource := DataSource; //Hier erhalte ich EAbstractError; FInputMask.Parent := self; end; end; Sowohl FDataLink.DataSource als auch FDataSource sind doch letztlich nix anderes als Zeiger auf die Datenquelle. Deren Adresse hole ich von außen. Aber warum dann die Exception? Gibt es zur Lösung des Problems ein Standardverfahren, das diese Exception vermeidet? Bin mit meinem Latein am Ende. Warum funktioniert die Zuweisung nicht. Ich verwende für die Entwicklung Turbo Delphi Exploerer, die kostenlose Version ohne Updates. In meiner Version erhalte ich nicht EAccessviolation, sondern EAbstractError. Deshalb noch die Definition meiner Basisklasse für meine Eingabemaske:
Delphi-Quellcode:
Die virtuellen Methoden waren vorher als virtual; abstract; deklariert. Wegen der EAbstractError Exception habe ich diese Methoden virtual; definiert und im Implementationsteil stehen leere Methodenrümpfe. Dennoch werde ich die Exception nicht los.
TCustomInputMask = class(TScrollBox)
private { Private-Deklarationen } protected { Protected-Deklarationen } FCount: Integer; FInputs: TObjectList; FLabels: TObjectList; FMasks: TStrings; public { Public-Deklarationen } procedure CreateLabel(ACaption: TCaption); virtual; procedure CreateEdit(AEditMask: String); virtual; procedure CreateCheckBox(ACaption: String); virtual; procedure CreateComboBox; virtual; procedure CreateMask; virtual; procedure CreateMemo; virtual; procedure CreateRadioGroup(ACaptions: TStrings); virtual; procedure CreateRichEdit; virtual; end; //Hier noch die Definition meiner eigenen Datensatzmaske. TDBInputMask = class(TCustomInputMask) //diese Klasse für Datenbankmasken verwenden //Feldanzahl, damit Anzahl Edits wird durch die Datenbank bestimmt private FDataSource: TDataSource; FEdits: TStrings; //Feldnamen nach Anzeigereihenfolge function GetInputs(Index: Integer): TObject; function GetLabels(Index: Integer): TDBText; function GetMasks(Index: Integer): String; function GetDataSource: TDataSource; procedure SetCount(ACount: Integer); procedure SetInputs(Index: Integer; AInput: TObject); procedure SetLabels(Index: Integer; ALabel: TDBText); procedure SetMasks(Index: Integer; AMask: String); procedure SetDataSource(ADataSource: TDataSource); public constructor Create(AOwner: TComponent); procedure CreateLabel(ACaption: TCaption); override; procedure CreateLabelCaptions(ACaptions: TStrings); procedure CreateEdit(AEditMask: String); override; procedure CreateCheckBox(ACaption: String); override; procedure CreateComboBox; override; procedure CreateMask; override; procedure CreateMemo; override; procedure CreateRadioGroup(ACaptions: TStrings); override; procedure CreateRichEdit; override; destructor Destroy; override; property Count: Integer read FCount write SetCount; property DataSource: TDataSource read GetDataSource write SetDataSource; property Inputs[Index: Integer]: TObject read GetInputs write SetInputs; property Masks[Index: Integer]: String read GetMasks write SetMasks; default; end; Weil aber bei der Einen Version die Exception, wenn auch EAccessviolation, statt EAbstractError, wie bei der Anderen Version während der Zuweisung der Datenquelle ausgelöst wird, habe ich die Frage in diesen Thread gepackt. Denn ich vermute, das die Fehlerursache irgendwo im Softwaredesign liegt. Egal, welche Exception letzlich ausgelöst wird. Braucht Ihr, um helfen zu können noch mehr Quelltext? Dann teilt mir das bitte hier mit und ich werde die Quellen liefern. Die Datensatzmaske ist nichts sonderlich geheimes. |
Re: Nicht erkärliche EAccessVoilation
Hat den der Parent einen Parent?
|
Re: Nicht erkärliche EAccessVoilation
Zitat:
Ist das Problem dort zu suchen oder wird zur Unterstützung bei der Fehlersuche noch Quelltext gebraucht? Ich dachte, das hier ein generelles Problem vorkliegt, weil der Fehler in beiden Versionen der Datensatzmaske auftritt. Beide Male bei der Zuweisung der Datenquelle. Der fremde Quelltext stammt von einem DP User. Leider habe ich keine Vorgaben erhalten, wie der Quelltext zu behandeln ist, bezüglich seiner Veröffentlichung. Zeigen kann ich daher nur meinen eigenen uneingeschränkt, so das zur Fehlerbehebung beiträgt. In der Methode wird ja, wie im Quelltext zu sehen, abgefragt, ob value<>nil ist: if value <> nil then begin FDataLink.DataSource := Value; end; Auch ich frage in meiner Version ab, ob ein Zeiger ungleich NIL übergeben wird. if (ADataSource<>nil) and (FDataSource<>ADataSource) then begin FDataSource := ADataSource; Wenn ich debugge, kommt die Exception bei der Zuweisung der Datenquelle. Im Hauptprogramm folgt nach Zuweisung der Datenquelle die Zuweisung der Eigenschaft Parent, weshalb der Cursor bei normalem Programmstart dort stehen bleibt. Biem Debuggen im Einzelschrittbetrieb meckert das Programm bei Zuweisung der Datenquelle und das in beiden Versionen der Datensatzmaske, sowohl in der fremden als auch in meiner eigenen. |
Re: Nicht erkärliche EAccessVoilation
Wenn FDataLink nil ist, krachts auch bei der Zuweisung der DataSource. Egal ob "value" nil ist. Genauso wenn Self.Parent nil ist. Dann kannst du nicht auf Self.Parent.Parent zugreifen (tmp.Parent).
|
Re: Nicht erkärliche EAccessVoilation
Zitat:
Delphi-Quellcode:
Und der Parent wird hier zugewiesen? In meiner eigenen Version!
if (ADataSource<>nil) and (FDataSource<>ADataSource) then
begin FDataSource := ADataSource;
Delphi-Quellcode:
Die Inputmaske ist im Grunde ein Nachkomme von TScrollBox. Ist in dieser das Feld Parent = NIL. Wie aber kommt eine Scrollbox aus der Komponentenpalette auf das Delphi Formular? Weist Delphi nicht intern auch der Eigenschaft Parent das Formular zu, auf dem sie platziert wird? Wenn ich hier falsch liege, muss ich mal ganz OT fragen, was macht denn dann Delphi mit der dfm Datei? Geschieht die entscheidende Zuweisung da wesentlich anders. Kann man das mit eigenem Quelltext auch so machen, wenn man die Komponente zur Laufzeit erzeugt? Ich dachte immer, Delphi liest die dfm-Datei und macht daraus das gleiche, was ich mache, wenn ich die Kompo zur Laufzeit erzeuge. Scheint aber Deiner knappen Auskunft nach nicht so zu sein. Biitte bitte hilf mir weiter. Ich weiß wirklich nicht, wo ich nach dem Fehler suchen soll.
FInputMask := TDBInputMask.Create(self);
FInputMask.Top := 312; FInputMask.Left := 8; FInputMask.Width := 425; FInputMask.Height := 145; FInputMask.DataSource := DataSource; FInputMask.Parent := self; Bei Honaraversprechen müsste ich allerdings vorher wissen, wieviel Geld man für die fertige Datensatzmaske als Delphi Komponente auf dem Markt verlangen könnte. Wäre eine echte Alternative, da auch ich noch immer nach einer passenden Lehrstelle suche. Da käme eine kommerzielle Vermarktbarkeit einer selber geschiebenen Delphi Komponente wie gerufen. Hast Du vielleicht ne Ahnung, welche Firmen so was brauchen könnten und was solch eine Komponente dann noch können müsste? Dann wäre die Sache einfacher, weil ich dann einen Anreiz für Deine bzw. Eure Hilfe bieten könnte. Wenn aber die Kompo nicht verkäuflich ist, dann bitte bitte lasst Gnade walten und sgt mir wenigstens, wie ich den Fehler eingrenzen kann. Kann ja sein, das Parent in:
Delphi-Quellcode:
den Wert NIL hat. Aber hier:
if value <> nil then
begin FDataLink.DataSource := Value;
Delphi-Quellcode:
wird dem FDataLink doch eine Adresse zugewiesen. Der Debugger meckert diese Stelle zumindest nicht an. Außerdem meckert der Debugger im Einzelschrittbetrieb nicht bei Parent, sondern bei FDataLink.DataSource.
constructor TCR_DB_Editor.Create(AOwner: TComponent);
begin inherited Create(AOwner); UpdatingControls := false; ControlStyle := ControlStyle + [csReplicatable]; FControlList := TStringList.Create; FDataLink := TCR_DB_EditorLink.Create(self); end; [edit=mkinzler]Delphi-Tags ergänzt Mfg, mkinzler[/edit] |
Re: Nicht erkärliche EAccessVoilation
Könntest du bitte die vollständige Fehlermeldung posten? (Sorry falls ich es übersehen habe)
Denn die vollständige Meldung enthält Adressen die bei der Suche nach der Ursache mehr als hilfreich sind. |
Re: Nicht erkärliche EAccessVoilation
Hallo!
Zitat:
Hier die Fehlermeldung: //FInputMask := TCR_DB_Editor.Create(self); FInputMask := TDBInputMask.Create(self); Modul laden: ntshrui.dll. Ohne Debug-Infos. Basisadresse: $76940000. Prozess desktopdd.exe (1544) Modul laden: ATL.DLL. Ohne Debug-Infos. Basisadresse: $76AD0000. Prozess desktopdd.exe (1544) Modul laden: NETAPI32.dll. Ohne Debug-Infos. Basisadresse: $71BA0000. Prozess desktopdd.exe (1544) Thread-Start: Thread-ID: 1640. Prozess desktopdd.exe (1544) Thread-Start: Thread-ID: 1636. Prozess desktopdd.exe (1544) Modul laden: SHDOCVW.dll. Ohne Debug-Infos. Basisadresse: $71000000. Prozess desktopdd.exe (1544) Erste Gelegenheit für Exception bei $77E4D756. Exception-Klasse EAbstractError mit Meldung 'Abstrakter Fehler'. Prozess desktopdd.exe (1544) Und hier die Meldungen, wenn ich die Fremdbibliothek verwende: FInputMask := TCR_DB_Editor.Create(self); //FInputMask := TDBInputMask.Create(self); Modul laden: SETUPAPI.dll. Ohne Debug-Infos. Basisadresse: $76620000. Prozess desktopdd.exe (400) Modul laden: ntshrui.dll. Ohne Debug-Infos. Basisadresse: $76940000. Prozess desktopdd.exe (400) Modul laden: ATL.DLL. Ohne Debug-Infos. Basisadresse: $76AD0000. Prozess desktopdd.exe (400) Modul laden: NETAPI32.dll. Ohne Debug-Infos. Basisadresse: $71BA0000. Prozess desktopdd.exe (400) Thread-Start: Thread-ID: 404. Prozess desktopdd.exe (400) Thread-Start: Thread-ID: 1740. Prozess desktopdd.exe (400) Thread-Start: Thread-ID: 428. Prozess desktopdd.exe (400) Modul laden: SHDOCVW.dll. Ohne Debug-Infos. Basisadresse: $71000000. Prozess desktopdd.exe (400) Thread-Start: Thread-ID: 956. Prozess desktopdd.exe (400) Erste Gelegenheit für Exception bei $77E4D756. Exception-Klasse EAccessViolation mit Meldung 'Zugriffsverletzung bei Adresse 004D1A93 in Modul 'desktopdd.exe'. Lesen von Adresse 00000030'. Prozess desktopdd.exe (400) Die Klasse TCR_DB_Editor ist die Klasse der fremden Eingabemaske. Die Klasse TDBInputmask ist meine eigene Eingabemaske. Wenn ich hier:
Delphi-Quellcode:
die zusätzliche Bedingung (tmp <> nil) einbaue, erhalte ich eine EInvalidOperation
function TCR_DB_Editor.GetRealParent : TWinControl;
var MYDBCtrlGrid : TMYDBCtrlGrid; tmp :TWinControl; Flag : boolean; begin Flag := false; tmp := self.Parent; result := tmp; //showmessage(result.Name); while (tmp <> nil) AND ( tmp.Parent <> nil ) AND (Flag =false) do begin if Pos('dbctrl', lowercase(tmp.ClassName )) > 0 then begin ... @nuclearping Zitat:
Modul laden: ntshrui.dll. Ohne Debug-Infos. Basisadresse: $76940000. Prozess desktopdd.exe (1760) Modul laden: ATL.DLL. Ohne Debug-Infos. Basisadresse: $76AD0000. Prozess desktopdd.exe (1760) Modul laden: NETAPI32.dll. Ohne Debug-Infos. Basisadresse: $71BA0000. Prozess desktopdd.exe (1760) Thread-Start: Thread-ID: 1640. Prozess desktopdd.exe (1760) Thread-Start: Thread-ID: 1636. Prozess desktopdd.exe (1760) Thread-Start: Thread-ID: 1500. Prozess desktopdd.exe (1760) Modul laden: SHDOCVW.dll. Ohne Debug-Infos. Basisadresse: $71000000. Prozess desktopdd.exe (1760) Thread-Start: Thread-ID: 1532. Prozess desktopdd.exe (1760) Erste Gelegenheit für Exception bei $77E4D756. Exception-Klasse EInvalidOperation mit Meldung 'Element '' hat kein übergeordnetes Fenster'. Prozess desktopdd.exe (1760) ...und zwar hier: if HorzScrollBar <> nil then HorzScrollbar.Position := 0; in dieser Methode:
Delphi-Quellcode:
Nun werde ich noch mal meine eigene Eingabemaske auf Fehler "abklopfen".
procedure TCR_DB_Editor.ReOrderControls;
... Variablendeklaratioenen begin //Initialisierungen, die nichts mit den Schrollbars zu tun haben //Das steht unmittelbar vor der strittigen Anweisung ww := Width div (2 * FElement_ListCols) ; if ww < FMinWidthHoriz then ww := FMinWidthHoriz; VertikalRowCounter := 0; //Hier tritt die Exception auf < EInvalidOperation //Wozu braucht der Scrollbar ein übergeordnetes Fenster, //um dessen Anfangsposition zuzuweisen? if HorzScrollBar <> nil then HorzScrollBar.Position := 0; if VertScrollBar <> nil then VertScrollBar.Position := 0; end; |
Re: Nicht erkärliche EAccessVoilation
Also deine Variable temp ist vom Typ TWinControl. Wo wird denn das Objekt temp erstellt? Du fängts einfach so damit an zu arbeiten ohne es zu erzeugen. Oder habe ich da jetzt was übersehen?
|
Re: Nicht erkärliche EAccessVoilation
Zitat:
|
Re: Nicht erkärliche EAccessVoilation
Hallo!
Zitat:
TWinControl | TControl (Hier wird die Eigenschaft Parent eingeführt) | TComponent Zitat:
an tmp wird self.parent zugewiesen. Self ist ja das Objekt selber. den Parameter self müsste ma da sogar weglassen können. Die KLasse TCR_DB_Editor, zu der die Methode gehört in der an die Variable tmp der Wert self.parent zugewiesen wird, stmmt von TSchrollBox ab, in der die Eigenschaft Parent auch definiert ist. Das Objekt temp wird gar nicht erstellt, sondern ist nur ein Platzhalter innerhalb der Methode. So weit, so gut, doch folgt ja dieser Code:
Delphi-Quellcode:
Und da haben wir unseren tmp.parent
function TCR_DB_Editor.GetRealParent : TWinControl;
var MYDBCtrlGrid : TMYDBCtrlGrid; tmp :TWinControl; Flag : boolean; begin Flag := false; tmp := self.Parent; result := tmp; while (tmp <> nil) AND ( tmp.Parent <> nil ) AND (Flag =false) do begin if Pos('dbctrl', lowercase(tmp.ClassName )) > 0 then begin MYDBCtrlGrid := TMYDBCtrlGrid(tmp); result := MYDBCtrlGrid.Panel; Flag := true; end; tmp := tmp.Parent; end; end; Ich fürchte, ich sollte den Spender des Quellcodes fragen, ob ich die Unit vollständig hier posten darf. Anderenfalls werd ich wohl die Quelle erst mal gründlicher studieren müssen. Ich versteh nämlich auch noch nicht alles, was der hier programmiert hat. MyDBCtrlGrid stammt von TDBCtrlGrid ab, hat also auch einen Parent. MyDBCtrlGrid führt die Eigenschaft Panel ein. So sollte Parent nach dieser Prozedur auf Parent von MyDBCtrlgrid zeigen. Die Variable tmp ist somit nur eine Hilfsvariable, um in der Schleife den aktuellen Parent festzuhalten. In wie weit dieser Parent von Bedeutung ist für die Anzeige der Eingabemaske, konnte ich noch nicht feststellen, da ich nach Hinzufügen der Bedingung (tmp <> nil), die im Original nicht enthalten war, eine EInvalidOperation - Exception erhalte. Allerdings tritt meine Exception EInvalidOperation hier auf:
Delphi-Quellcode:
Ist es geschickter, einen neuen Thread, mit dem Thema EInvalidOperation zu eröffnen? Ich mach das mal.
procedure TCR_DB_Editor.ReOrderControls;
... Varablendeklaratioen begin //Hier wird die alte Liste mit den Eingabecontrols gelöscht, um die passenden Eingabecontrols //entsprechend neuer Feldreihefolge in diese Liste einzufügen if Element_EditHeigth > FElement_RowHight then FElement_RowHight := Element_EditHeigth +2; // Label und Eingabe eine Höhe: deshalb /2 1 * Elementhöhe / Spalten // // oben und unten // ElementBlockHight := FElement_RowHight * Pred( FControlList.Count-FElement_NonVisib ) div (2 * FElement_ListCols); VertikalTopMargin := Pred(Height - ElementBlockHight ) div 2; if VertikalTopMargin < 1 then VertikalTopMargin := 1; ww := Width div (2 * FElement_ListCols) ; if ww < FMinWidthHoriz then ww := FMinWidthHoriz; VertikalRowCounter := 0; //Hier bei HorzScrollbar kommt die neue Exception //HorzScrollBar und VertScrollBar sind ider Vorgängerklasse TScrollBox bereits definiert //Warum tritt dann die EInvalidOperation auf if HorzScrollBar <> nil then HorzScrollBar.Position := 0; if VertScrollBar <> nil then VertScrollBar.Position := 0; ---------------------------------------------------------------------------------------------------- Meine EAbstractError Exception in meinem eigenen Entwurf hängt gar nicht mit der Zuweisung der Datenquelle zusammen, sondern mit der Verwendung einer Stringliste vom Typ TStrings anstelle von TStringList. Die Variable darf dabei vom Typ TStrings sein, jedoch muss an diese eine TStringlist zugewiesen werden. Jedenfalls in Turbo Delphi. Falsch:
Delphi-Quellcode:
var
List: TStrings; procedure CreateList; begin List := TStrings.Create; end; Richtig:
Delphi-Quellcode:
Mit der zweiten Version der Stringliste kann unbedenklich gearbeitet werden. Die erste Variante erzeugt beim Zugriff auf die Liste eine EAbstrctError Exception.
var
List: TStrings; procedure CreateList; begin List := TStringList.Create; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz