STM_SETIMAGE, Resourcenleck unter Windows XP



  • Hi,
    habe hier gerade ein Problem mit der STM_SETIMAGE-Message.
    Ich habe dem MS VS internen Ressourceneditor ein Dialogfeld mit einem Static-Control erstellt. Zur Laufzeit möchte ich nun das vorher festgelegt Bild gegen ein anderes austauschen.

    hb = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOO));
    DeleteObject((HBITMAP)SendMessage(hWndStatic,STM_SETIMAGE,IMAGE_BITMAP, (LPARAM)hb));
    

    Rein optisch war dies funktionell i.O. Das Bild wurde ausgetauscht. Da STM_SETIMAGE den Handle auf das bisherige Bitmap zurückliefert, wiegte ich mich in Sicherheit, dass hier kein Ressourcenleck entstehen kann, da ich dieses ja über DeleteObject gleich wieder lösche. Allerdings wird mit jedem Aufruf dieser 2 Zeilen ein zusätzliches GDI-Objekt bei mir erzeugt (laut Task-Manager). Also habe ich nachgeschaut, und stellte fest, dass STM_SETIMAGE mir einen NULL-Handle zurückliefert. Klar das ich den nicht freigeben kann. Dann nochmal flux in die Doku geschaut, und den Teil über STM_SETIMAGE genau gelesen. gegen Ende stiess ich dann auf:

    In version 6 of the Microsoft Win32 controls, a bitmap passed to a static control using the STM_SETIMAGE message was the same bitmap returned by a subsequent STM_SETIMAGE message. The client is responsible to delete any bitmap sent to a static control.

    With Microsoft Windows XP, if the bitmap passed in the STM_SETIMAGE message contains pixels with non-zero alpha, the static control takes a copy of the bitmap. This copied bitmap is returned by the next STM_SETIMAGE message. The client code may independently track the bitmaps passed to the static control, but if it does not check and release the bitmaps returned from STM_SETIMAGE messages, the bitmaps are leaked.

    Ich deute nun diesen Text so, dass bei der Übergabe eines Bitmaphandles automatisch von dem Bitmap eine Kopie erstellt wird. Der Handle dieser Kopie wird mir dann beim nächsten Aufruf von STM_SETIMAGE zurückgeliefert. Somit kann ich je mein Bitmap gleich nach der übergabe löschen, da nun eine Kopie existiert. Des weiteren muss ich den zurückgegebenen Handle ebenfalls freigeben, daraus folgt für mich:

    hb = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOO));
    DeleteObject((HBITMAP)SendMessage(myhwnd,STM_SETIMAGE,IMAGE_BITMAP,(HANDLE)hb));
    DeleteObject(hb);
    

    Hab das ganze getestet und siehe da, die Ressourcenlecks waren verschwunden, und das gewünschte Verhalten war immer noch sichtbar. Allerdings bin ich nicht wirklich glücklich damit.

    Ich hielt meinen ersten Ansatz für nicht völlig falsch. Ok, sicherlich gibt es bessere Lösungen. Und laut Dokumentation war ja bis V6 der win32-Controls das Verhalten auch so, dass mein Ansatz funktioniert hätte. Erst mit WinXP ist das Verhalten wohl geändert worden, so dass dieser zusätzlicher Aufwand meinerseits möglich ist. Was mich nun beschäftigt ist:

    1. Ich denke dass es viele Programme draussen im Feld gibt, die meinen Ansatz verwendet haben.
    2. Ich glaube nicht, dass Microsoft einfach eine grundlegende Schnittstelle so in ihrem Verhalten ändert, dass bei existierenden Programmen ohne Fehlermeldungen ein Ressourcenleck entstehen kann, da ja nun der Overhead des freigeben der Kopie entstanden ist.
    3. Warum kriege ich beim Austausch ein NULL-Handle zurück, wenn ich das im Ressourceneditor festgelegte autausche? Auch dieses muss doch zur Laufzeit im Speicher irgendwo existieren.

    Kann jemand meine Sorgen verstehen, und mir meinen Denkfehler aufzeigen? Ist meine Lösung vielleicht auch falsch? Gibt es wirklich diese Inkompatibilitäten ab WinXP?

    Sven



  • Hi

    2. Ich glaube nicht, dass Microsoft einfach eine grundlegende Schnittstelle so in ihrem Verhalten ändert, dass bei existierenden Programmen ohne Fehlermeldungen ein Ressourcenleck entstehen kann, da ja nun der Overhead des freigeben der Kopie entstanden ist.

    Ich schon!

    MS bringt sogar schlimmeres fertig.


Anmelden zum Antworten