Interface als published property geht nicht

Rund um die LCL und andere Komponenten

Re: Interface als published property geht nicht

Beitragvon af0815 » 4. Jan 2018, 16:36 Re: Interface als published property geht nicht

Ich teste gerade mit aktuellen fpc trunk und Lazarus trunk, die habe ich komplett auf einer persistenten Ramdisk. Wenn es funktioniert teste ich es später auf stabilen fpc für Lazarus fixes 1.8.x. Aktuell sind also die letzten Erkenntnisse auf trunk/trunk basierend.

Generell halte ich das Problem komplett Lazarus sitzend. Beim FPC habe ich die entsprechenden Tests gefunden und dort ist meiner Meinung nach alles dafür vorhanden und auch eingebunden. Was ich sehe im Code des ObjectInpektors von Lazarus, das die Verwendung der Interfaces gar nicht richtig/komplett vorbereitet sind.

Ein Problem ist, das ein Interface nicht von TObject (und Nachfahren abstammt).
Code: Alles auswählen
Index: components/ideintf/objectinspector.pp
===================================================================
--- components/ideintf/objectinspector.pp   (revision 56931)
+++ components/ideintf/objectinspector.pp   (working copy)
@@ -2204,7 +2204,10 @@
   if (not (paSubProperties in Row.Editor.GetAttributes)) then exit;
   // check if circling
   if (Row.Editor is TPersistentPropertyEditor) then begin
-    AnObject:=TPersistent(Row.Editor.GetObjectValue);
+    if (Row.Editor is TInterfacePropertyEditor) then
+      AnObject:=TPersistent(Row.Editor.GetIntfValue)
+    else
+      AnObject:=TPersistent(Row.Editor.GetObjectValue);
     if FSelection.IndexOf(AnObject)>=0 then exit;
     ParentRow:=Row.Parent;
     while ParentRow<>nil do begin
 

es ist mir durch die Warnungen beim Kompileren des obigen Teil des Patches aufgefallen. Der erzwungene Cast AnObject:=TPersistent(Row.Editor.GetIntfValue) ist genaugenommen nicht erlaubt, da TPersistent kein Nachfahre von TInterface ist.

Ich habe noch nicht wirklich eine Idee wie das alles zusammenhängen kann. Das Problem tritt aber erst auf, wenn man wie im Bugrport beschrieben die Zuweisung macht. Nicht vorher.

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3292
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon Michl » 4. Jan 2018, 23:00 Re: Interface als published property geht nicht

Ja das aufräumen funktioniert noch nicht richtig. Sehe ich auch:

