AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Zugriffverletzung beim Verwenden von Interfaces
Thema durchsuchen
Ansicht
Themen-Optionen

Zugriffverletzung beim Verwenden von Interfaces

Ein Thema von mirage228 · begonnen am 14. Dez 2003 · letzter Beitrag vom 16. Dez 2003
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von mirage228
mirage228

Registriert seit: 23. Mär 2003
Ort: Münster
3.750 Beiträge
 
Delphi 2010 Professional
 
#1

Zugriffverletzung beim Verwenden von Interfaces

  Alt 14. Dez 2003, 18:30
Hallo,

ich habe mich die letzten Tage mal mit Interfaces beschäftigt und habe sie auch in mein Programm eingebaut.

Leider bin ich da auf ein Problem gestoßen...
In meiner Anwendung ist folgende Umgebung gegeben:

Ich hab das Interface ICipher, dass ein paar Eigenschaften (+ die dazugehörigen Get und Set Methoden) und ein paar Prozeduren (als stdcall deklariert) beinhaltet.

Ich leite davon die Klasse TCipher zusammen mit TInterfacedObject ab, die die Methoden des Interfaces definiert. Die Methoden ändern Felder im private Bereich von TCipher, die Get und Sets selbst im protected bereich. Hierbei werden die Prozeduren, welche im ICipher Interface als stdcall deklariert sind, zusätzlich mit den Direktiven virtual und abstract versehen.

Nun habe ich DLLs die eine Prozedur exportieren, die einen VAR Parameter des Typs ICipher verlangt.
Diese DLL exportiert einen Nachfahren von TCipher, welche die oben genannten Prozeduren mit override überschreibt. Diese Nachfahren haben zusätzlich noch ein paar private Felder, die intern für die Verwaltung von diversen Einstellungen verwendet werden. (Es gibt auch noch ein bis zwei, die keine zusätzlichen privaten Felder besitzen).

In meinem Programm habe ich noch zusätzlich die Klasse TCustomCipher, die ein ICipher Objekt sowie ein Feld für den Namen und das Handle einer DLL hat. Beim erstellen (Create) von TCustomCipher wird die exportierte Prozedur aus der DLL aufgerufen und das ICipher Objekt als Parameter übergeben. In der DLL wird dann eine Instanz erstellt (z.B. Cipher := TMyCipher.Create() ).

Nun habe ich da noch eine Klasse TCipherList, die eine Liste für die TCustomCiphers darstellt, u.A. mit Suchfunktion.

Nun habe ich folgendes Problem:
Ich hab in einer Combobox die Namen der Verschlüsselungen stehen. Beim onChange werden Labels mit den Eigenschaften (Beschreibung, Entwickler, etc.) gefüllt. Es wird SearchCipher aufgerufen, um den Index in der Liste zu ermitteln (ich prüfe vor dem fortfahren ob der Index gültig ist!).
Bei den Klassen ohne zusätzliche, interne PRIVATE Felder, tritt kein Fehler auf. Bei den anderen nach 1-2 Aufrufen. Die onChange-Prozedur läuft korrekt zu Ende, aber danach wird eine Access Violation ausgelöst. Das seltsame ist, dass diese nicht der MessageBox meines Application.OnException Handlers entspricht.
Diese Meldung wird anscheinend irgendwo anders ausgelöst und ich weiss nicht wo...

Code:
access violation at 0x401c3c: write of address 0x5b
89 02 89 50 04 5B C3 90 8B 15 75 E4
EDIT:
Weitere Fehler die auftauchen (vom OnException Handler abgefangen):
- Ungültige Zeigeroperation (Zugriff auf eine Variable der Cipher: ICipher von TCustomCipher)
- Zugriffsverletzung, auch in DelphiMM.DLL (Beim Aufruf von SearchCipher)

Wenn ich den Combox mit dem Mausrad scrolle tritt sofort die zuerst genannte Access Violation auf. Wenn ich die Items manuell auswähle kriege ich nach einer Zeit einer der unteren Fehler. Und ich weiss nicht worans liegt...

