noch einmal BM_SETIMAGE / ERLEDIGT



  • Im XP-Style gehts bei mir!

    #pragma comment(linker, "/MANIFESTDEPENDENCY:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
    


  • XP, äh, ich hab ja Windows 7... Common Controls 6 halt.


  • Mod

    Evtl. nimmt die klassiche Button Klasse nur DIBs.
    Während die Commnon Control 6.0 Klasse alles frisst auch device dependant bitmaps.

    BTW: Dein Umgang mit SelectObject erzeugt ein GDI-Leak.



  • Ich habs jetzt.

    HDC hdc = CreateCompatibleDC(NULL);
    bitmap = CreateCompatibleBitmap(hdc, 100, 50);
    

    erzeugt nicht die korrekte Bitmap. Es muss so aussehen:

    HDC hdc = CreateCompatibleDC(NULL);
    HDC myHdc = GetDC(hwnd);
    bitmap = CreateCompatibleBitmap(myHdc, 100, 50);
    

    Martin Richter schrieb:

    BTW: Dein Umgang mit SelectObject erzeugt ein GDI-Leak.

    Du meinst, weil die Bitmap in dem Speichergerätekontext nicht wiederhergestellt wird? Dazu schreibt Petzold, das sei bei Speichergerätekontexten (bzgl. der Bitmaps nicht nötig). Interessanterweise macht er das aber auch bei zB Brushes iVm Speichergerätekontexten nicht in seinen Beispielen, was mich etwas verwirrt. Wie gesagt, für Bitmaps erwähnt er es ausdrücklich auf Seite 636 ganz oben, 5. Auflage deutsch.


  • Mod

    Du selektierst die Bitmap in einen DC nd merkst Dir die alte nicht.
    d.h.
    1. Die alte Bitmap di eim DC war wird ciht freigegeben.
    2. Die einselektierte Bitmap ist im DC in Benutzung und wird nicht freigegeben.



  • Ähh, jetzt verwirrst Du mich auch ...
    Die von mir erstellte Bitmap gebe ich bei WM_DESTROY frei - der DC existiert zu dem Zeitpunkt ja längst nicht mehr. Die, die vorher standardmäßig drin ist, gebe ich in der Tat nicht frei - weil sie mir nicht gehört und ich sie ja auch nicht selbst erstellt habe <- kann ich die überhaupt erfolgreich freigeben?

    Wie ist das denn nun mit Speichergerätekontexten? Liegt der Petzold falsch, wenn er schreibt, dass die Bitmap nicht wiederhergestellt werden muss, bevor der DC freigegeben wird?

    Er schreibt an der oben zitierten Stelle: ... weil die GDI beim Anlegen von Speichergerätekontexten immer wieder dasselbe Standard-Bimap mit 1 x 1 Pixeln verwendet ...

    das hört sich so an, als wenn ich das nicht freigeben dürfte/sollte?!



  • Belli schrieb:

    Ich habs jetzt.

    HDC hdc = CreateCompatibleDC(NULL);
    bitmap = CreateCompatibleBitmap(hdc, 100, 50);
    

    erzeugt nicht die korrekte Bitmap. Es muss so aussehen:

    HDC hdc = CreateCompatibleDC(NULL);
    HDC myHdc = GetDC(hwnd);
    bitmap = CreateCompatibleBitmap(myHdc, 100, 50);
    

    Das glaube ich nicht, und hat bei mir auch nichts geändert.



  • Hier nochmal der komplette Code, wie er bei mir nun das tut, was ich erwarte - bis auf eine Ausnahme: Die Message-Box, die signalisiert, dass SendMessage(..., BM_SETIMAGE, ...); 0 zurückgibt, kommt immer noch ... aber ich habe mein Image auf dem Button:

    #include <windows.h>
    #include <sstream>
    
    #define  ID_BUTTON3    3
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         static TCHAR szAppName[] = TEXT ("ButtonTest") ;
         HWND         hwnd ;
         MSG          msg ;
         WNDCLASS     wndclass ;
    
         wndclass.style         = 0; //CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0 ;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
         wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH) ;
         wndclass.lpszMenuName  = NULL ;
         wndclass.lpszClassName = szAppName ;
    
         if (!RegisterClass (&wndclass))
         {    // UNICODE-Compilierung ist die einzige realistische Fehlermöglichkeit 
              MessageBox (NULL, TEXT ("Programm arbeitet mit Unicode und setzt Windows NT voraus!"), 
                          szAppName, MB_ICONERROR) ;
              return 0 ;
         }
    
         hwnd = CreateWindow (szAppName, TEXT ("Test des BitmapButtons"),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              500, 300,
                              NULL, NULL, hInstance, NULL) ;
    
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;
         while (GetMessage (&msg, NULL, 0, 0))
              {
              TranslateMessage (&msg) ;
              DispatchMessage (&msg) ;
              }
         return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	  static HBITMAP bitmap;
    
         switch (message)
         {
    	     case WM_CREATE:
    		       {
    		       	//Button erstellen
    		          HWND hbtn = CreateWindow("BUTTON", "", WS_CHILD | BS_BITMAP | WS_VISIBLE | BS_PUSHBUTTON, 235, 5, 100, 50, hwnd,
    		                       (HMENU) ID_BUTTON3, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL);
    
    				 	//Bitmap und Device Context erstellen und Bitmap in DC selecten
    					 //HDC hdc = CreateCompatibleDC(NULL);
    					 HDC thdc = GetDC(hwnd);
    					 HDC hdc = CreateCompatibleDC(thdc);
    
    					 bitmap = CreateCompatibleBitmap(thdc, 100, 50);
    
    					 ReleaseDC(hwnd, thdc);
    					 HBITMAP altBitMap = (HBITMAP)SelectObject(hdc, bitmap);
    
    					 //Bitmap mit Brush füllen
    					 RECT rect = {0, 0, 100, 50};
    					 HBRUSH brush = CreateSolidBrush(RGB(0, 250, 0));
    					 FillRect(hdc, &rect, brush);
    					 DeleteObject(brush);
    					 int altBkMode = SetBkMode(hdc, TRANSPARENT);
    					 DrawText(hdc, "Okay", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    
    					 //DC wird nicht mehr benötigt
    					 SelectObject(hdc, altBitMap);
    					 SetBkMode(hdc, altBkMode);
    					 DeleteDC(hdc);
    
    					 //Bitmap an den Button binden
    					 LRESULT res = SendMessage(hbtn, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap);
    					 if(!res)
    					 {
    					 	int err = GetLastError();  //ergibt 87: The parameter is incorrect.
    					 	std::stringstream ss;
    					 	ss << "... assigning Bitmap:\n" << err;
    					 	MessageBox(hwnd, ss.str().c_str(), "Error ...", MB_OK);
    					 } 
    				 }
    
    	          return 0 ;
    
    		  case WM_PAINT:
    		  		 HDC hdc, chdc;
    		  		 PAINTSTRUCT ps;
    		  		 HBITMAP altBitMap;
    
    		  		 hdc = BeginPaint(hwnd, &ps);
    
    		  		 //meine Bitmap
    		  		 chdc = CreateCompatibleDC(hdc);
    		  		 altBitMap = (HBITMAP)SelectObject(chdc, bitmap);
    
    				 //ins Fenster blitten, klappt, an der Bitmap scheint es also nicht zu liegen
    				 BitBlt(hdc, /*Pos xy*/30, 120, /*größe xy*/100, 50, chdc, 0, 0, SRCCOPY);
    
    				 EndPaint(hwnd, &ps);
    
    				 SelectObject(chdc, altBitMap);
    				 DeleteObject(chdc);
    
    				 return 0;
    
    	     case WM_DESTROY :
    	     		 DeleteObject(bitmap);
    	          PostQuitMessage (0) ;
    	          return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    


  • Alter Frickler 😃

    Der Rückgabewert von BM_SETIMAGE sagt nichts über einen Fehler aus... http://msdn.microsoft.com/en-us/library/bb761822



  • Ah, Schei....
    ich hab das 'previously' völlig falsch interpretiert ... haha, ich hatte erwartet, dass ich ein HANDLE auf das soeben von mir 'angehängte' Image bekomme, aber es ist natürlich das, was vor meinem SendMessage mit dem Button assoziiert war, mithin 0, nu fällt es mir wie Schuppen aus den Haaren ...

    Vielen Dank an alle, die sich mit meinem Problem beschäftigt haben.


Anmelden zum Antworten