Code: Alles auswählen
#0 fpc_intf_decr_ref(0x153f64f8) at ..\inc\objpas.inc:59
#1 fpc_finalize(0x11df6c4c, 0x11eb228) at ..\inc\rtti.inc:349
#2 RECORDRTTI(0x11df6c18, 0x11eb27b, {procedure (POINTER, POINTER)} 0xe97ea30) at ..\inc\rtti.inc:227
#3 CLEANUPINSTANCE(0x11df6c18) at ..\inc\objpas.inc:745
#4 FREEINSTANCE(0x11df6c18) at ..\inc\objpas.inc:436
#5 DESTROY(0x11df6c18, 0x1) at ..\objpas\classes\compon.inc:494
#6 DESTROYCOMPONENTS(0x13b814f0) at ..\objpas\classes\compon.inc:513
#7 DESTROY(0x13b814f0, 0x0) at ..\objpas\classes\compon.inc:491
#8 DESTROY(0x13b814f0, 0x0) at lclclasses.pp:135
#9 DESTROY(0x13b814f0, 0x0) at include\control.inc:5137
#10 DESTROY(0x13b814f0, 0x0) at include\wincontrol.inc:6627
#11 DESTROY(0x13b814f0, 0x0) at include\customcontrol.inc:54
#12 DESTROY(0x13b814f0, 0x0) at include\scrollingwincontrol.inc:316
#13 DESTROY(0x13b814f0, 0x1) at include\customform.inc:212
#14 FREE(0x13b814f0) at ..\inc\objpas.inc:336
#15 DESTROYJITCOMPONENT(0x119f4448, 0) at ..\designer\jitforms.pp:777
#16 DESTROYJITCOMPONENT(0x119f4448, 0x13b814f0) at ..\designer\jitforms.pp:765
#17 DELETECOMPONENT(0x119d3c38, 0x13b814f0, true) at customformeditor.pp:563
#18 PREPAREFREEDESIGNER(0x100f3cc0, true) at ..\designer\designer.pp:814
#19 CLOSEUNITCOMPONENT(0x1193bcb8, 0x21eb70, []) at sourcefilemanager.pas:7638
#20 CLOSEEDITORFILE(0x1193bcb8, 0x10155720, [CFPROJECTCLOSING]) at sourcefilemanager.pas:2768
#21 CLOSEPROJECT(0x1193bcb8) at sourcefilemanager.pas:4385
#22 DOCLOSEPROJECT(0x105300c0) at main.pp:6237
#23 MAINIDEFORMCLOSEQUERY(0x105300c0, 0x11626258, false) at main.pp:2052
#24 CLOSEQUERY(0x11626258) at include\customform.inc:2247
#25 CLOSE(0x11626258) at include\customform.inc:2157
#26 WMCLOSEQUERY(0x11626258, {MSG = 66622, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\customform.inc:2255
#27 DISPATCH(0x11626258, 0) at ..\inc\objpas.inc:674
#28 WNDPROC(0x11626258, {MSG = 66622, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\control.inc:2254
#29 WNDPROC(0x11626258, {MSG = 66622, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\wincontrol.inc:5407
#30 WNDPROC(0x11626258, {MSG = 66622, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\customform.inc:1467
#31 WNDPROC(0x11626258, {MSG = 66622, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at mainbar.pas:551
#32 DELIVERMESSAGE(0x11626258, 0) at lclmessageglue.pas:112
#33 DOWINDOWPROC(0x22a9d8) at win32\win32callback.inc:2529
#34 WINDOWPROC(918956, 16, 0, 0) at win32\win32callback.inc:2691
#35 CUSTOMFORMWNDPROC(918956, 16, 0, 0) at win32\win32wsforms.pp:386
#36 gapfnScSendMessage at :0
#37 ?? at :0
#38 USER32!GetThreadDesktop at :0
#39 WIN32WSFORMS$_$TWIN32WSSCROLLBOX_$__$$_CREATEHANDLE$TWINCONTROL$TCREATEPARAMS$$LONGWORD at :0
#40 USER32!GetThreadDesktop at :0
#41 ?? at :0
 
Irgendwie scheint die Referenzzählung nicht zu passen.

Leider bin ich zur Zeit echt eingespannt, versuche aber wenn ich demnächst Zeit habe, dies zu debuggen. Evtl. findest du ja aber schneller die Ursache?! :)
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2210
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon Michl » 4. Jan 2018, 23:17 Re: Interface als published property geht nicht

Nur kurz getestet: wenn man zur Designzeit eine Komponente (die dieses Interface hat) dem TIntfComp.ObjectHasInterface zuweist und wieder entfernt (egal, ob die Komponente auf dem Form verbelibt oder nicht), tritt dieser Fehler nicht auf.

Evtl. muss man beim Aufräumen der Komponenten, die vorziehen, die per Interface als Property verbunden sind.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2210
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon af0815 » 5. Jan 2018, 10:08 Re: Interface als published property geht nicht

Nachdem ich kein Problem mit der Zeit bei diesem privaten Projekt habe - das mit den Interface Based, geht auf eine (alte) Idee aus einem sehr interessanten Buch* zurück, Programmierung auf Interfaces nicht auf Objekte - brennt es mir nicht. Ausserdem kann ich sehr viel über den OI unter Lazarus lernen.

