AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi GDI+: IStream oder TStreamAdapter
Thema durchsuchen
Ansicht
Themen-Optionen

GDI+: IStream oder TStreamAdapter

Ein Thema von ken_jones · begonnen am 20. Aug 2012 · letzter Beitrag vom 21. Aug 2012
Antwort Antwort
ken_jones

Registriert seit: 16. Mai 2005
Ort: Luzern
154 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

GDI+: IStream oder TStreamAdapter

  Alt 20. Aug 2012, 18:04
Ich hatte bis eben gerade ein Problem, es nun gelöst, aber nicht ganz begriffen wieso es jetzt geht. Kann mir einer von euch Cracks eine Hinweis geben?

Meine Applikation verwendet GDI+ (unter DXE2,Win7) und versucht einen JPG-Stream in eine GPBitmap zu laden.

Folgender Code (wie er überall im Netz zu finden ist und funktionieren sollte) funktioniert bei mir nicht:

Delphi-Quellcode:
procedure TfrmMain.TestProc(Jpegdata: TMemoryStream);
var
  Image : IGPBitmap;
  Graphics : IGPGraphics;
  SA : TStreamAdapter;
begin
  Graphics := TGPGraphics.Create(imgVorschau.Canvas.Handle);
  try
    sa := TStreamAdapter.Create(JpegData);
    Image := TGPBitmap.Create(sa);
    Graphics.DrawImage(Image, 0, 0, Image.Width, Image.Height);
  except
    ...
  end;
end;
Folgender Code schon, aber wieso?

Delphi-Quellcode:
procedure TfrmMain.TestProc(Jpegdata: TMemoryStream);
var
  Image : IGPBitmap;
  Graphics : IGPGraphics;
  SA : IStream;
begin
  Graphics := TGPGraphics.Create(imgVorschau.Canvas.Handle);
  try
    sa := TStreamAdapter.Create(JpegData);
    Image := TGPBitmap.Create(sa);
    Graphics.DrawImage(Image, 0, 0, Image.Width, Image.Height);
  except
    ...
  end;
end;
Einzig hab ich den SA von TStreamAdapter auf IStream geändert, aber ich erzeuge nach wie vor den TStreamAdapter auf diese Variable.
Ist das Zufall, dass das jetzt bei mir läuft (und dann früher oder später doch wieder crashed) oder geht das so in Ordnung?

Danke für Hints!
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

AW: GDI+: IStream oder TStreamAdapter

  Alt 20. Aug 2012, 19:01
Die 1. Variante ist falsch und die 2. Variante ist richtig.
Der kommentierte Code macht es vielleicht verständlich:
Delphi-Quellcode:
var
  SA : TStreamAdapter;
...
    // hier wird ein Objekt vom Typ TStreamAdapter erzeugt
    sa := TStreamAdapter.Create(JpegData);

    // beim Aufruf wird im Hintergrund aus dem Objekt ein IStream-Interface erzeugt
    // und dessen Referenzzähler um 1 hochgezählt
    Image := TGPBitmap.Create(sa);
    // nach dem Aufruf wird der Referenzzähler um 1 runtergezählt
    // da nun aber der RefCount = 0 ist wird Free & Destroy aufgerufen

    // zu diesem Zeitpunkt ist der StreamAdapter schon tot, obwohl er eigentlich jetzt gebraucht würde
    Graphics.DrawImage(Image, 0, 0, Image.Width, Image.Height);
Rein theoretisch sollte Delphi merken, dass das übergebene IStream-Interface innerhalb von TGPBitmap noch benützt wird.
Dazu müsste die Klasse TGPBitmap intern aber _AddRef() aufrufen, tut es anscheinend aber nicht.
Andreas
  Mit Zitat antworten Zitat
ken_jones

Registriert seit: 16. Mai 2005
Ort: Luzern
154 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: GDI+: IStream oder TStreamAdapter

  Alt 20. Aug 2012, 20:11
Vielen herzlichen Dank für die schnelle Antwort!
Das ist eine sehr interessante Erklärung für dieses Phänomen. Ich werde mich bei nächster Gelegenheit mal dahinterklemmen und das Untersuchen.
Aber dein Tipp ist Gold wert! Danke!

Gruss,
ken
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: GDI+: IStream oder TStreamAdapter

  Alt 20. Aug 2012, 21:07
Objektreferenzen sind nicht mir einer Referenzzählung versehen ... niemals.
Also wird Delphi da auch niemals _AddRef aufrufen.

Bei Übergabe an den Constructor, als Interface, wird bei Aufruf des Constructor eine Interface-Referenz erstellt und demnach auch _AddRef aufgerufen.
Bei Austritt aus dem Custructor wird diese Referenz nicht mehr benötigt und _Release aufgerufen, womit die Referenzählung runterzählt, auf 0 kommt und das Interface/Objekt freigibt.

Antwort: Kombiniere niemals Objektreferenzen mit Interfacereferenzen. (nicht ohne die Referenzzählung für diesen Fall außer Kraft zu setzen),
denn Objektreferenzen werden immer über Free/Destroy freigegeben und Interfaces geben sich selber frei (durch die Referenzzählung ausgelöst) und des darf niemals mehrere "Owner" geben (wenn diese nicht alle voneinander wissen und sich gegenseitig Benachrichtigen, wenn einer alles auflöst, bzw. nicht ohne die anderen Owner irgendwie über die zusätzlichen Referenzen in den Ownern zu informieren).

In diesem Fall wird ein Interface (IStream) benötigt, also sollte auch ausschließlich nur mit Interface-Referenzen gearbeitet werden.
$2B or not $2B

Geändert von himitsu (20. Aug 2012 um 21:13 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#5

AW: GDI+: IStream oder TStreamAdapter

  Alt 21. Aug 2012, 01:02
Ich hatte das seinerzeit weggekapselt um "es von der Backe zu haben"
Delphi-Quellcode:
    TGPImageWrapper=Class(TObject)
       private
       FImage: TGPImage;
       FStream: TMemoryStream;
       public
       Constructor Create(AGraphic:TGraphic);overload;
       Constructor Create(FileName: String);overload;
       Destructor Destroy;override;
       Public
       Property Image:TGPImage read FImage;
..........
.........


constructor TGPImageWrapper.Create(AGraphic: TGraphic);
begin
  inherited Create;
  FStream := TMemoryStream.Create;
  AGraphic.SaveToStream(FStream);
  Fimage:= TGPImage.Create(TStreamAdapter.Create(FStream));
end;

constructor TGPImageWrapper.Create(FileName: String);
begin
  inherited Create;
  Fimage:= TGPImage.Create(FileName);
end;

destructor TGPImageWrapper.Destroy;
begin
  FImage.Free;
  FStream.Free;
  inherited;
end;
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Antwort Antwort


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 08:36 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