Beschreibung
Gerade habe ich folgendes Phänomen erlebt:
Beim Speichern eines GDI+-Bilds (Image
– bzw. Bitmap
-Klasse) bekam ich einen Statuscode 7 zurückgeliefert, was die Fehlermeldung „Win32Error“ bedeutet.
Also wie bei den meisten GDI+-Fehlermeldungen völlig ungenau und völlig an der wahren Ursache vorbei.
Da ich das ganze im Debugger laufen ließ und dieser bei First-Chance-Exceptions anhält, sah ich die genaue Stelle wo zum ersten Mal ein Fehler auftritt. Nämlich eine Zugriffsverletzung („Access violation“, 0x00000005) innerhalb von GDI+ an der folgenden Stelle im Aufrufstapel:
Bzw. als Textversion:
GdiPlus.dll!GpJpegEncoder::PushPixelData() + 0xa5 GdiPlus.dll!GpMemoryBitmap::PushIntoSink() + 0x14b GdiPlus.dll!GpMemoryBitmap::SaveToStream() + 0xa1 GdiPlus.dll!GpMemoryBitmap::SaveToFile() + 0x39 GdiPlus.dll!CopyOnWriteBitmap::DoSave() + 0x206 GdiPlus.dll!CopyOnWriteBitmap::SaveToFile() + 0x15 GdiPlus.dll!GpBitmap::SaveToFile() + 0x1f GdiPlus.dll!_GdipSaveImageToFile@16() + 0x5f zlzdiud.dll!Gdiplus::Image::Save() Zeile 140 + 0x18
Das Bild habe ich aus der Zwischenablage geholt (Zwischenablagenformat CF_DIB
) und dann über die Funktion Bitmap::FromBITMAPINFO()
ein Bitmap
-Objekt daraus gemacht.
Ursache
Nach einigen Tests habe ich herausgefunden, woran es lag:
Sobald ich den Speicher freigegeben hatte, der die Daten aus der Zwischenablage gespeichert hat (ein Instanz der MFC-Klasse CByteArray
), schlug der Aufruf von Image::Save()
mit oben genannter Fehlermeldung fehl; habe ich den Speicher erst nach dem Aufruf von Image::Save()
freigegeben, verlief das Speichern erfolgreich.
Die Ursache ist also (wiedermal) wie bei den meisten GDI+-Routinen: Ich muß selbst dafür sorgen, daß ich den Speicher, aus dem ein ein Bitmap
-Objekt erstellt wurde, lange genug reserviere, weil GDI+ sich das nicht selbst in interne Puffer kopiert.
Ist für ehrlich gesagt teilweise ggf. verständlich (Performance, Flexibilität), aber sehr unintuitiv (Komfort)!
Lösung
Den Speicher für ein Bitmap
-Objekt, das aus einem Aufruf via Bitmap::FromBITMAPINFO()
(oder entsprechend anderer Funktionen) erstellt wurde, muß während der gesamten Lebensdauer des Bitmap
-Objekts gültig sein und von der benutzenden Anwendung reserviert bleiben.