vector<HBITMAP>

Thomasio

Erfahrenes Mitglied
Ich versuche alle Grafiken meiner Anwendung beim Start zu laden und in einem globalen vector abzulegen.

Code:
vector<HBITMAP>MyBitmaps;

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int nCmdShow)
{

...

CreateBitmaps();

...

}

void CreateBitmaps()
{

HBITMAP MyBitmap = (HBITMAP)LoadImage(0,"image1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(!MyBitmap)
  {
      // error
  }
MyBitmaps.push_back(MyBitmap);

MyBitmap = (HBITMAP)LoadImage(0,"image2.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(!MyBitmap)
  {
      // error
  }
MyBitmaps.push_back(MyBitmap);

}

Nach meinem Verständnis müsste nach Aufruf der Funktion der vector meine Grafiken enthalten, während alle Variablen die innerhalb der Funktion benutzt werden nicht mehr gültig sind und auf den ersten Blick funktioniert das so.

Code:
case WM_PAINT:
{

...

HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem,MyBitmaps[0]);
BitBlt(...);

...

}
break;

Ich weiss aber, auch denn die Variable nicht mehr gültig ist, die Bitmaps werden am Ende der Funktion nicht automatisch gelöscht, sondern ich muss den Speicher selber wieder frei geben.
Versuche ich aber die Bitmaps nach push_back() zu löschen, etwa so:

Code:
void CreateBitmaps()
{

HBITMAP MyBitmap = (HBITMAP)LoadImage(0,"image1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(!MyBitmap)
  {
      // error
  }
MyBitmaps.push_back(MyBitmap);
DeleteObject(MyBitmap);

MyBitmap = (HBITMAP)LoadImage(0,"image2.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(!MyBitmap)
  {
      // error
  }
MyBitmaps.push_back(MyBitmap);
DeleteObject(MyBitmap);

}

dann funktioniert das nicht mehr, sprich ich habe nur leere Fenster.
Offensichtlich zeigt der vector auf den Speicher, in den innerhalb der Funktion die Grafik geladen wurde.

Jetzt stehe ich davor, wie die Kuh vorm Bahnhof.
Mache ich grundsätzlich was falsch, oder ist das so in Ordnung?
 
Hallo

ich glaube hier liegt ein allgemeines missverständniss des begriffes "HANDLE" vor.

LoadImage liefert dir kein bild (als datenobjekt). Es liefert dir auch keinen pointer (speicheraddresse) auf ein datenobjekt.
Stattdessen legt es das bild in einem internen speicher ab, den es selber verwaltet, und gibt dir einen so genannten Handle zurück.

Ein handle ist eine (meist nummische) information, die dir die möglichkeit gibt, das datenobjekt mit anderen funktionen wieder anzusprechen. (ziemlich ähnlich wie ein pointer).

In dem moment wo du DeleteObject auf einem Handle aufrufst, wird das datenobjekt hinter dem handle zerstört.
Damit ist die Handle ID die in deinem vector geseichert ist, vollkommen wertlos, denn das datenobjekt im internen bitmap speicher von windows existiert nicht mehr.

Wenn du nun also windows anweisst das bild mit der nummer 7 zu zeichnen, wird windows feststellen - bild nummer 7... kenn ich nicht.
Es kann in einigen ausnahmefällen sogar passieren, dass "bild nummer 7" inzwischen von einem anderen bild das später geladen wurde belegt ist, und daher ein falsches bild gezeichnet wird.

Die korrekte stelle derartige sachen freizugeben ist in der regel der WM_DESTROY message handler. Auch wenn viele programme es gar nicht wieder freigeben und die window resourcen einfach leaken.
 
Vielen Dank für diese wirklich ausführliche Antwort, ich denke, das habe ich soweit begriffen.

Nur eine Zusatzfrage:
Wenn ich in der Funktion DeleteObject() nicht aufrufe, bleibt dann die Bitmap auch nach Ende der Funktion erhalten, so dass ich über die Handles im vector darauf zugreifen kann, oder überschreibt Windows mir die Bitmap bei der nächstbesten Gelegenheit?
 
Zurück