Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   

Die mobilen Seiten von c++.de:
http://m.c-plusplus.de
Infos hier [BETA]

  
c++.de :: WinAPI ::  Bitmaps: Speicherallokation, Freigabe und Löschung     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
cyberleon
Mitglied

Benutzerprofil
Anmeldungsdatum: 26.04.2012
Beiträge: 35
Beitrag cyberleon Mitglied 23:17:59 27.05.2012   Titel:   Bitmaps: Speicherallokation, Freigabe und Löschung            Zitieren

Zitat:

In Deiner WM_PAINT ist auch noch ein grober Schnitzer drin:
Du erzeugst dort jedesmal einen Speicher-Gerätekontext, löschst diesen aber nie mit DeleteDC, sondern gibst ihn lediglich frei mit ReleaseDC.
Wenn Du Dein Programm so eine Weile laufen lässt, hast Du bald alle GDI-Objekte des Systems verbraucht. Nicht gut, denn GDI-Objekte sind nicht unbegrenzt vorhanden.

Für die Performance wäre es auch besser, wenn Du LoadImage und CreateCompatibleDC in die WM_CREATE auslagerst und die Handles global abspeicherst. In der WM_DESTROY löschst Du die beiden dann wieder.


Gruß
Greenhorn


Zuerst einmal vielen lieben Dank für diese tollen Hinweise! Ich habe mich leider erst heute an die Arbeit machen können - folgendes kam dabei heraus (Der Code funktioniert! Ich bin nur unsicher, ob ich alles richtig gemacht habe!):

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Backgroundpainting
HBITMAP h1Bitmap;
HDC h1BitmapDC;
HDC h1DC;
 
int Bitmaphoehe;
int Bitmapbreite;
 
