GDI+ Operator new() und das MFC Makro DEBUG_NEW richtig verwenden

Wenn Sie GDI+ und MFC kombiniert verwenden, ist Ihnen das folgende Problem vielleicht auch schon einmal auf die Füße gefallen:

Beim Kompilieren eines Debug-Builds gibt der Compiler für Quellcodezeilen in denen Instanzen von GDI+ Klassen durch Aufrufen des new() Operators erzeugt werden, die folgende Fehlermeldung aus:

„error C2660: ‚Gdiplus::GdiplusBase::operator new‘ : function does not take 3 parameters“ oder
„Fehler C2660: ‚Gdiplus::GdiplusBase::operator new‘ : Funktion akzeptiert keine 3 Parameter“

Die betroffene Quellcodezeile könnte zB. so aussehen:
Gdiplus::Graphics *graphics = new Gdiplus::Graphics( theHdc );


Ursache für den Fehler ist, dass GDI+ Klassen einen eigenen new() Operator besitzen. Dieser ist in Gdiplus::GdiplusBase definiert.

Das MFC Makro DEBUG_NEW, welches nur in Debug Builds aktiv ist, definiert wiederum einen new() Operator dem 2 zusätzliche Parameter (der Dateiname und die Zeilennummer) übergeben werden. Dieser Operator wird genutzt, um zu verfolgen an welcher Stelle im Quellcode ggf. nicht freigegebener Speicher allokiert wurde. Eine sehr praktische Eigenschaft von MFC.

Das DEBUG_NEW Makro von MFC ist in ‚afx.h‘ wie folgt definiert:
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#define DEBUG_NEW new(THIS_FILE, __LINE__)


Ein möglicher Lösungsansatz, wie er auch auf diversen Internetseiten angepriesen wird, ist das Deaktivieren des DEBUG_NEW Makros in den entsprechenden CPP Dateien. Durch Löschen / Auskommentieren des Defines
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

welches am Anfang einer jeden CPP Datei mit MFC Unterstützung zu finden ist.

Diese Lösung ist zwar schnell und einfach, schaltet aber dafür den MFC internen Speicher-Trackingmechanismus aus. Der DEBUG_NEW Operator protokolliert beim Beenden der Anwendung alle nicht gelöschten Objekte und hilft somit Speicherlöcher und Ressourcenlecks zu finden.


Die beste Lösung für das Problem, wenn auch die Umfänglichste, ist, den GDI+ new() Operator durch eine Variante, welche 3 Parameter akzeptiert, zu überladen.
class GdiplusBase
{
 public:
 void * (operator new)(size_t nSize, LPCSTR, int)
 {
  return DllExports::GdipAlloc(nSize);
 }
}

Das Überladen des new() Operators hat den Vorteil, dass Sie die normale GDI+ Syntax unter Beibehaltung des MFC Speichertrackers nutzen können. Dies hat vorallem in bereits bestehenden Projekten einen großen Nutzen. Den vollständigen Quellcode des GDI+ Zusatzheaderfiles erhalten Sie auf der Microsoft Webseite zu Microsoft KB317799.


Eine weitere Lösung, welche aber nicht in jedem Fall verwendet werden kann, sind die statischen „From…()“ Methoden der GDI+ Klassen, wie zB. Gdiplus::Bitmap:: FromFile(), Gdiplus::Bitmap: FromHBITMAP(), Gdiplus::Graphics:: FromHDC(), Gdiplus::Graphics:: FromHWND().

Ein Beispiel:
// error C2660:
Gdiplus::Bitmap *pBmp = new Gdiplus::Bitmap( "C:\\Test.jpg" );
.
// Erfolgreich
Gdiplus::Bitmap *pBmp = Gdiplus::Bitmap::FromFile( "C:\\Test.jpg" );

Diese Lösung hat den Vorteil, dass man weder den MFC Speicher-Trackingmechanismus deaktivieren noch in den GDI+ Headern herum fummeln muss. Leider lässt sich diese Lösung nicht auf alle GDI+ Klassen (zB. CachedBitmap) anwenden.

Ebenso kann man die Clone() Methoden von Bitmap und Image verwenden um nicht auf dem Stack allokierte Instanzen der Klassen zu erhalten.


Weitere Informationen:

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s