Ich kann danach die Anwendung in Delphi nicht mehr weiterlaufen lassen (der RUN Button ist disabled). Wenn ich das Programm aus Windows heraus starte, wird die Anwendung nach dem Fehler ohne Warnung beendet.

Kann mir jemand helfen?

mfG
mirage228
David F.
  Mit Zitat antworten Zitat
Kamil

Registriert seit: 17. Aug 2002
178 Beiträge
 
#2

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 14. Dez 2003, 19:37
Ich hatte mal so ein ähnliches Problem: ich habe ein Interface an ein anderes Objekt übergeben. Sobald dann das Objekt mit dem Interface arbeiten wollte gab es Fehler. Die Lösung bei mir war ein explizites Aufrufen von _AddRef nach dem Übergeben des Interface und wenn es nicht mehr gebraucht wurde ein Aufruf von _Release.
  Mit Zitat antworten Zitat
Benutzerbild von mirage228
mirage228

Registriert seit: 23. Mär 2003
Ort: Münster
3.750 Beiträge
 
Delphi 2010 Professional
 
#3

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 14. Dez 2003, 21:17
Hi,

danke für deine Antwort.

Wo muss ich jetzt genau das _AddRef und _Release aufrufen. Bei mir dann in der Ladeprozedur von TCustomCipher?

Aufjeden fall konnte ich jetzt durch ein setzen von _AddRef bzw. _Release ein paar mal mehr darauf zugreifen, bevor wieder alles versagte...

EDIT: Durch Herumprobieren habe ich es solange geschaft durchzuhalten bis mein Programm mir den Fehler ausgab, dass die gewählte Verschlüsselung nicht in der Liste gefunden wurde. Im Evaluator hatten die Einträge alle keinen Namen, bis auf einen der den Namen Schriftart "Fixedsys" trug?!
Alles sehr seltsam...
EDIT2: Also bei einem Rekonstruierungsversuch ging es dann wieder nicht. Also da stimmt was wirklich ernsthaftes nicht...

mfG
mirage228
David F.
  Mit Zitat antworten Zitat
Kamil

Registriert seit: 17. Aug 2002
178 Beiträge
 
#4

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 00:39
Zeig mal ein wenig Code.

Ein paar Tipps:
-überschreibe _AddRef und _Release (mit dem selben Code wie TInterfacedObject) und schau dir den Wert von FRefCount an. Sobald er 0 wird, wird dein Objekt (Interface) zertört.
-beim Zugriff auf dein Objekt/Interface immer mit Assigned prüfen ob das Objekt noch existiert.

Ich weiß nicht wie gut du dich mit Interfaces auskennst:
Delphi-Quellcode:
//Dieser Code ist richtig:
procedure TForm1.Button8Click(Sender: TObject);
var
  MyInterface: IMyInterface;
  MyObject: TMyInterfacedObject;
begin
  MyObject:=TMyInterfacedObject.Create;
  MyInterface:=MyObject;
  MyObject.DoSomething;
  MyInterface.DoSomething;
end; //der Destruktor TMyInterfacedObject.Destroy wird automatisch aufgerufen!!!

//Dieser Code ist FALSCH!!!!!!
procedure TForm1.Button8Click(Sender: TObject);
var
  MyInterface: IMyInterface;
  MyObject: TMyInterfacedObject;
begin
  MyObject:=TMyInterfacedObject.Create;
  MyInterface:=MyObject;
  MyObject.DoSomething;
  MyInterface.DoSomething;
  MyObject.Free;
end; //Der Destruktor wird zwei mal aufgerufen -> Exception (Invalid pointer operation.)
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#5

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 01:04
Hallo mirage228,

wenn ich Deine Ausführungen richtig verstanden habe, liegt die Ursache des Problems in der heterogenen Verwendung von Klassen(-Objekten) und (Objekt-)Interfaces.
Bedingt durch das in Delphi verwendete Interface-Konzept wird bei der Arbeit mit Interfaces eine implizite Referenzzählung vorgenommen.

Der folgende Code
Delphi-Quellcode:
var
  myObject: IMyInterface
begin
  myObject:= GetAnObject;
  myObject.AMethod;
  myObject:= GetAnotherObject;
  myObject.AnotherMethod;