int PaintBackground(HWND hwnd)
{
         static PAINTSTRUCT ps;
         static HDC h1DC;
         RECT rect;
         h1DC = BeginPaint( hwnd, &ps );                   // draw the following stuff:
             GetClientRect(hwnd, &rect);        // Fenstergrösse herausfinden, um in LoadImage einzufügen
             int hoehe = rect.bottom - rect.top;      
             int breite = rect.right - rect.left;
             BITMAP bmp;
             GetObject(h1Bitmap,sizeof(bmp),&bmp);
 
             SelectObject(h1BitmapDC,h1Bitmap);
             StretchBlt(h1DC,0,0, breite, hoehe,h1BitmapDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY    
             
             ReleaseDC(hwnd,h1BitmapDC);
             ReleaseDC(hwnd,h1DC);
             Bitmaphoehe = bmp.bmHeight;
             Bitmapbreite = bmp.bmWidth;
             if(h1Bitmap == NULL)
             {
             MessageBox(hwnd, "Could not load Bitmap!", "Error", MB_OK | MB_ICONEXCLAMATION);
             }
             Ellipse( h1DC, 300, 100, 330, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
             Ellipse( h1DC, 160, 100, 190, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
             Rectangle( h1DC, 20, 90, 330, 100 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
             Rectangle( h1DC, 220, 70, 300, 90 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
             
 
         EndPaint( hwnd, &ps );
}
 
// Buttonpainting
HBITMAP h2Bitmap;          // Bitmap, die später das Image für Buttons aufnehmen wird
static HWND hButton;       // hButton an dieser Stelle deklariert, da er in int Paintbuttons benötigt wird
HDC h2BitmapDC;
HDC h2DC;
int Checkvariable;         // zum Überprüfen interner Werte in dieser Funktion (momentan abrufbar über Klick auf button1)
#define FastDT(buffer,rect) DrawText(hdc,buffer,-1,&rect,DT_CENTER|DT_SINGLELINE|DT_VCENTER);
 
int PaintButtons(HWND hButton)
{
   static PAINTSTRUCT ps;
   static HDC hdc;
   RECT rect;
   int hoehe;
   int breite;
   char buffer9[256] = "0";
   GetWindowText(hButton, buffer9, 256);
         hdc = BeginPaint(hButton, &ps);
         GetClientRect(hButton, &rect);        // Fenstergrösse herausfinden, um in LoadImage einzufügen
         hoehe = rect.bottom - rect.top;      
         breite = rect.right - rect.left;
         BITMAP bmp;
         GetObject(h2Bitmap,sizeof(bmp),&bmp);
  Checkvariable = sizeof(bmp);
         SelectObject(h2BitmapDC,h2Bitmap);
         StretchBlt(hdc,0,0, breite, hoehe,h2BitmapDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
         // hier war LoadImage h2Bitmap
         SetBkMode (hdc, TRANSPARENT);  // damit der Text nicht in einem weissen Rechteck erscheint
         FastDT(buffer9,rect);      //siehe Makro oben:      DrawText(hdc, buffer9,-1,&rect,DT_CENTER | DT_SINGLELINE | DT_VCENTER);
 
 
 
     /*
     n Deiner WM_PAINT ist auch noch ein grober Schnitzer drin:
Du erzeugst dort jedesmal einen Speicher-Gerätekontext, löschst diesen aber nie mit DeleteDC, sondern gibst ihn lediglich frei mit ReleaseDC.
Wenn Du Dein Programm so eine Weile laufen lässt, hast Du bald alle GDI-Objekte des Systems verbraucht. Nicht gut, denn GDI-Objekte sind nicht unbegrenzt vorhanden.
 
Für die Performance wäre es auch besser, wenn Du LoadImage und CreateCompatibleDC in die WM_CREATE auslagerst und die Handles global abspeicherst. In der WM_DESTROY löschst Du die beiden dann wieder.
*/
 
         ReleaseDC(hButton,h2BitmapDC);
         ReleaseDC(hButton,h2DC);
         EndPaint(hButton, &ps );
 
    return Checkvariable;
}


Anschließend die Aufrufe in der WM_CREATE, in die ich wie in der Kritik gefordert meine LoadImage und meine CreateCompatibleDC ausgelagert habe:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[ ..... ]
WM_CREATE
{
         [ ..... ]
 
         // Background
         h1Bitmap = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 400, 400, LR_LOADFROMFILE);  // Achtung: die beiden Zahlenwerte müssen gleich gross sein, ansonsten kann man sie benutzen um Teile der Bitmap von unten oder von links abzuschneiden.
         h1DC = GetDC(hwnd);
         h1BitmapDC = CreateCompatibleDC(h1DC);
         
         // Button Images
         h2Bitmap = (HBITMAP)LoadImage(NULL, "test2.bmp", IMAGE_BITMAP, 40, 40, LR_LOADFROMFILE);  // Achtung: die beiden Zahlenwerte müssen gleich gross sein, ansonsten kann man sie benutzen um Teile der Bitmap von unten oder von links abzuschneiden.
         
         // Buttons        
         h1Button = CreateWindow(  "button",
                                  "Experience",
                                  WS_CHILD | WS_VISIBLE,
                                  0, 0, 100, 30,
                                  hwnd,
                                  NULL,
                                  ((LPCREATESTRUCT) lParam) -> hInstance,
                                  NULL);
                                 
         h2DC = GetDC(h1Button);                            // Vorbereitung der Buttonwerte. Momentan nur für identische Buttons (Größe, Bitmap)
         h2BitmapDC = CreateCompatibleDC(h2DC);
 
         [ ..... ]
}

Dann die Aufrufe in der WM_PAINT:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      case WM_PAINT:
      {
         // Background zeichnen
         PaintBackground(hwnd);
         // Buttons einfärben durch Funktionsaufruf der zu Programmbeginn deklarierten Funktion PaintButtons():
         PaintButtons(h1Button);
         PaintButtons(h2Button);
         PaintButtons(h3Button);
         PaintButtons(h4Button);
         PaintButtons(h5Button);
         PaintButtons(h6Button);
         PaintButtons(h7Button);
         PaintButtons(h8Button);
 
      }

Und zuletzt die Speicherbereinigung beim Programmende
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      case WM_DESTROY:
      {
         del_img();
         PostQuitMessage(0);
         
         // Clean Background Bitmap
         DeleteObject(h1Bitmap);
         DeleteDC(h1DC);
         DeleteDC(h1BitmapDC);
         // Clean Button Bitmap(s)
         DeleteObject(h2Bitmap);
         DeleteDC(h2DC);
         DeleteDC(h2BitmapDC);
         
         return 0;
      }


Habe ich das soweit richtig gemacht? Also in Bezug auf den Quote vom Anfang? Oder habe ich vielleicht etwas übersehen? (Ich wette darauf 8)( )

Alles Gute und frohe Pfingsten!

_________________
C++ Learning Start at: Di, 26. 04. 2012
C++ Status: Dorftrottel (me is nuub)


Zuletzt bearbeitet von cyberleon am 01:06:02 28.05.2012, insgesamt 2-mal bearbeitet
Martin Richter
Moderator

Benutzerprofil
Anmeldungsdatum: 18.04.2006
Beiträge: 14186
Beitrag Martin Richter Moderator 08:53:53 28.05.2012   Titel:              Zitieren

Also dieser Code ist mit x-Fehlern gesprickt.
static HDC h1DC; ??? verdeckt globalö h1DC. Gleiches für h2DC.

Hier kann doch gar nichts funktionieren.

Typisches GDI leak.

Wenn Du ein Objektin einen GDI Kontext selektierst (SelectObject), dann gekomst Du das alte Objekt zurück. Dein Objekt bleibt im Kontext und kann nicht freigegeben werden, wenn der Kontext gelöscht wird bzw. wenn Du das Objekt zerstötren willst.

Immeer den Rückgabewert sichern und am Ende der GDI-Operation wieder das alte Objekt zurück selektieren.

Waruim bitte sind die PAINTSTRUCTs statisch?

_________________
Martin Richter (MVP für C++) WWJD http://blog.m-ri.de
"A well-written program is its own heaven; a poorly written program is its own hell!" The Tao of Programming
Greenhorn__
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.06.2010
Beiträge: 38
Beitrag Greenhorn__ Mitglied 14:23:41 28.05.2012   Titel:              Zitieren

Habe es nur kurz überflogen, aber ich würde es eher so machen ...

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Globals
HDC     hdcMem ;
HBITMAP hbmBkGnd ;
HBITMAP hbmButton [8] ;
 
 
[ ..... ]
 
case WM_CREATE:
{
    [ ..... ]
    POINT pt [8] = {50, 40, ..., ..., usw.} ; // Positionen der Schaltflächen
 
    // Background
    hbmBkGnd = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    HDC hDC = GetDC(hwnd);
    hdcMem = CreateCompatibleDC(hDC);
    ReleaseDC (hwnd, hDC) ;
 
    // Button Images
    for (int i = 0 ; i < 8 ; i++ )
    {
        hbmButton[i] = (HBITMAP)LoadImage(NULL, "test2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
 
        // Buttons
        hButton = CreateWindow( "button",
                            "Experience",
                            WS_CHILD | WS_VISIBLE | BS_BITMAP,
                            pt[i].x, pt[i].y, 100, 30,
                            hwnd,
                            NULL,
                            ((LPCREATESTRUCT) lParam) -> hInstance,
                            NULL);
 
        SendMessage (hButton, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmButton[i]) ;
    }
    [ ..... ]
}
case WM_DESTROY:
{
    // Clean Background Bitmap
    DeleteObject(hbmBkGnd);
    DeleteDC(hdcMem);
 
    // Clean Button Bitmap(s)
    for (int i = 0 ; i < 8 ; i++ )
    {
        DeleteObject(hbmButton[i]);
    }
 
    PostQuitMessage(0);
 
    return 0;
}
 
 
[ ..... ]
 
void PaintBackground(HWND hwnd)
{
    PAINTSTRUCT ps;
    HGDIOBJ hObjOld ;
    RECT rect;
    HDC hDC = BeginPaint( hwnd, &ps );
    GetClientRect(hwnd, &rect);
 
    BITMAP bmp;
    GetObject(hbmBkGnd, sizeof(bmp), &bmp);
 
    hObjOld = SelectObject(hdcMem, hbmBkGnd);
    StretchBlt(hDC, 0, 0, rect.right, rect.bottom,hdcMem,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
    SelectObject(hdcMem, hObjOld);
 
    Ellipse( hDC, 300, 100, 330, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
    Ellipse( hDC, 160, 100, 190, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
    Rectangle( hDC, 20, 90, 330, 100 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
    Rectangle( hDC, 220, 70, 300, 90 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
 
 
    EndPaint( hwnd, &ps );
}


Ungetestet, können noch Fehler drin sein ...


Gruß
Greenhorn


Zuletzt bearbeitet von Greenhorn__ am 18:16:30 28.05.2012, insgesamt 5-mal bearbeitet
cyberleon
Mitglied

Benutzerprofil
Anmeldungsdatum: 26.04.2012
Beiträge: 35
Beitrag cyberleon Mitglied 23:24:09 30.05.2012   Titel:              Zitieren

Einen Keksbaum @ Martin!

Vielen lieben Dank für die Hinweise!

Zitat:

Also dieser Code ist mit x-Fehlern gesprickt.
static HDC h1DC; ??? verdeckt globalö h1DC. Gleiches für h2DC.

Hier kann doch gar nichts funktionieren.

Typisches GDI leak.


Da mein Code (seltsamerweise) funktionierte, hatte ich die Doppeldeklaration von h1DC übersehen. Außerdem war HDC hdc unnötig, ich habe es entfernt und alle hdc durch h2DC ersetzt.

Zitat:

Waruim bitte sind die PAINTSTRUCTs statisch?


Das "static" der Paintstruct war ein Relikt aus der Zeit, als ich mal versucht hatte, die Paintstruct "dauerhaft" das ganze Programm über zu benutzen - und erst beim WM_DESTROY wieder zu entfernen - was natürlich voll in die Hose ... :D
C++:
PAINTSTRUCT ps;  

reicht völlig.

Zitat:

Wenn Du ein Objektin einen GDI Kontext selektierst (SelectObject), dann gekomst Du das alte Objekt zurück. Dein Objekt bleibt im Kontext und kann nicht freigegeben werden, wenn der Kontext gelöscht wird bzw. wenn Du das Objekt zerstötren willst.

Immeer den Rückgabewert sichern und am Ende der GDI-Operation wieder das alte Objekt zurück selektieren.


auf
http://msdn.microsoft.com/en-us/library/dd162957(v=vs.85).aspx
habe ich
Zitat:

The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.

gefunden, daher ging ich davon aus, dass das neue Objekt das alte ersetzt und dabei das alte gelöscht wird. Nubfragen: Wie sichere ich den Rückgabewert? Mit "das alte Objekt zurückselektieren" meinst du sicher eben diesen gesicherten Rückgabewert, den ich selektieren muss?

Kekskiste @ Greenhorn!

Super Ideen!

Die mit dem point pt array hebe ich mir auf jeden Fall für später auf, solange ich mir noch nicht sicher über die Positionen der Buttons bin!

Besonders gefällt mir die Idee, den Buttons schon bei Createwindow dauerhaft die Images zuzuweisen!

Den Background in eine void am Programmende zu stecken werde ich auf jeden Fall auch ausprobieren!

Vielen lieben Dank euch zweien, ich melde mich wenn ich fertig bin (oder(wahrscheinlicher) versage 8)( )!

_________________
C++ Learning Start at: Di, 26. 04. 2012
C++ Status: Dorftrottel (me is nuub)
c++.de :: WinAPI ::  Bitmaps: Speicherallokation, Freigabe und Löschung   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.