Eines der Probleme ist, das ich für den OI keinerlei Tests finde. Das würde die Sache wesentlich erleichtern. Tests für die Komponente IDEIntf sind bis auf einen MenueIntf nicht vorhanden. Ich gehe davon aus das der OI genaugenommen nicht getestet wird. Das erklärt für mich einiges :-)
Laut der internen Beschreibung im OI ist der sehr wohl auch standalone nutzbar, somit sollten auch Test machbar sein. Was ich jetzt einmal verstehen muss, ist wie bzw. wo die Komponenten gespeichert sind und wie man diese Speicherung nachbauen kann, damit der OI richtig läuft.

* Building Object Applications That Work von Scott W. Ambler, Cambridge University Press, ISBN 0-521-64826-2 1998 :-)
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3292
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: Win7/Linux (L stable FPC stable) per fpcup | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon Michl » 5. Jan 2018, 21:58 Re: Interface als published property geht nicht

Zu den Tests und Objectinspector allgemein, kann ich leider aus dem Stegreif auch nichts sagen. Vieles versteht man, wenn man den Code liest bzw. debuggt (zumindest mir hilft es). Da Mattias als Autor am besten Bescheid wissen müsste, wäre der richtige Ort für eine Frage diesbezüglich die Lazarus Mailing-List.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2210
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon Michl » 5. Jan 2018, 23:06 Re: Interface als published property geht nicht

Wie oben vermutet, liegt der Fehler in der Reihenfolge der Freigaben. Ein einfaches Beispiel demonstiriert das (Heaptrc muss aktiviert sein):
Code: Alles auswählen
procedure TForm1.FormCreate(Sender: TObject);
begin
  FIntfComp := TIntfComp.Create(nil);
  FCompInterface := TCompInterface.Create(nil);
  FIntfComp.ObjectHasInterface := FCompInterface;
end;

gebe ich nun den Speicher wie folgt frei:
Code: Alles auswählen
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FIntfComp.Free;
  FCompInterface.Free;
end;
kommt es zu keinem SIGSEGV,

so schon:
Code: Alles auswählen
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FCompInterface);
//  FIntfComp.ObjectHasInterface := nil;  // <- auch so gibt es den SIGSEGV
  FIntfComp.Free;
end;


Bei:
Code: Alles auswählen
unit IntfComp;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs;
 
type
 
  // define the Interface
 
  { ITestInterface }
 
    ITestInterface =  interface
      ['{DC209DB2-6E2D-4680-93D6-5D9B3983C0D3}']
      function OnlyDummy: integer;
    end;
 
  { TIntfComp }
 
  TIntfComp = class(TComponent)
  private
    FObjectHasInterface: ITestInterface;
    function GetObjectHasInterface: ITestInterface;
    procedure SetObjectHasInterface(AValue: ITestInterface);
  public
    destructor Destroy; override;
  published
    property ObjectHasInterface: ITestInterface read GetObjectHasInterface write SetObjectHasInterface;
  end;
 
  { TCompInterface }
 
  TCompInterface = class(TComponent, ITestInterface)
  private
    function OnlyDummy: integer;
  end;
 
 
procedure Register;
 
implementation
 
procedure Register;
begin
  RegisterComponents('ShowBug',[TIntfComp, TCompInterface]);
end;
 
{ TCompInterface }
 
function TCompInterface.OnlyDummy: integer;
begin
  Result := -1;
end;
 
{ TIntfComp }
 
function TIntfComp.GetObjectHasInterface: ITestInterface;
begin
  Result:= FObjectHasInterface;
end;
 
procedure TIntfComp.SetObjectHasInterface(AValue: ITestInterface);
begin
  FObjectHasInterface:= AValue;
end;
 
destructor TIntfComp.Destroy;
begin
  FObjectHasInterface := nil;
  inherited Destroy;
end;
 
end.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2210
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

• Themenende •
Vorherige

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste

porpoises-institution
accuracy-worried