end;
wird deshalb vom Compiler um Code ergänzt, den man etwa so schreiben könnte
Delphi-Quellcode:
begin
  myObject:= GetAnObject;
  myObject._AddRef;
  myObject.AMethod;
  myObject._Release;
  myObject:= GetAnotherObject
  myObject._AddRef;
  myObject.AnotherObject;
  myObject._Release;
end;
Tatsächlich variiert der Aufruf von _Release ein wenig, so dass in diesem Beispiel die Methode erst nach dem Aufruf von GetAnotherObject aufgerufen wird, darüber hinaus sollte man sich die Referenzzählung von try..finally-Blöcken umschlossen vorstellen, der Einfachheit halber habe ich das aber vernachlässigt.

Betrachtet man nun die Implementierung von _Release in dem von Dir verwendeten Vorfahren TInterfacedObject:
Delphi-Quellcode:
function TInterfacedObject._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;
Erkennt man, dass Objekte dieses Typs freigegeben werden, sobald der Referenzzähler null erreicht hat. Weil ein solches Objekt nach dem Verlassen des Konstruktors mit null belegt ist führt dieser Code
Delphi-Quellcode:
var
  myClassicalObject: TInterfacedObject;
  myInterfacedObject: IInterface;
begin
  myClassicalObject:= TInterfacedObject.Create;
  myInterfacedObject:= myClassicalObject; // implicit call of _AddRef
  myInterfacedObject:= nil; // implicit call of _Release -> Free;

  // !myClassicalObject contains an invalid reference, now
  Showmessage(IntToStr(myClassicalObject.RefCount));
end;
zu Problemen (dass der Code fehlerfrei funktionieren kann, liegt an der Speicherverwaltung von Delphi, führt aber spätestens bei mehreren parallelen Verarbeitungssträngen zu Problemen).

Wenn Du Dich mit diesem Phänomen eingehender beschäftigen möchtest, empfehle ich Dir, eine Testklasse zu implementieren, die die Methoden _AddRef und _Release sowie den Aufruf des Destruktors protokolliert, bzw den Code im integrierten Debugger mit Debug-DCUs und einem Nachfahren von TInterfacedObject mit Breakpoints in den entsprechenden Zeilen der Unit System zu analysieren.

Lösen lassen sollte sich das Problem relativ einfach, indem Du entweder ausschließlich "klassische Objekte" oder Interfaces verwendest. Listen für den letzteren Fall lassen sich dann zB mithilfe von TInterfaceList realisieren...
gruß, choose
  Mit Zitat antworten Zitat
choose

Registriert seit: 2. Nov 2003
Ort: Bei Kiel, SH
729 Beiträge
 
Delphi 2006 Architect
 
#6

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 01:11
Hallo Kamil, netter Beitrag von Dir (auch die Bezeichnungen der Typen und Variablen gefallen mir gut ). Widersprechen muss ich Dir in diesem Punkt
Zitat von Kamil:
beim Zugriff auf dein Objekt/Interface immer mit Assigned prüfen ob das Objekt noch existiert.
Der Aufruf von Assigned prüft lediglich, ob eine Variable ungleich nil ist, so dass "verlorene Referenzen" mit dieser Funktion nicht aufgespürt werden können. Auch kann mit dieser schlichten Überprüfung nicht unterschieden werden, ob an einer bestimmten Speicherstelle tatsächlich einmal ein "Objekt (gewesen) ist" oder es sich bei dem als Referenz interpretierten Wert um "Müll" vom Stack handelt...
gruß, choose
  Mit Zitat antworten Zitat
Kamil

Registriert seit: 17. Aug 2002
178 Beiträge
 
