Memory oder Handle leak bei TreeView Drag&Drop



  • Hi Coders,

    in meinem Programm vermute ich ein Memory- oder Handle-Leak bei den Bitmap-Objekten in einem TreeView-Control.
    (Visual Studio 6, kein MFC o.ä.)

    Mit Tools wie z.B. GDIOBj http://www.fengyuan.com/bin/gdiobj.zip oder Bear http://www.geocities.com/the_real_sz/misc/bear_.htm kann man Handle-Leaks (z.B. GDI-Leaks) bequem aufspüren.

    Angenommen, bei Programmstart werden 7 Bitmaps (d.h. 7 Bitmap-Handles in GDI) angelegt.
    Während eines Drag&Drops in einem TreeView-Control steigt der Verbrauch auf 14 Bitmaps an, soweit ok.
    Nach Beendigung des Drag&Drops geht die Anzahl der Bitmap-Handles jedoch nur noch auf 10 zurück, statt wie erwartet auf den Anfangswert 7.
    Wiederhole ich die gleiche Drag&Drop-Aktion, so steigt der Wert wieder auf den alten Spitzenwert 14 an.
    Danach fällt der Verbrauch erneut auf 10 zurück (und driftet also auch nicht periodisch weg).
    Und das Phänomen ist beliebig oft reproduzierbar.

    Könnt Ihr dieses Phänomen auch bei Euch beobachten?

    Im Grunde genommen sind die "mysteriösen" verbleibenden Leaks von den 3 Bitmap-Handles vernachlässigbar.
    Dennoch würde es mich schon sehr interessieren, warum diese nicht freigegeben werden. Alleine schon um den Lerneffekt zu erhöhen.

    Ich verwende den gleichen Konstrukt, wie er in vielen Codebeispielen im Internet zu finden ist. Lediglich Subclassing wurde noch angewendet.

    Das (stark abgespeckte) Skeleton meines TreeView Drag&Drop in meinem Programm sieht wie folgt aus:
    (Alle Codeteile werden von Proc_Window_Frame() des Parent-Fensters hwnd_frame aus aufgerufen)

    case WM_CREATE:
    hwnd_tree = CreateWindowEx( WS_CHILD... );    //TreeView-Fenster als Child-Fenster generieren.
    pProc_TreeView_original = SetWindowLongPtr( hwnd_tree, GWLP_WNDPROC, (LONG_PTR)Proc_Window_TreeView );
                                                  //Subclassing TreeView WndProc
    himl_tree = ImageList_Create();
    hbitmap = LoadBitmap();
    ImageList_AddMasked( himl_tree, hbitmap );
    DeleteObject( hbitmap );
    b_tree_mousedrag_aktiv = 0;
    
    case WM_NOTIFY:
    
    /* dann -> */ case TVN_BEGINDRAG:
    himl_tree_drag = TreeView_CreateDragImage( pstruct_nmtv->hdr.hwndFrom );
    ImageList_BeginDrag( himl_tree_drag );
    ImageList_DragEnter( pstruct_nmtv->hdr.hwndFrom );
    SetCapture( hwnd_frame );
    b_tree_mousedrag_aktiv = 1;
    
    case WM_MOUSEMOVE:
    if ( b_tree_mousedrag_aktiv != 0 )
    {
      ImageList_DragMove();
      ImageList_DragShowNolock( FALSE );
      TreeView_Select( hwnd_tree, htreeitem, TVGN_DROPHILITE );   //Beim Draggen das darunterliegende Item selektieren.
      ImageList_DragShowNolock( TRUE );
    }
    
    case WM_LBUTTONUP:      //Drag&Drop erfolgreich umsetzen.
    case WM_CAPTURECHANGED: //Drag&Drop abbrechen.
    case WM_RBUTTONDOWN:    //Drag&Drop abbrechen.
    if ( b_tree_mousedrag_aktiv != 0 )
    {
      ImageList_DragLeave( hwnd_tree );
      ImageList_EndDrag();
      //ImageList_RemoveAll( himl_tree_drag );  // <-- habe ich in keinem Sample gesehen, hat aber leider keine Auswirkung.
      ImageList_Destroy( himl_tree_drag );
      b_tree_mousedrag_aktiv = 0;
      ReleaseCapture(); //Calling ReleaseCapture() causes the window that is losing
                        //the mouse capture to receive a WM_CAPTURECHANGED message.
      ShowCursor( TRUE );
    }
    

    Ich hoffe, ich habe nicht zuviel von meinem Code wegkopiert?
    (Damit die Lesbarkeit nicht unnötig erschwert wird, sind auch die notwendigen Fehlerabfragen bereits entfernt)

    Bin auf Eure Hinweise dankbar,
    Martin


  • Mod

    So wie ich das sehe ist das kein Leak. Die Anzahl der Handles steigt ja nicht weiter.

    1. ImageList_BeginDrag erzegt eine interne Kopie der Imagelist, Du kannst Deine Kopie sofort entsorgen, nachdem Du ImageList_BeginDrag aufgerufen hast!
    2. ImageList_EndDrag entsorgt IMHO einige ImageLists aber nicht alle. Einige werden einfach weiterhin im Speicher gehalten und wiederverwendet.



  • Hi Martin,
    das ist aber eine fixe Antwort 👍

    Danke für das Hintergrundinfo!
    Martin


Anmelden zum Antworten