[gelöst] 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: 3479
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
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: 2260
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: 2260
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: 3479
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
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: 2260
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: 2260
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 » 2. Feb 2018, 18:44 Re: Interface als published property geht nicht

Ich versuche etwas mehr über das Verhalten des ObjektInspektors herauszufinden, damit ich ev. mehr gegen den Bug tun kann. Dazu versuche ich jetzt den ObjektInspektor alleine im Testprogramm zu verwenden, allerdings stosse ich da auf Probleme. Ich erstelle zur Laufzeit eine Form und füge ein Panel in die Form ein, das geht soweit und sieht man auch im Test-OI. Versuche ich in das Panel noch ein Panel einzufügen, so wird das nicht im OI angezeigt. Da habe ich irgendeinen Knopf in meiner Denkweise.

Das komplette Testprojekt liegt auf Github unter https://github.com/afriess/LazarusBug0032919

Hier nur der spezifische Code

Code: Alles auswählen
procedure TForm1.BuCreateClick(Sender: TObject);
begin
  BuCreate.Enabled:= false;
  BuFree.Enabled:= not BuCreate.Enabled;
 
  DUT := TObjectInspectorDlg.Create(nil);
 
  // create the PropertyEditorHook (the interface to the properties)
  ThePropertyEditorHook:=TPropertyEditorHook.Create(DUT);
  DUT.PropertyEditorHook:=ThePropertyEditorHook;
 
  // Create components
  ATestForm :=  TForm.Create(nil);
  // Create a Panel
  ATestPanel := TPanel.Create(ATestForm);
  ATestPanel.Parent:=ATestForm;
  ATestPanel.Caption:= 'Panel';
  // Create in the panel a panel (to see the chain)
  ATestPanelSub := TPanel.Create(ATestPanel);
  ATestPanelSub.Parent := ATestPanel;
  ATestPanelSub.Caption:= 'Sub Panel';
 
  ThePropertyEditorHook.LookupRoot:=ATestForm;
 
  PerList:=TPersistentSelectionList.Create;
  PerList.Add(ATestForm);
  DUT.Selection:=PerList;
  PerList.Free;
 
  DUT.Show;
end;
 


Wo habe ich da den Fehler gemacht ?

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

Beitragvon Michl » 2. Feb 2018, 21:03 Re: Interface als published property geht nicht

af0815 hat geschrieben:damit ich ev. mehr gegen den Bug tun kann
Ich hatte diesen mal zwei Tage lang sehr intensiv debuggt. Siehe auch http://www.lazarusforum.de/viewtopic.php?f=19&t=11350. Es liegt tatsächlich an der Reihenfolge, wie die Objekte freigegeben werden. Wenn das per Interface verbundene Objekt länger lebt, als das, was es eingebunden hat, ist alles gut. Sobald das per Interface eingebundene Objekt vorher gelöscht wird, kommt es zum SIGSEGV. Dazu muss man auch nicht Lazarus beenden, dies funktioniert auch, wenn man so ein Objekt erstellt, verbindet, löscht und dieses wiederholt (erst beim zweiten mal gibt es den SIGSEGV).

Bis dato hatte ich keine Möglichkeit gefunden, dem verbundenen Objekt mitzuteilen, daß bevor das per Interface verbundene Objekt gelöscht wird, dieses beim "Parent" auf nil zu setzen. Wenn ich mich recht erinnere, waren mehr oder weniger die Versuche letztlich an der Reffernzzählung gescheitert. Komischerweise funktioniert diese, wenn man händisch zuerst das Interface Objekt vom Parent entfernt. Dann geht das Löschen beider Objekte, egal welche Reihenfolge.

Zum aktuellen Problem (Standalone OI) kann ich nicht viel sagen. Mir fehlt es zur Zeit auch an Zeit, mich da hinein zu denken (in ein paar Wochen habe ich hoffentlich den Kopf wieder etwas freier). Vermutlich wirst du bessere/schnellere Antworten in der Lazarus-Mailing-List bekommen (afaik liest hier Mattias nicht mit).
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2260
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 » 2. Feb 2018, 22:16 Re: Interface als published property geht nicht

Michl hat geschrieben:Zum aktuellen Problem (Standalone OI) kann ich nicht viel sagen.

