Einzelnen Beitrag anzeigen

Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

AV bei Spring.Event<> auf VCL-Komponenten und FastMM FullDebugMode

  Alt 27. Nov 2014, 20:12
Ich bin absolut ratlos. Ich platziere einen Frame (TContainedFrame) auf einem Formular (TMyForm). Der Frame hat eine public var OnClickedAButton: Event<TNotifyEvent> .

Im OnCreate-Event des Formulars füge ich eine Methode des Formulars zum Event des Frames hinzu:
Delphi-Quellcode:
procedure TMyForm.FormCreate(Sender: TObject);
begin
   containedFrame.OnClickedAButton.Add(handleAButtonClick);
end;

procedure TMyForm.handleAButtonClick(Sender: TObject);
begin
   Caption := 'A button in '+Sender.ClassName+' was clicked';
end;

Das Problem: Der Destruktor von TContainedFrame erzeugt eine Zugriffsverletzung mit folgendem, mysteriösen Callstack:
Code:
System.Classes.{System.Generics.Collections}TList<System.Classes.TComponent>.IndexOf(???)
System.Classes.{System.Generics.Collections}TList<System.Classes.TComponent>.Remove(???)
System.Classes.TComponent.RemoveNotification($9672)
System.Classes.TComponent.RemoveFreeNotification($7EF3A7D0)
System._IntfClear(???)
:004CE51F System::Generics::Collections::TList__1<System::Classes::TComponent *>::IndexOf(????)
Ich kann diese AV auch manuell herbeiführen wenn ich im Destruktor von TContainedFrame einfach nur OnClickedAButton := nil; sage.

Ja, die Abhilfe wäre, dort stattdessen OnClickedAButton.Clear(); zu sagen. Aber warum ist das so? Die AV bekomme ich nur, wenn ich FastMM4 im FullDebugMode verwende.


Noch komischer: Ist keine VCL im Spiel, läuft folgender Code, trotz FastMM, problemlos durch:

Delphi-Quellcode:
program Project14;

{$APPTYPE CONSOLE}
{$R *.res}
uses FastMM4, System.SysUtils, System.Classes, Spring;

type
   TContainedClass = class
      public var
         myEvent: Event<TNotifyEvent>;
   end;

   TMyClass = class
      protected var
         containedInstance: TContainedClass;
      protected
         procedure handleEvent(Sender: TObject);
      public
         constructor Create();
         destructor Destroy(); override;
   end;

constructor TMyClass.Create;
begin
   containedInstance := TContainedClass.Create();
   containedInstance.myEvent.Add(handleEvent);
end;

destructor TMyClass.Destroy;
begin
   containedInstance.Free();
   inherited;
end;

procedure TMyClass.handleEvent(Sender: TObject);
begin
   //
end;

begin
  try
   TMyClass.Create().Destroy();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Ich habe absolut keinen Ansatz, warum das hier so passiert. Ja, es ist ein wilder Wust von irgendeinem speziellen Spezialproblem. Aber jede wilde Idee macht mich froh
  Mit Zitat antworten Zitat