AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Supports ohne out Parameter

Ein Thema von pflaume · begonnen am 10. Okt 2012 · letzter Beitrag vom 10. Okt 2012
Antwort Antwort
Seite 1 von 2  1 2      
pflaume

Registriert seit: 3. Nov 2007
3 Beiträge
 
#1

Supports ohne out Parameter

  Alt 10. Okt 2012, 10:28
Delphi-Version: 2009
Hallo,

Ich werde nicht so recht schlau aus dem was genau bei den folgenden Situationen passiert.
Es geht um diese Funktion aus der SysUtils.pas:

function Supports(const Instance: TObject; const IID: TGUID): Boolean; Wenn man das unten stehende Programm ausführt, verabschiedet es sich an markierter Stelle #1 mit einer
EInvalidPointer Exception (wahrscheinlich beim Freigeben der temporären Variable aus einer anderen
Supports() Überladung).

Delphi-Quellcode:
program Project38;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  IFirst = interface
    ['{BC927DB0-9B4D-49C4-8460-6714605F4F20}']
  end;

  ISecond = interface
    ['{F7DBA334-8216-4435-AD56-2E9465CE975B}']
  end;

  TFirstSecond = class(TInterfacedObject, IFirst, ISecond)
  end;

var
  a: TFirstSecond;
  f: IFirst;
  s: ISecond;

begin
  a := TFirstSecond.Create;

  if Supports(a, IFirst) then
    Writeln('a supports IFirst');

  if Supports(a, ISecond) then // #1
    Writeln('a supports ISecond');

  if Supports(a, IFirst, f) then
    Writeln('[out] a supports IFirst');

  if Supports(a, ISecond, s) then
    Writeln('[out] a supports ISecond');

  Readln;
end.
Ändert man das folgende Programm ab und ersetzt die Writeln Aufrufe durch ShowMessage,
verschwindet dieser Fehler.

Delphi-Quellcode:
program Project38;

{$APPTYPE CONSOLE}

uses
  Dialogs,
  SysUtils;

type
  IFirst = interface
    ['{BC927DB0-9B4D-49C4-8460-6714605F4F20}']
  end;

  ISecond = interface
    ['{F7DBA334-8216-4435-AD56-2E9465CE975B}']
  end;

  TFirstSecond = class(TInterfacedObject, IFirst, ISecond)
  end;

var
  a: TFirstSecond;
  f: IFirst;
  s: ISecond;

begin
  a := TFirstSecond.Create;

  if Supports(a, IFirst) then
    ShowMessage('a supports IFirst');

  if Supports(a, ISecond) then
    ShowMessage('a supports ISecond');

  if Supports(a, IFirst, f) then
    ShowMessage('[out] a supports IFirst');

  if Supports(a, ISecond, s) then
    ShowMessage('[out] a supports ISecond');

  Readln;
end.
Hinzu kommt das der erste Aufruf von Supports() ohne out Parameter, scheinbar
die Variable a verändert. Leider reicht mein Assemblerwissen nicht ganz aus
um alles nachzuvollziehen was in class function TObject.GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
geschiet.
Nach meinem Verständnis müssten alle vier Meldungen angezeigt werden, stattdessen wird nur die erste angezeigt.

Vielleicht kann jemand Licht ins Dunkel bringen
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 10:41
Verwende mal TComponent, statt dem TInterfacedObject. [edit] oder TInterfacedPersistent, dessen Name ich ständig vergesse (Dank an Uwe)

Du nutzt das TFirstSecond als Objekt-Instanz, womit es intern keine Interfacereferenz gibt.
Suppots greift aber intern über ein Interface zu, womit also eine Interface-Referenz erstellt wird. Bei Freigabe dieser Referenz wird dann das ganze Objekt freigegeben, da es keine weiteren Referenzen gibt.

In TComponent wird die Referenzzählung der Interfaces "ignoriert" und diese steuern vorallem nicht die Freigabe.
$2B or not $2B

Geändert von himitsu (10. Okt 2012 um 11:11 Uhr)
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#3

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 10:42
Hallo,