#7

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 01:21
Ich gehe davon aus, dass Objekte nach dem Freigeben brav auf nil gestetzt werden oder FreeAndNil verwendet wird wenn Objekte mehrmals erstellt und gelöscht werden oder nicht unbedingt existieren müssen. Wenn das Objekt am Anfang erstellt und am Ende gelöscht wird hat es natürlich keinen Sinn. Ich glaube es gab erst letztens einen Beitrag über das verwenden von FreeAndNil.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#8

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 11:39
@Kamil, aber auch das nützt nicht viel, bei Mehrfachreferenzen auf dieses Object. Denn mit FreeAndNil() würde ja nur die Original Reference gesäubert. Alle anderen Referenzen zeigen denoch auf die ehemeals gültige Speicheradresse. Es bleibt technisch gesehen nur eine einzigste korrekte Annahme übrig, der Programmierer sollte über Reference Counting sicherstellen das zu jeder Zeit ein gültiges Object vorliegt.

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#9

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 11:42
@Mirage: ich würde gerne noch mehr über deine Library erfahren !? Soviel wie ich erahnen konnte willste Verschlüsselungsalgorithmen per Interfaces kapseln. Da ich selber schon sehr viel damit rumgebastelt habe würde ich gerne über das eigentliche Klassen-/Interface Konzept diskutieren. Bisher habe ich nämlich noch kein absolut sauberes Konzept gefunden, das alle wichtigen Interfaces unterstützen könnte.

Gruß Hagen
  Mit Zitat antworten Zitat
Benutzerbild von mirage228
mirage228

Registriert seit: 23. Mär 2003
Ort: Münster
3.750 Beiträge
 
Delphi 2010 Professional
 
#10

Re: Zugriffverletzung beim Verwenden von Interfaces

  Alt 15. Dez 2003, 13:15
Hallo,

danke für eure zahlreichen Antworten!

Mittlerweile bin ich mir schon sicher, dass eines (oder mehrere) meiner Objekte freigegeben wird und ich deshalb nicht mehr darauf zu greifen kann (bzw. nur mit oben genannten Fehlern).

Meine Annahme ist derzeit, das nach dem Benutzen in einer Prozedur im Hauptprogramm (Abrufen der Eigenschaften etc.) der Destructor aufgerufen und mein Objekt freigegeben wird und das die Fehler verursacht.

Ich werde heute nachmittag das ganze ausführlich debuggen, um hoffentlich die Fehlerquelle zu finden und diese zu beseitigen.

@negaH:

Ich hatte mein Konzept folgendermaßen geplant:
Ich habe das Interface ICipher, welche einige Get und Set Methoden für Eigenschaften, wie Namen und Beschreibung der Verschlüsselung hat, sowie Prozeduren, zum Ver- und Entschlüsseln von Texten und Dateien (insgesamt also 4). Sowie noch 2 Prozeduren der ich einen Stream übergebe, damit die Verschlüsselung ihre Einstellungen (falls erforderlich) darin speichern bzw. daraus lesen kann.

Jetzt müsste eigentlich jede Verschlüsselung DLL diese ganzen Get und Set Methoden implementieren. Da habe ich TCipher für geschrieben. Es ist abgeleitet von TInterfacedObject und ICipher implementiert diese Methoden und versieht zu dem die 6 anderen Prozeduren mit virtual; und abstract; damit diese von den Klassen der Verschlüsselung DLL überschrieben werden könnte. Das ganze ist jedoch optional. Wer möchte, kann auch trotzdem seine eigene Implementierung schreiben. TCipher vereinfacht das ganze jedoch. In meinen Verschlüsselungs-DLLs sind die Klassen von TCipher abgeleitet und überschreiben die 6 Prozeduren (Manche haben noch ein Paar private Variablen, z.B. zum Speichern der Schlüssellänge etc.) Die DLL exportiert diese Klasse mit eine Funktion die einen VAR Parameters des Typs ICipher erwartet.

Im Hauptprogramm habe ich dann die Klasse TCustomCipher, die dein ICipher Objekt und DLL Handle und Namen speichert. Beim Constructor wird eine DLL geladen und die Verschlüsselung aus der DLL importiert.

TCipherList rundet das ganze ab, in dem es alle .dll aus einem angegebenen Verzeichnis holt und dafür dann die TCustomCipher Objekte erstellt.

Im Programm suche ich mir dann die Verschlüsselung der Liste, zeige ihre Eigenschaften an oder Ver/Entschlüsse damit.

Ich hoffe das war das, was du wissen wolltest.

mfG
mirage228
David F.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:58 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