![]() |
GDI+: IStream oder TStreamAdapter
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:
Folgender Code schon, aber wieso?
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;
Delphi-Quellcode:
Einzig hab ich den SA von TStreamAdapter auf IStream geändert, aber ich erzeuge nach wie vor den TStreamAdapter auf diese Variable.
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; 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! |
AW: GDI+: IStream oder TStreamAdapter
Die 1. Variante ist falsch und die 2. Variante ist richtig.
Der kommentierte Code macht es vielleicht verständlich:
Delphi-Quellcode:
Rein theoretisch sollte Delphi merken, dass das übergebene IStream-Interface innerhalb von TGPBitmap noch benützt wird.
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); Dazu müsste die Klasse TGPBitmap intern aber _AddRef() aufrufen, tut es anscheinend aber nicht. |
AW: GDI+: IStream oder TStreamAdapter
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 |
AW: GDI+: IStream oder TStreamAdapter
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. |
AW: GDI+: IStream oder TStreamAdapter
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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:55 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz