Speicherleck bei CImage & BitBlt. Wie stopfen?



  • Guten Tag

    Ich verwende CImage um ein Bild des Programmfensters zu speichern.

    void CTestDlg::OnBnClickedButtonTest()
    {
    	CImage cImg;
    	CRect cRect;
    	//Den zu speichernden Bildbereich ermitteln
    	GetClientRect(&cRect);
    
    	// Das Bild mit der passenden Größe erzeugen
    	if(!cImg.Create(cRect.Width(),cRect.Height(),24))
    	{
    		// Wenn das Erzeugen fehlgeschlagen ist, beenden
    		return;
    	}
    	// Kopieren der Bilddaten
    	if(!BitBlt(cImg.GetDC(),0,0,cRect.Width(),cRect.Height(),GetDC()->GetSafeHdc() ,0,0,SRCCOPY))
    	{
    		// Wenn beim Kopieren etwas nicht funktioniert, die Bildklasse aufräumen und beenden
    		cImg.ReleaseDC();
    		cImg.Destroy();
    		return;
    	}
    	// Die DC nach dem Kopieren wieder freigeben, das Bild speichern und löschen
    	cImg.ReleaseDC();
    
    	cImg.Save(_T("C:\\TestOrdner\\Test.png"));
    
    	cImg.Destroy();
    }
    

    Wenn ich diese Funktion mehrfach aufrufe, sieht man deutlich dass der Speicherverbrauch steigt.

    Kann mit bitte jemand verraten wo ich hier das Speicherleck gebaut habe und wie ich es stopfen kann?

    mfg Bernhard



  • Geraden: In den "GetDC" aufrufen?



  • Danke für den Hinweis.

    Ich hatte nach Funktionen wie cDc->ReleaseDC() gesucht, aber keine gefunden.
    Wenn ich aber ReleaseDC(cDc) verwende, funktioniert es.

    Vielen Dank nochmals.
    mfg Bernhard


  • Mod

    Und warum machst Du das überhaupt?

    Man zeichnet grundsätzlich immer nur in OnPaint!

    Ansonsten für alle anderen noch mal im Klartext:
    Alle Deine Aufrufe von GetDC leaken natürlich...



  • Martin Richter schrieb:

    Alle Deine Aufrufe von GetDC leaken natürlich...

    Ich sehe da nur zwei, und einer davon ( CImage::GetDC ) leakt in seinem Programm sicher nicht. Zumindest nicht so lange BitBlt keine Exception wirft.


  • Mod

    hustbaer schrieb:

    Martin Richter schrieb:

    Alle Deine Aufrufe von GetDC leaken natürlich...

    Ich sehe da nur zwei, und einer davon ( CImage::GetDC ) leakt in seinem Programm sicher nicht. Zumindest nicht so lange BitBlt keine Exception wirft.

    Du hast wie immer recht... es ist nur der CWnd::GetDC Aufruf der leaked.
    Allerdings ist der unnötig, wen man eben in OnPaint zeichnet und nicht wild bei einem Klick...



  • Martin Richter schrieb:

    Du hast wie immer recht...

    Haha, das wäre schön!
    Aber danke für die Blumen 🙂



  • Danke für die Hinweise.

    Wie ich vorher schon geschrieben habe, hatte ich nach dem Hinweis von Jochen ReleaseDC eingefügt.

    Die Testfunktion schaut inzwischen so aus:
    (Ich habe die Funktionalität testweise über einen Button gestartet um das Speicherleck einfacher eingrenzen zu können)

    void CTestDlg::OnBnClickedButtonTest()
    {
        CImage cImg;
        CRect cRect;
        //Den zu speichernden Bildbereich ermitteln
        GetClientRect(&cRect);
    
        // Das Bild mit der passenden Größe erzeugen
        if(!cImg.Create(cRect.Width(),cRect.Height(),24))
        {
            // Wenn das Erzeugen fehlgeschlagen ist, beenden
            return;
        }
        CDC* cDc = GetDC();
        // Kopieren der Bilddaten
        if(!BitBlt(cImg.GetDC(),0,0,cRect.Width(),cRect.Height(),cDc->GetSafeHdc() ,0,0,SRCCOPY))
        {
            // Wenn beim Kopieren etwas nicht funktioniert, die Bildklasse aufräumen und beenden
            ReleaseDC(cDc);
            cImg.ReleaseDC();
            cImg.Destroy();
            return;
        }
        // Die DC nach dem Kopieren wieder freigeben, das Bild speichern und löschen
        ReleaseDC(cDc);    
        cImg.ReleaseDC();
    
        cImg.Save(_T("C:\\TestOrdner\\Test.png"));
    
        cImg.Destroy();
    }
    

    Ihr habt natürlich recht dass man nur in OnPaint auf den Bildschirm zeichnet.
    Ich mache es normalerweise so, dass ich in dem Fall in einer eigenen Zeichenfunktion in eine CImage Variable zeichne, und diese dann in OnPaint auf den Anzeigebereich klatsche.
    (Schnellere Aktualisierung der Anzeige da nicht alle Daten bei jedem Aktualisieren der Anzeige neu gezeichnet werden müssen.)

    In diesem Fall läuft die Sache anders herum.
    Es wird der Anzeigebereich in die CImage Variable kopiert und dann abgespeichert.
    Der Zweck dieser Übung ist später die Funktion über den Timer gesteuert alle paar Minuten aufzurufen um die Bilder auf ein Netzwerklaufwerk abzuspeichern.
    So kann man ohne spezielles Programm überprüfen was das Programm so treibt.

    mfg Bernhard


Log in to reply