Toolbar Dialog verursacht Speicherleck [gelöst]



  • Ich habe in einem Dialog-Fenster eine Toolbar (ich nenn sie mal Haupt-Toolbar) eingebaut. Drückt man auf den ersten Knopf der Haupt-Toolbar geht ein zweiter Dialog auf, welche nur aus einer weiteren Toolbar besteht. Dieser schliesst sich automatisch sobald man außerhalb dieser Toolbar klickt.

    Und genau dieser Toolbar-Dialog verursacht ein Speicherleck. Wenn ich den Dialog öffne, werden 8-20 KByte zusätzlichen Speicher reserviert. Dieser Speicher wird aber nicht freigegeben wenn der Dialog geschlossen wird. Das es ein Speicherleck ist scheint mit klar zu sein denn wenn ich den Toolbar-Dialog ständig öffne und schliesse, steigt die Speicheranforderung ohne Probleme um ein paar MByte.

    Im Code mache ich folgendes:

    LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
      ...
      case IDC_FIRST_TOOLBAR_BUTTON_CLICK:
      {
        if (hSecondToolbarDialog  == NULL)
          hSecondToolbarDialog = CreateDialog(hModuleInstance, MAKEINTRESOURCE(IDD_SECONDTOOLBAR), hWnd, SecondToolbar_DialogProc);
        else
        {
          EndDialog(hSecondToolbarDialog, 0);
          hSecondToolbarDialog  = NULL;		
        }
        return 0
      }
      ...
    }
    
    BOOL CALLBACK SecondToolbar_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
      switch(uMsg)
      {
        case WM_INITDIALOG:
        {
          TBADDBITMAP BitmapID;
          TBBUTTON tbButton;
          HWND hToolBar;
          RECT Rect;
    
          hToolBar = CreateWindowEx(0, 
    				TOOLBARCLASSNAME, NULL, 				
    				WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | CCS_NODIVIDER,
    				0, 0, 0, 0,
    				hwndDlg, (HMENU) 1, hModuleInstance, NULL);
          BitmapID.hInst = NULL;
          BitmapID.nID = (UINT_PTR) hFirstToolbarButtonBitmap;
          tbButton.iBitmap = SendMessage(hToolBar, TB_ADDBITMAP, 1, (LPARAM)(LPTBADDBITMAP) &BitmapID);  
          tbButton.idCommand = IDC_FIRSTTOOLBARBUTTON;      
          tbButton.fsState = TBSTATE_ENABLED;
          tbButton.fsStyle = 0;
          tbButton.dwData = 0;
          tbButton.iString = NULL;
          SendMessage(hToolBar, TB_ADDBUTTONS, (WPARAM) 1, (LPARAM) (LPTBBUTTON) &tbButton);
          // Hier werden noch weitere Toolbar Buttons eingefügt
          SendMessage(hToolBar, TB_SETROWS, MAKEWPARAM(1, TRUE), (LPARAM) &Rect);
          ShowWindow(hToolBar, SW_SHOW);
          // Positionierung der Toolbar
          return TRUE;
        }
      }
      return FALSE;
    }
    

    Debugging mittels crtdbg.h bringt keine Ergebnisse. DebugDiag bringt aber folgendes Ergebnis:

    comctl32.dll is responsible for 365,46 KBytes worth of outstanding allocations. The following are the top 2 memory consuming functions:
    comctl32!operator new+10: 275,46 KBytes worth of outstanding allocations.
    comctl32!ToolbarWndProc+4f: 51,33 KBytes worth of outstanding allocations.
    
    ...
    
    Call stack sample 1
    
    Address   0x0017ab18 
    Allocation Time   00:07:01 since tracking started 
    Allocation Size   1,52 KBytes 
    
    Function   Source   Destination 
    comctl32!operator new+10                 kernel32!LocalAlloc 
    comctl32!CImageList::Create+4e           comctl32!operator new 
    comctl32!ImageList_CreateInstance+27     comctl32!CImageList::Create 
    comctl32!ImageList_Create+22             comctl32!ImageList_CreateInstance 
    comctl32!TBAddBitmapToImageList+36       comctl32!ImageList_Create 
    comctl32!AddBitmap+a4                    comctl32!TBAddBitmapToImageList 
    comctl32!ToolbarWndProc+f63              comctl32!AddBitmap 
    user32!InternalCallWinProc+28       
    user32!UserCallWinProcCheckWow+150       user32!InternalCallWinProc 
    user32!SendMessageWorker+4a5             user32!UserCallWinProcCheckWow 
    user32!InternalCreateDialog+9df          user32!SendMessageWorker 
    user32!CreateDialogIndirectParamAorW+33  user32!InternalCreateDialog 
    user32!CreateDialogParamA+4a             user32!CreateDialogIndirectParamAorW 
    TestProjekt!MainWindowProc+14e4          c:\devel\TestProjekt\gui.cpp @ 1141   user32!CreateDialogParamA 
    user32!InternalCallWinProc+28       
    user32!UserCallWinProcCheckWow+150       user32!InternalCallWinProc 
    user32!SendMessageWorker+4a5             user32!UserCallWinProcCheckWow 
    user32!SendMessageW+7f                   user32!SendMessageWorker 
    comctl32!TBOnLButtonUp+122               user32!SendMessageW 
    comctl32!ToolbarWndProc+b30              comctl32!TBOnLButtonUp
    

    Der Verweis gui.cpp @ 1141 zeigt genau auf den CreateDialog Befehl (also wohl in SecondToolbar_DialogProc auf WM_INITDIALOG). Und offenbar scheint die Toolbar sich hier eine Image Liste (mittels TB_ADDBITMAP) aufzubauen, diese aber nicht mehr freizugeben. Warum dies aber nicht nach dem Beenden des Dialog's freigegeben wird, verstehe ich nicht. 😕

    Was mache ich hier falsch ??? 😕



  • Ich bin blöd 😃

    Typischer Fall von Fehlerbehebung durch Fehlerbeschreibung.

    Ich schliesse den Dialog mittels EndDialog() was man nach MSDN nicht machen sollte. Ersetze ich den Befehl durch DestroyWindow verschwindet das Speicherleck.


Anmelden zum Antworten