Der Standalone OI wurde von mir genommen um zu sehen ob das Problem auch ohne Debugging von Lazarus selbst zu isolieren ist. Die Probleme sind im Objectinspector aufgetreten bzw. im Bereich der Propertyeditoren. Deswegen habe ich versucht den OI als getrennte Einheit anzusehen, da auch die Kommentare im OI selbst darauf schliessen gelassen haben, das man den Universeller verwenden kann. Deswegen habe ich angefangen mich mit dem auseinanderzusetzen (im wahrsten Sinne des Wortes :-) ).

Danke nochmals

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

Beitragvon Soner » 4. Feb 2018, 17:47 Re: Interface als published property geht nicht

af0815 hat geschrieben:Ich versuche etwas mehr über das Verhalten des ObjektInspektors herauszufinden, damit ich ev. mehr gegen den Bug tun kann. Dazu versuche ich jetzt den ObjektInspektor alleine im Testprogramm zu verwenden, allerdings stosse ich da auf Probleme. Ich erstelle zur Laufzeit eine Form und füge ein Panel in die Form ein, das geht soweit und sieht man auch im Test-OI. Versuche ich in das Panel noch ein Panel einzufügen, so wird das nicht im OI angezeigt. Da habe ich irgendeinen Knopf in meiner Denkweise.

Das komplette Testprojekt liegt auf Github unter https://github.com/afriess/LazarusBug0032919

Hier nur der spezifische Code

Code: Alles auswählen
procedure TForm1.BuCreateClick(Sender: TObject);
begin
  BuCreate.Enabled:= false;
  BuFree.Enabled:= not BuCreate.Enabled;
 
  DUT := TObjectInspectorDlg.Create(nil);
 
  // create the PropertyEditorHook (the interface to the properties)
  ThePropertyEditorHook:=TPropertyEditorHook.Create(DUT);
  DUT.PropertyEditorHook:=ThePropertyEditorHook;
 
  // Create components
  ATestForm :=  TForm.Create(nil);
  // Create a Panel
  ATestPanel := TPanel.Create(ATestForm);
  ATestPanel.Parent:=ATestForm;
  ATestPanel.Caption:= 'Panel';
  // Create in the panel a panel (to see the chain)
  ATestPanelSub := TPanel.Create(ATestPanel);
  ATestPanelSub.Parent := ATestPanel;
  ATestPanelSub.Caption:= 'Sub Panel';
 
  ThePropertyEditorHook.LookupRoot:=ATestForm;
 
  PerList:=TPersistentSelectionList.Create;
  PerList.Add(ATestForm);
  DUT.Selection:=PerList;
  PerList.Free;
 
  DUT.Show;
end;
 


Wo habe ich da den Fehler gemacht ?

Andreas


Wenn man von ATestPanelSub als Eigentümer den Form angibt wird es in Komponententree sichtbar:
ATestPanelSub := TPanel.Create(ATestForm);

ZIemlich merkwürdiges verhalten, jedenfalls gibt es im ORdner Lazarus/Examples/objectinspector funktionierendes Beispiel.
Soner
 
Beiträge: 411
Registriert: 26. Sep 2012, 23:07
Wohnort: Hamburg
OS, Lazarus, FPC: Win7Pro-32Bit, Immer letzte Lazarus Release mit SVN-Fixes | 
CPU-Target: 32Bit
Nach oben

Beitragvon Soner » 4. Feb 2018, 17:52 Re: Interface als published property geht nicht

Ich habe jezt im Beispiel von Lazarus\examples\objectinspector ein Subpanel wie in dein Beispiel erstellt, da wird es auch nicht angezeigt wenn man Parent als Eigentümer angibt, mann muß Root-Komponente(hier Form1) angeben damit es angezeigt wird. Entweder Bug in Komponententree oder gewollt.
Soner
 
Beiträge: 411
Registriert: 26. Sep 2012, 23:07
Wohnort: Hamburg
OS, Lazarus, FPC: Win7Pro-32Bit, Immer letzte Lazarus Release mit SVN-Fixes | 
CPU-Target: 32Bit
Nach oben

Beitragvon af0815 » 15. Feb 2018, 20:08 Re: Interface als published property geht nicht

Es geht jetzt, dank eines Hints von Mathias Gärtner, Beim Create MUSS man immer die Form/Frame angeben, als Parent dann denjenigen dessen Parent das ist. Es geht jetzt auch mit meinen Code bei Github.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3479
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon af0815 » 18. Feb 2018, 18:19 [gelöst] Interface als published property geht nicht