ich vermute einfach mal (hab gerade kein Delphi zur Hand), dass Supoorts intern AddRef / Release aufruft. Durch das Release wird dann das Objekt freigegeben und schon knallt's.
Eine mögliche Lösung (die viele Probleme vermeidet) ist, immer mit Interfaces zu arbeiten und nie mit dem konkreten Objekt. Alternativ gibt es noch ein Basisobjekt, das die Referenzzählung ausschaltet. Da musst Du aber wissen, was Du tust. Solltest Du aber bei Interfaces immer

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#4

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 10:47
Die anderen haben es ja schon erklärt. Das Support ohne out-Parameter ruft intern das mit out-Parameter auf, wobei das temporäre Interface beim Verlassen der Funktion freigegeben wird. Da a ein TFirstSecond ist, was von TInterfacedObject abgeleitet wurde, ist der interne Referenzzähler nach dem Create Null. Wenn jetzt die implizite Referenzzählung ein Add/Release ausführt, wird beim Release der Referenzzähler wieder zu Null und die Instanz wird freigegeben. Ab dann zeigt a auf eine nicht mehr existente Instanz.

Wenn du sowohl mit Interfaces als auch mit Objekt-Instanzen arbeiten willst, kannst du statt TInterfaceObject auch TInterfacedPersistent nehmen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
pflaume

Registriert seit: 3. Nov 2007
3 Beiträge
 
#5

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:10
Danke für die Antworten, das mit Referenzzählung hätte mir auffallen müssen, aber
was ist mit dem zweiten Teil der Frage?
Wie und warum genau verändert Supports() die Instanz so das bei dem Aufruf von
Supports(a, ISecond) als Rückgabe Wert false rauskommt?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#6

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:20
aber was ist mit dem zweiten Teil der Frage?
Wenn du TInterfacedPersistent verwendest, dann passiert das bei dir immernoch?
$2B or not $2B
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#7

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:27
Ich verstehe nicht, weshalb Dir alle raten, nicht TInterfacedObject zu verwenden... Ändere einfach
Delphi-Quellcode:
var
  a: TFirstSecond;
in
Delphi-Quellcode:
var
  a: IInterface;
und alles funktioniert.
Thomas Nitzschke
Google Maps mit Delphi

Geändert von Thom (10. Okt 2012 um 12:34 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#8

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:36
Danke für die Antworten, das mit Referenzzählung hätte mir auffallen müssen, aber
was ist mit dem zweiten Teil der Frage?
Wie und warum genau verändert Supports() die Instanz so das bei dem Aufruf von
Supports(a, ISecond) als Rückgabe Wert false rauskommt?
Offensichtlich war meine Erklärung nicht verständlich genug: Es ist nicht das QueryInterface was die Referenzzählung auslöst, sondern die Implementierung des Supports ohne out-Parameter:

Delphi-Quellcode:
function Supports(const Instance: IInterface; const IID: TGUID): Boolean;
var
  Temp: IInterface;
begin
  Result := Supports(Instance, IID, Temp);
end;
Nach dem a := TFirstSecond.Create ist der Referenzzähler von a = 0. Beim ersten Aufruf von Supports wird in der Support-Funktion für Temp ein implizites AddRef und Release ausgelöst, da beim Verlassen der Funktion alle lokalen Interface-Variablen auf nil gesetzt werden. Beim Release springt der Referenzzähler wieder auf 0 und die Instanz wird freigegeben. Danach verweist a nicht mehr auf eine gültige Instanz und es geschehen nicht vorhersagbare Dinge.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#9

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:40
Ich verstehe nicht, weshalb Dir alle raten, nicht TInterfacedObject zu verwenden... Ändere einfach
Delphi-Quellcode:
var
  a: TFirstSecond;
in
Delphi-Quellcode:
var
  a: IInterface;
und alles funktioniert.
Dieses Vorgehen ist aber nicht in jedem Fall anwendbar. Man muss sich schon entscheiden, ob man nur mit Interface-Referenzen und Referenzzählung arbeiten will, oder ob man ohne Referenzzählung selber die Objekt-Instanzen verwalten will. Für beide Vorgehen gibt es je nach Anwendungsfall gute Gründe. Man muss dann nur die passende Elternklasse verwenden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#10

AW: Supports ohne out Parameter

  Alt 10. Okt 2012, 12:51
War im Beispiel der falsche Overload der Funktion - der richtige enthält übrigens eine entsprechende Warnung:

Delphi-Quellcode:
function Supports(const Instance: TObject; const IID: TGUID): Boolean;
var
  Temp: IInterface;
begin
  // NOTE: Calling this overload on a ref-counted object that has REFCOUNT=0
  // will result in it being freed upon exit from this routine.
  Result := Supports(Instance, IID, Temp);
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 20:04 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