Zück zu meinem eigentlich Problem, sieh Überschrift. Da habe ich gerade einen Tip von Martin Schreiber auf der Mailingliste bekommen:
Code: Alles auswählen
If you want to set a COM interface pointer to nil without calling _release() 
use
" pointer(FObjectHasInterface):= nil;"
 


Ich habe in mein Object einen eigenen destructor eingefügt, der die Verbindung zum Interface bei abräumen der Objekte korrekt auflöst. Wenn man das Objekt einfach nil setzt, so wird im Hintergrund automatisch ein _Release ausgelöst und damit das Interface-Objekt hier falsch gelöscht.
Code: Alles auswählen
destructor TIntfComp.Destroy;
begin
  pointer(FObjectHasInterface):= nil;
//  FObjectHasInterface:= nil;
  inherited Destroy;
end;
 

Martin hat das auf der Mailingliste sehr schön mit der Begriffserklärung klar gemacht.
Code: Alles auswählen
 It is 
an undefined "implementation detail" when the interface variable goes out of
scope, there is a risk that it goes out of scope and _release() will be
called after the according object has been destroyed by a TObject.Destroy()
call.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3479
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon mse » 19. Feb 2018, 09:08 Re: [gelöst] Interface als published property geht nicht

Ein wichtiger Hinweis in diesem Zusammenhang:
Wenn man keine Interface-Referenzzählung benötigt, sondern die Lebensdauer der Objekte mittels TObject.Destroy()/Free() oder dem TComponent.Owner-Mechanismus steuern will, sollte man CORBA-Interfaces verwenden.
Code: Alles auswählen
 
{$interfaces corba}
type
 meincorbainterface = interface
[...]
 end;
 

COM-Interface sollten meiner Meinung nach lediglich zur Kommunikation mit externen Windows Active-X-Elementen verwendet werden, innerhalb einer FPC-Anwendung sollten sie nicht eingesetzt werden. Sehr problematisch ist die Kombination von TComponent und COM-Interface.
Als MSEgui noch Delphi-kompatibel war, war ich bei der Delphi-Version gezwungen COM Interface einzusetzen, da Delphi keine nicht-referenz-gezählten Interface kennt. Es war ein Albtraum...
mse
 
Beiträge: 1986
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Michl » 22. Feb 2018, 22:14 Re: [gelöst] Interface als published property geht nicht

@mse: Eigentlich funktionieren jetzt COM Interface Properties im Designer von Lazarus. Soviel ich sehen kann, haben wir zur Zeit nur das Problem, wenn das verbundene Objekt zuerst gelöscht wird, daß dieses auch auf nil im Property gesetzt wird. Das funktioniert unter 32bit so:
Code: Alles auswählen
{$interfaces com}
  ITestInterface = interface
    ['{DC209DB2-6E2D-4680-93D6-5D9B3983C0D3}']
    function OnlyDummy: integer;
  end;
{$interfaces com}     
 
  TIntfComp = class(TComponent)
  private
    FObjectHasInterface: ITestInterface;
    function GetObjectHasInterface: ITestInterface;
    procedure SetObjectHasInterface(AValue: ITestInterface);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    destructor Destroy; override;
  published
    property ObjectHasInterface: ITestInterface read GetObjectHasInterface write SetObjectHasInterface;
  end;
 
...
 
procedure TIntfComp.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  // if ObjectHasInterface is being removed then we need to make sure it is
  // removed from here too
  // WriteLn('TIntfComp.Notification ', dbgs(PtrInt(AComponent)), ' ', dbgs(PtrInt(ObjectHasInterface)), ' ', dbgs(SizeOf(AComponent)));
  if (Operation = opRemove) and (PtrInt(AComponent) + $30 = PtrInt(ObjectHasInterface)) then
    Pointer(FObjectHasInterface) := nil;
end;

Kannst du mir erklären, warum ich unter 32bit ein Offset von 48 und bei 64bit ein Offset von 88 habe, wenn ich testen will, ob der Zeiger auf AComponent gleich Zeiger auf ObjectHasInterface ist?! (ObjectHasInterface ist eine Instanz von TCompInterface = class(TComponent, ITestInterface) )
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2260
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

» Weitere Beiträge siehe nächste Seite »
VorherigeNächste

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: Google [Bot] und 3 Gäste

porpoises-institution
accuracy-worried