2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
19 #include <WINNT/tal_alloc.h>
20 #include <winnt/osi_malloc.h>
24 * PARAMETERS _________________________________________________________________
28 #define cDEFAULT_BUCKETS 128
30 #define dwSIG_AT_END 'Okay'
32 #define iINVALID ((size_t)-1)
34 #define MIN_BUCKETS(_cObjects) ((_cObjects) / 23)
35 #define TARGET_BUCKETS(_cObjects) ((_cObjects) / 5)
39 #define cmsecREFRESH 1000
43 * DEFINITIONS ________________________________________________________________
49 PVOID aElements; // = EXPANDARRAYHEAP.aElements + 4;
50 // Followed by allocated space for aElements
51 } EXPANDARRAYHEAP, *LPEXPANDARRAYHEAP;
53 class ALLOCEXPANDARRAY
56 ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap = 0);
57 ~ALLOCEXPANDARRAY (void);
59 PVOID GetAt (size_t iElement);
60 void SetAt (size_t iElement, PVOID pData);
64 size_t m_cElementsPerHeap;
67 LPEXPANDARRAYHEAP *m_aHeaps;
85 } MEMCHUNK, *PMEMCHUNK;
99 LONG cAllocTotalTared;
103 LONG cbAllocCppTared;
104 LONG cbAllocDynaTared;
105 LONG cbAllocTotalTared;
110 CRITICAL_SECTION *pcs;
114 ALLOCEXPANDARRAY *pHeap;
131 #define HASH(_dw,_cTable) (((DWORD)(_dw) >> 4) % (_cTable))
135 * REALLOC ____________________________________________________________________
140 #define REALLOC(_a,_c,_r,_i) Alloc_ReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
141 BOOL Alloc_ReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
146 if (cReq <= *pcTarget)
149 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
152 if ((pNew = (LPVOID)GlobalAlloc (GMEM_FIXED, cbElement * cNew)) == NULL)
154 memset (pNew, 0x00, cbElement * cNew);
157 memset (pNew, 0x00, cbElement * cNew);
160 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
161 memset (&((char*)pNew)[ cbElement * (*pcTarget) ], 0x00, cbElement * (cNew - *pcTarget));
162 GlobalFree ((HGLOBAL)*ppTarget);
173 * USER INTERFACE ROUTINES ____________________________________________________
177 #define IDC_INITIALIZE 100
178 #define IDC_BOX_ALLOC 101
179 #define IDC_LABEL_CPP 102
180 #define IDC_LABEL_OTHER 103
181 #define IDC_LABEL_TARED 104
182 #define IDC_LABEL_TOTAL 106
183 #define IDC_LABEL_COUNT 107
184 #define IDC_LABEL_SIZE 108
185 #define IDC_LABEL_AVERAGE 109
186 #define IDC_VALUE_CPP_COUNT 110
187 #define IDC_VALUE_OTHER_COUNT 111
188 #define IDC_VALUE_TARED_COUNT 112
189 #define IDC_VALUE_TOTAL_COUNT 113
190 #define IDC_VALUE_CPP_SIZE 114
191 #define IDC_VALUE_OTHER_SIZE 115
192 #define IDC_VALUE_TARED_SIZE 116
193 #define IDC_VALUE_TOTAL_SIZE 117
194 #define IDC_VALUE_CPP_AVERAGE 118
195 #define IDC_VALUE_OTHER_AVERAGE 119
196 #define IDC_VALUE_TARED_AVERAGE 120
197 #define IDC_VALUE_TOTAL_AVERAGE 121
198 #define IDC_BOX_DETAILS 122
200 #define IDC_LABEL 124
203 #define IDC_RESET 127
204 #define IDC_REFRESH 128
205 #define IDC_LIST_ADD 129
206 #define IDC_LIST_REMOVE 130
207 #define IDC_LIST_REMOVEADD 131
209 #define cszTITLE TEXT("Memory Manager")
222 RECT rValueOtherCount;
223 RECT rValueTaredCount;
224 RECT rValueTotalCount;
226 RECT rValueOtherSize;
227 RECT rValueTaredSize;
228 RECT rValueTotalSize;
229 RECT rValueCppAverage;
230 RECT rValueOtherAverage;
231 RECT rValueTaredAverage;
232 RECT rValueTotalAverage;
252 HWND MakeWindow (LPCTSTR pszClass, LPCTSTR pszTitle, DWORD dwStyle, RECT *prSource, HWND hParent, UINT idc, DWORD dwStyleEx = 0)
254 RECT rr = { 0, 0, 16, 16 };
257 HWND hWnd = CreateWindowEx (dwStyleEx, pszClass, pszTitle, dwStyle, rr.left, rr.top, rr.right - rr.left, rr.bottom - rr.top, hParent, (HMENU)idc, GetModuleHandle(0), 0);
259 SendMessage (hWnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 1);
263 void SetWindowRect (HWND hWnd, RECT *pr)
265 SetWindowPos (hWnd, 0, pr->left, pr->top, pr->right - pr->left, pr->bottom - pr->top, SWP_NOZORDER | SWP_NOACTIVATE);
268 void FormatBytes (LPTSTR pszText, double lfValue)
273 *pszText++ = TEXT('-');
276 if (lfValue >= 1048576)
278 LONG Value = (LONG)(lfValue / 1048576);
279 lfValue -= Value * 1048576;
280 LONG Frac = (LONG)(lfValue * 100 / 1048576);
281 wsprintf (pszText, TEXT("%ld.%ld MB"), Value, Frac);
283 else if (lfValue >= 3072)
285 LONG Value = (LONG)(lfValue / 1024);
286 lfValue -= Value * 1024;
287 LONG Frac = (LONG)(lfValue * 100 / 1024);
288 wsprintf (pszText, TEXT("%ld.%ld kb"), Value, Frac);
290 else // (lfValue < 3072)
292 wsprintf (pszText, TEXT("%ld b"), (LONG)lfValue);
296 void FormatTime (LPTSTR pszText, DWORD dwTick)
298 static FILETIME ftTickZero = { 0, 0 };
299 if (!ftTickZero.dwHighDateTime && !ftTickZero.dwLowDateTime)
301 // We need to find out what FILETIME corresponds with a tick
302 // count of zero. To do that, first find the FILETIME and tick
303 // count that represent *now* (in local time).
306 GetLocalTime (&stNow);
307 SystemTimeToFileTime (&stNow, &ftTickZero);
309 DWORD dwTickNow = GetTickCount();
311 // A FILETIME is a count-of-100ns-intervals, and a tick count is
312 // a count of 1ms-intervals. So we need to subtract off a big
313 // number times our tick count.
315 if ((dwTickNow * 10000) < (dwTickNow))
316 ftTickZero.dwHighDateTime --;
317 dwTickNow *= 10000; // convert to 100ns intervals
318 if (dwTickNow > ftTickZero.dwLowDateTime)
319 ftTickZero.dwHighDateTime --;
320 ftTickZero.dwLowDateTime -= dwTickNow; // unsigned, so it'll wrap OK
323 // Convert the given tick count into 100ns intervals, and add it
324 // to our ftTickZero.
326 FILETIME ftTick = ftTickZero;
328 if ((dwTick * 10000) < (dwTick))
329 ftTick.dwHighDateTime ++;
330 dwTick *= 10000; // convert to 100ns intervals
331 if (dwTick > (DWORD)(0-ftTick.dwLowDateTime)) // too big to add?
332 ftTick.dwHighDateTime ++;
333 ftTick.dwLowDateTime += dwTick; // unsigned, so it'll wrap OK
335 // Convert to a SYSTEMTIME, and output the time component
338 FileTimeToSystemTime (&ftTick, &stTick);
340 wsprintf (pszText, TEXT("%ld:%02ld:%02ld.%02ld"),
342 (DWORD)stTick.wMinute,
343 (DWORD)stTick.wSecond,
344 (DWORD)(stTick.wMilliseconds / 100));
347 void SetDlgItemBytes (HWND hDlg, int idc, double lfValue)
350 FormatBytes (szText, lfValue);
351 SetDlgItemText (hDlg, idc, szText);
355 void MemMgr_ShowWarning (PMEMCHUNK pChunk, LPSTR pszFile, DWORD dwLine, LPTSTR pszDesc)
357 TCHAR szMessage[ 1024 ];
358 wsprintf (szMessage, TEXT("%s\n\n Address: 0x%08lX (%s)\n Allocated: %s line %ld\n Freed: %s line %ld\n\nClick OK for memory details."), pszDesc, pChunk->pData, pChunk->pszExpr, pChunk->pszFile, pChunk->dwLine, pszFile, dwLine);
359 if (MessageBox (NULL, szMessage, cszTITLE, MB_ICONHAND | MB_OKCANCEL | MB_DEFBUTTON2) == IDOK)
361 // TODO: Show Details
365 void MIX (RECT *pr, RECT *pr1, RECT *pr2)
367 pr->left = pr2->left;
369 pr->right = pr2->right;
370 pr->bottom = pr1->bottom;
373 void MemMgr_GetWindowSizes (WINDOWSIZES *pSizes)
376 GetClientRect (l.hManager, &rClient);
377 InflateRect (&rClient, 0-cBORDER, 0-cBORDER);
379 pSizes->rLabelAverage.right = rClient.right -cxBETWEEN*2;
380 pSizes->rLabelAverage.top = rClient.top +8 +cyBETWEEN;
381 pSizes->rLabelAverage.left = pSizes->rLabelAverage.right -cxVALUES;
382 pSizes->rLabelAverage.bottom = pSizes->rLabelAverage.top +cyLABELS;
384 pSizes->rLabelSize = pSizes->rLabelAverage;
385 pSizes->rLabelSize.left -= cxBETWEEN + cxVALUES;
386 pSizes->rLabelSize.right -= cxBETWEEN + cxVALUES;
388 pSizes->rLabelCount = pSizes->rLabelSize;
389 pSizes->rLabelCount.left -= cxBETWEEN + cxVALUES;
390 pSizes->rLabelCount.right -= cxBETWEEN + cxVALUES;
392 pSizes->rLabelCpp.left = rClient.left +cxBETWEEN;
393 pSizes->rLabelCpp.top = pSizes->rLabelCount.bottom +cyBETWEEN;
394 pSizes->rLabelCpp.right = pSizes->rLabelCpp.left +cxLABELS;
395 pSizes->rLabelCpp.bottom = pSizes->rLabelCpp.top +cyLABELS;
397 pSizes->rLabelOther = pSizes->rLabelCpp;
398 pSizes->rLabelOther.top += cyBETWEEN + cyLABELS;
399 pSizes->rLabelOther.bottom += cyBETWEEN + cyLABELS;
401 pSizes->rLabelTotal = pSizes->rLabelOther;
402 pSizes->rLabelTotal.top += cyBETWEEN + cyLABELS;
403 pSizes->rLabelTotal.bottom += cyBETWEEN + cyLABELS;
405 pSizes->rLabelTared = pSizes->rLabelTotal;
406 pSizes->rLabelTared.top += cyBETWEEN + cyLABELS;
407 pSizes->rLabelTared.bottom += cyBETWEEN + cyLABELS;
409 pSizes->rBoxAlloc = rClient;
410 pSizes->rBoxAlloc.bottom = pSizes->rLabelTared.bottom +cyBETWEEN;
412 MIX (&pSizes->rValueCppCount, &pSizes->rLabelCpp, &pSizes->rLabelCount);
413 MIX (&pSizes->rValueOtherCount, &pSizes->rLabelOther, &pSizes->rLabelCount);
414 MIX (&pSizes->rValueTaredCount, &pSizes->rLabelTared, &pSizes->rLabelCount);
415 MIX (&pSizes->rValueTotalCount, &pSizes->rLabelTotal, &pSizes->rLabelCount);
417 MIX (&pSizes->rValueCppSize, &pSizes->rLabelCpp, &pSizes->rLabelSize);
418 MIX (&pSizes->rValueOtherSize, &pSizes->rLabelOther, &pSizes->rLabelSize);
419 MIX (&pSizes->rValueTaredSize, &pSizes->rLabelTared, &pSizes->rLabelSize);
420 MIX (&pSizes->rValueTotalSize, &pSizes->rLabelTotal, &pSizes->rLabelSize);
422 MIX (&pSizes->rValueCppAverage, &pSizes->rLabelCpp, &pSizes->rLabelAverage);
423 MIX (&pSizes->rValueOtherAverage, &pSizes->rLabelOther, &pSizes->rLabelAverage);
424 MIX (&pSizes->rValueTaredAverage, &pSizes->rLabelTared, &pSizes->rLabelAverage);
425 MIX (&pSizes->rValueTotalAverage, &pSizes->rLabelTotal, &pSizes->rLabelAverage);
427 pSizes->rBoxDetails = rClient;
428 pSizes->rBoxDetails.top = pSizes->rBoxAlloc.bottom +cyBETWEEN;
429 pSizes->rBoxDetails.bottom -= cyBUTTONS +cyBETWEEN;
431 pSizes->rList = pSizes->rBoxDetails;
432 pSizes->rList.top += 8;
433 InflateRect (&pSizes->rList, 0-cBORDER, 0-cBORDER);
435 pSizes->rClose = rClient;
436 pSizes->rClose.top = pSizes->rClose.bottom - cyBUTTONS;
437 pSizes->rClose.left = pSizes->rClose.right - cxBUTTONS;
439 pSizes->rReset = pSizes->rClose;
440 pSizes->rReset.right = pSizes->rClose.left - cxBETWEEN;
441 pSizes->rReset.left = pSizes->rReset.right - cxBUTTONS;
443 pSizes->rTare = pSizes->rClose;
444 pSizes->rTare.right = pSizes->rReset.left - cxBETWEEN;
445 pSizes->rTare.left = pSizes->rTare.right - cxBUTTONS;
447 pSizes->rLabel = pSizes->rTare;
448 pSizes->rLabel.right = pSizes->rTare.left - cxBETWEEN;
449 pSizes->rLabel.left = pSizes->rLabel.right - cxBUTTONS;
451 pSizes->rHide = pSizes->rLabel;
452 pSizes->rHide.right = pSizes->rLabel.left - cxBETWEEN;
453 pSizes->rHide.left = pSizes->rHide.right - cxBUTTONS;
456 void MemMgr_OnSize (void)
459 MemMgr_GetWindowSizes (&Sizes);
460 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_ALLOC), &Sizes.rBoxAlloc);
461 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_CPP), &Sizes.rLabelCpp);
462 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_OTHER), &Sizes.rLabelOther);
463 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TARED), &Sizes.rLabelTared);
464 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TOTAL), &Sizes.rLabelTotal);
465 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_COUNT), &Sizes.rLabelCount);
466 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_SIZE), &Sizes.rLabelSize);
467 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_AVERAGE), &Sizes.rLabelAverage);
468 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_COUNT), &Sizes.rValueCppCount);
469 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_COUNT), &Sizes.rValueOtherCount);
470 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_COUNT), &Sizes.rValueTaredCount);
471 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_COUNT), &Sizes.rValueTotalCount);
472 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_SIZE), &Sizes.rValueCppSize);
473 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_SIZE), &Sizes.rValueOtherSize);
474 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_SIZE), &Sizes.rValueTaredSize);
475 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_SIZE), &Sizes.rValueTotalSize);
476 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_AVERAGE), &Sizes.rValueCppAverage);
477 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_AVERAGE), &Sizes.rValueOtherAverage);
478 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_AVERAGE), &Sizes.rValueTaredAverage);
479 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_AVERAGE), &Sizes.rValueTotalAverage);
480 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_DETAILS), &Sizes.rBoxDetails);
481 SetWindowRect (GetDlgItem (l.hManager, IDC_LIST), &Sizes.rList);
482 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL), &Sizes.rLabel);
483 SetWindowRect (GetDlgItem (l.hManager, IDC_HIDE), &Sizes.rHide);
484 SetWindowRect (GetDlgItem (l.hManager, IDC_TARE), &Sizes.rTare);
485 SetWindowRect (GetDlgItem (l.hManager, IDC_RESET), &Sizes.rReset);
486 SetWindowRect (GetDlgItem (l.hManager, IDCANCEL), &Sizes.rClose);
490 void MemMgr_OnListRemove (PVOID pData)
492 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
495 Find.flags = LVFI_PARAM;
496 Find.lParam = (LPARAM)pData;
499 if ((iItem = ListView_FindItem (hList, 0, &Find)) == -1)
501 // The listview's find feature sucks; I've seen with my own little
502 // eyes that it may miss an item if it's the only one in a list.
503 // Look for ourselves.
505 int cItems = ListView_GetItemCount(hList);
506 for (iItem = 0; iItem < cItems; ++iItem)
510 Item.mask = LVIF_PARAM;
511 ListView_GetItem (hList, &Item);
512 if (Item.lParam == (LPARAM)pData)
519 ListView_DeleteItem (hList, iItem);
524 void MemMgr_RemoveFromList (PMEMCHUNK pChunk)
526 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVE, (LPARAM)(pChunk->pData));
527 pChunk->fInList = FALSE;
531 LPTSTR MemMgr_GetItemKey (HWND hList, int iItem)
533 static TCHAR szText[ 256 ];
534 LPTSTR pszReturn = NULL;
543 Item.mask = LVIF_PARAM;
544 ListView_GetItem (hList, &Item);
546 EnterCriticalSection (l.pcs);
549 iBucket = HASH(Item.lParam,l.cBuckets);
555 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
557 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
559 if (pChunk->pData == (PVOID)Item.lParam)
561 if ((iChunk = pChunk->iNext) == iINVALID)
570 if (lr.iColSort == 0)
571 pszReturn = (LPTSTR)pChunk->dwTick;
572 else if (lr.iColSort == 4)
573 pszReturn = (LPTSTR)pChunk->cbData;
574 else // (lr.iColSort == 5)
575 pszReturn = (LPTSTR)pChunk->pData;
578 LeaveCriticalSection (l.pcs);
582 ListView_GetItemText (hList, iItem, lr.iColSort, szText, 256);
591 int MemMgr_CompareItems (LPTSTR pszKey1, LPTSTR pszKey2)
600 dw = (int)( (DWORD)pszKey1 - (DWORD)pszKey2 );
604 dw = lstrcmpi (pszKey1, pszKey2);
608 return (lr.fSortRev) ? (0-dw) : dw;
612 int MemMgr_PickListInsertionPoint (HWND hList, LPTSTR pszKey)
615 int iItemHigh = ListView_GetItemCount (hList) -1;
617 while (iItemLow <= iItemHigh)
619 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
621 LPTSTR pszAlternate = MemMgr_GetItemKey (hList, iItemTest);
623 int iCompare = MemMgr_CompareItems (pszKey, pszAlternate);
626 if ((iItemHigh = iItemTest-1) < iItemLow)
631 if ((iItemLow = iItemTest+1) > iItemHigh)
640 void MemMgr_OnListAdd (PMEMCHUNK pCopy)
642 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
645 FormatTime (szTime, pCopy->dwTick);
648 LPTSTR pszFlags = szFlags;
649 *pszFlags++ = (pCopy->fCPP) ? TEXT('C') : TEXT(' ');
650 *pszFlags++ = TEXT(' ');
651 *pszFlags++ = (pCopy->fFreed) ? TEXT('F') : TEXT(' ');
655 lstrcpy (szExpr, (pCopy->pszExpr) ? pCopy->pszExpr : TEXT("unknown"));
657 LPTSTR pszFile = pCopy->pszFile;
658 for (LPTSTR psz = pCopy->pszFile; *psz; ++psz)
660 if ((*psz == TEXT(':')) || (*psz == TEXT('\\')))
663 TCHAR szLocation[256];
664 if (!pszFile || !pCopy->dwLine)
665 lstrcpy (szLocation, TEXT("unknown"));
667 wsprintf (szLocation, TEXT("%s, %ld"), pszFile, pCopy->dwLine);
670 FormatBytes (szBytes, pCopy->cbData);
672 TCHAR szAddress[256];
673 wsprintf (szAddress, TEXT("0x%08lX"), pCopy->pData);
675 LPTSTR pszKey = NULL;
678 case 0: pszKey = (LPTSTR)pCopy->dwTick; break;
679 case 1: pszKey = (LPTSTR)szFlags; break;
680 case 2: pszKey = (LPTSTR)szExpr; break;
681 case 3: pszKey = (LPTSTR)szLocation; break;
682 case 4: pszKey = (LPTSTR)pCopy->cbData; break;
683 case 5: pszKey = (LPTSTR)pCopy->pData; break;
687 memset (&Item, 0x00, sizeof(Item));
688 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
689 Item.iItem = MemMgr_PickListInsertionPoint (hList, pszKey);
691 Item.cchTextMax = 256;
692 Item.lParam = (LPARAM)pCopy->pData;
694 Item.pszText = szTime;
695 DWORD iItem = ListView_InsertItem (hList, &Item);
696 ListView_SetItemText (hList, iItem, 1, szFlags);
697 ListView_SetItemText (hList, iItem, 2, szExpr);
698 ListView_SetItemText (hList, iItem, 3, szLocation);
699 ListView_SetItemText (hList, iItem, 4, szBytes);
700 ListView_SetItemText (hList, iItem, 5, szAddress);
706 void MemMgr_AddToList (PMEMCHUNK pChunk)
708 PMEMCHUNK pCopy = new MEMCHUNK;
709 memcpy (pCopy, pChunk, sizeof(MEMCHUNK));
712 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVEADD, (LPARAM)pCopy);
714 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_ADD, (LPARAM)pCopy);
715 pChunk->fInList = TRUE;
719 void MemMgr_RestoreSettings (void)
721 lr.rManager.left = 0;
723 lr.rManager.right = 510;
724 lr.rManager.bottom = 440;
725 lr.acxColumns[0] = 70;
726 lr.acxColumns[1] = 40;
727 lr.acxColumns[2] = 100;
728 lr.acxColumns[3] = 110;
729 lr.acxColumns[4] = 50;
730 lr.acxColumns[5] = 80;
735 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
737 DWORD dwType = REG_BINARY;
738 DWORD dwSize = sizeof(lr);
739 RegQueryValueEx (hk, TEXT("Settings"), 0, &dwType, (PBYTE)&lr, &dwSize);
744 void MemMgr_StoreSettings (void)
746 if (IsWindow (l.hManager))
748 GetWindowRect (l.hManager, &lr.rManager);
750 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
751 if (IsWindow (hList))
753 for (size_t ii = 0; ii < 6; ++ii)
754 lr.acxColumns[ ii ] = ListView_GetColumnWidth (hList, ii);
759 if (RegCreateKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
761 RegSetValueEx (hk, TEXT("Settings"), 0, REG_BINARY, (PBYTE)&lr, sizeof(lr));
766 void MemMgr_OnInit (void)
768 DWORD dwFlags = WS_CHILD | WS_TABSTOP | WS_VISIBLE;
769 MakeWindow (TEXT("Button"), TEXT("Allocation Statistics"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_ALLOC);
770 MakeWindow (TEXT("Static"), TEXT("C++ Objects:"), dwFlags, NULL, l.hManager, IDC_LABEL_CPP);
771 MakeWindow (TEXT("Static"), TEXT("Dynamic:"), dwFlags, NULL, l.hManager, IDC_LABEL_OTHER);
772 MakeWindow (TEXT("Static"), TEXT("Combined:"), dwFlags, NULL, l.hManager, IDC_LABEL_TOTAL);
773 MakeWindow (TEXT("Static"), TEXT("Tared:"), dwFlags, NULL, l.hManager, IDC_LABEL_TARED);
774 MakeWindow (TEXT("Static"), TEXT("Count"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_COUNT);
775 MakeWindow (TEXT("Static"), TEXT("Size"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_SIZE);
776 MakeWindow (TEXT("Static"), TEXT("Average"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_AVERAGE);
777 MakeWindow (TEXT("Static"), TEXT("0"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_COUNT);
778 MakeWindow (TEXT("Static"), TEXT("1"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_COUNT);
779 MakeWindow (TEXT("Static"), TEXT("2"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_COUNT);
780 MakeWindow (TEXT("Static"), TEXT("3"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_COUNT);
781 MakeWindow (TEXT("Static"), TEXT("4"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_SIZE);
782 MakeWindow (TEXT("Static"), TEXT("5"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_SIZE);
783 MakeWindow (TEXT("Static"), TEXT("6"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_SIZE);
784 MakeWindow (TEXT("Static"), TEXT("7"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_SIZE);
785 MakeWindow (TEXT("Static"), TEXT("8"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_AVERAGE);
786 MakeWindow (TEXT("Static"), TEXT("9"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_AVERAGE);
787 MakeWindow (TEXT("Static"), TEXT("10"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_AVERAGE);
788 MakeWindow (TEXT("Static"), TEXT("11"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_AVERAGE);
789 MakeWindow (TEXT("Button"), TEXT("Details"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_DETAILS);
790 MakeWindow (WC_LISTVIEW, TEXT(""), dwFlags | LVS_REPORT | LVS_SINGLESEL, NULL, l.hManager, IDC_LIST, WS_EX_CLIENTEDGE);
791 // MakeWindow (TEXT("Button"), TEXT("Label"), dwFlags, NULL, l.hManager, IDC_LABEL);
792 // MakeWindow (TEXT("Button"), TEXT("Hidden"), dwFlags, NULL, l.hManager, IDC_HIDE);
793 MakeWindow (TEXT("Button"), TEXT("Tare"), dwFlags, NULL, l.hManager, IDC_TARE);
794 MakeWindow (TEXT("Button"), TEXT("Restore"), dwFlags, NULL, l.hManager, IDC_RESET);
795 MakeWindow (TEXT("Button"), TEXT("Close"), dwFlags, NULL, l.hManager, IDCANCEL);
798 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
801 Col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM;
802 Col.fmt = LVCFMT_LEFT;
804 Col.cx = lr.acxColumns[0];
805 Col.pszText = TEXT("Time");
806 ListView_InsertColumn (hList, Col.iSubItem, &Col);
808 Col.cx = lr.acxColumns[1];
809 Col.pszText = TEXT("Flags");
811 ListView_InsertColumn (hList, Col.iSubItem, &Col);
813 Col.cx = lr.acxColumns[2];
814 Col.pszText = TEXT("Expression");
816 ListView_InsertColumn (hList, Col.iSubItem, &Col);
818 Col.cx = lr.acxColumns[3];
819 Col.pszText = TEXT("Location");
821 ListView_InsertColumn (hList, Col.iSubItem, &Col);
823 Col.fmt = LVCFMT_RIGHT;
824 Col.cx = lr.acxColumns[4];
825 Col.pszText = TEXT("Size");
827 ListView_InsertColumn (hList, Col.iSubItem, &Col);
829 Col.cx = lr.acxColumns[5];
830 Col.pszText = TEXT("Address");
832 ListView_InsertColumn (hList, Col.iSubItem, &Col);
834 EnterCriticalSection (l.pcs);
835 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
837 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
840 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
843 pChunk->fInList = FALSE;
844 if (!pChunk->fTared && !pChunk->fFreed)
845 MemMgr_AddToList (pChunk);
848 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
849 LeaveCriticalSection (l.pcs);
851 l.idTimer = SetTimer (l.hManager, 0, cmsecREFRESH, NULL);
854 void MemMgr_OnRefresh (void)
856 // Fill in the statistics at the top of the manager dialog
858 SetDlgItemInt (l.hManager, IDC_VALUE_CPP_COUNT, l.Stats.cAllocCpp, TRUE);
859 SetDlgItemInt (l.hManager, IDC_VALUE_OTHER_COUNT, l.Stats.cAllocDyna, TRUE);
860 SetDlgItemInt (l.hManager, IDC_VALUE_TARED_COUNT, l.Stats.cAllocTotalTared, TRUE);
861 SetDlgItemInt (l.hManager, IDC_VALUE_TOTAL_COUNT, l.Stats.cAllocTotal, TRUE);
863 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_SIZE, (double)l.Stats.cbAllocCpp);
864 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_SIZE, (double)l.Stats.cbAllocDyna);
865 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_SIZE, (double)l.Stats.cbAllocTotalTared);
866 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_SIZE, (double)l.Stats.cbAllocTotal);
868 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_AVERAGE, (l.Stats.cAllocCpp) ? ((double)l.Stats.cbAllocCpp / l.Stats.cAllocCpp) : 0);
869 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_AVERAGE, (l.Stats.cAllocDyna) ? ((double)l.Stats.cbAllocDyna / l.Stats.cAllocDyna) : 0);
870 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_AVERAGE, (l.Stats.cAllocTotalTared) ? ((double)l.Stats.cbAllocTotalTared / l.Stats.cAllocTotalTared) : 0);
871 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_AVERAGE, (l.Stats.cAllocTotal) ? ((double)l.Stats.cbAllocTotal / l.Stats.cAllocTotal) : 0);
874 void MemMgr_OnLabel (void)
879 void MemMgr_OnHide (void)
884 void MemMgr_OnReset (void)
886 l.Stats.cAllocCpp += l.Stats.cAllocCppTared;
887 l.Stats.cAllocDyna += l.Stats.cAllocDynaTared;
888 l.Stats.cAllocTotal += l.Stats.cAllocTotalTared;
889 l.Stats.cbAllocCpp += l.Stats.cbAllocCppTared;
890 l.Stats.cbAllocDyna += l.Stats.cbAllocDynaTared;
891 l.Stats.cbAllocTotal += l.Stats.cbAllocTotalTared;
893 l.Stats.cAllocCppTared = 0;
894 l.Stats.cAllocDynaTared = 0;
895 l.Stats.cAllocTotalTared = 0;
896 l.Stats.cbAllocCppTared = 0;
897 l.Stats.cbAllocDynaTared = 0;
898 l.Stats.cbAllocTotalTared = 0;
900 EnterCriticalSection (l.pcs);
901 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
903 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
905 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
908 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
911 pChunk->fInList = FALSE;
912 pChunk->fTared = FALSE;
914 MemMgr_AddToList (pChunk);
917 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
918 LeaveCriticalSection (l.pcs);
923 void MemMgr_OnTare (void)
925 l.Stats.cAllocCppTared += l.Stats.cAllocCpp;
926 l.Stats.cAllocDynaTared += l.Stats.cAllocDyna;
927 l.Stats.cAllocTotalTared += l.Stats.cAllocTotal;
928 l.Stats.cbAllocCppTared += l.Stats.cbAllocCpp;
929 l.Stats.cbAllocDynaTared += l.Stats.cbAllocDyna;
930 l.Stats.cbAllocTotalTared += l.Stats.cbAllocTotal;
932 l.Stats.cAllocCpp = 0;
933 l.Stats.cAllocDyna = 0;
934 l.Stats.cAllocTotal = 0;
935 l.Stats.cbAllocCpp = 0;
936 l.Stats.cbAllocDyna = 0;
937 l.Stats.cbAllocTotal = 0;
939 EnterCriticalSection (l.pcs);
940 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
942 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
944 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
947 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
950 pChunk->fInList = FALSE;
951 pChunk->fTared = TRUE;
954 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
955 LeaveCriticalSection (l.pcs);
961 void MemMgr_OnSort (void)
963 EnterCriticalSection (l.pcs);
964 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
966 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
968 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
971 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
974 pChunk->fInList = FALSE;
975 if (!pChunk->fTared && !pChunk->fFreed)
976 MemMgr_AddToList (pChunk);
979 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
980 LeaveCriticalSection (l.pcs);
984 void MemMgr_OnPaint (void)
987 HDC hdc = BeginPaint (l.hManager, &ps);
989 static HBRUSH hbr = (HBRUSH)CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
990 FillRect (hdc, &ps.rcPaint, hbr);
992 EndPaint (l.hManager, &ps);
996 void MemMgr_OnTimer (void)
998 if (GetWindowLong (l.hManager, GWL_USERDATA))
1000 SetWindowLong (l.hManager, GWL_USERDATA, 0);
1006 void MemMgr_OnDelayedRefresh (void)
1008 SetWindowLong (l.hManager, GWL_USERDATA, 1);
1012 BOOL CALLBACK MemMgr_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1017 MemMgr_StoreSettings();
1019 KillTimer (hDlg, l.idTimer);
1025 MemMgr_StoreSettings();
1029 MemMgr_StoreSettings();
1032 case WM_GETMINMAXINFO:
1034 lpmmi = (LPMINMAXINFO)lp;
1035 lpmmi->ptMinTrackSize.x = cxBUTTONS*5 + cxBETWEEN*4 + cBORDER*2 + 8;
1036 lpmmi->ptMinTrackSize.y = 270;
1044 switch (((NMHDR *)lp)->code)
1046 case LVN_COLUMNCLICK:
1047 if (((NM_LISTVIEW*)lp)->iSubItem == lr.iColSort)
1048 lr.fSortRev = !lr.fSortRev;
1051 lr.iColSort = ((NM_LISTVIEW*)lp)->iSubItem;
1052 lr.fSortRev = FALSE;
1055 MemMgr_StoreSettings();
1068 DestroyWindow (hDlg);
1071 case IDC_INITIALIZE:
1077 MemMgr_OnDelayedRefresh();
1096 case IDC_LIST_REMOVEADD:
1097 MemMgr_OnListRemove (((PMEMCHUNK)lp)->pData);
1098 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1102 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1105 case IDC_LIST_REMOVE:
1106 MemMgr_OnListRemove ((PVOID)lp);
1112 return DefWindowProc (hDlg, msg, wp, lp);
1117 * MANAGEMENT ROUTINES ________________________________________________________
1121 BOOL MemMgr_Initialize (void)
1125 l.pcs = new CRITICAL_SECTION;
1126 InitializeCriticalSection (l.pcs);
1128 l.pHeap = new ALLOCEXPANDARRAY (sizeof(MEMCHUNK));
1130 REALLOC (l.aBuckets, l.cBuckets, cDEFAULT_BUCKETS, 1);
1133 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1134 l.aBuckets[ii].iFirst = iINVALID;
1138 return (l.pHeap) && (l.aBuckets);
1142 void MemMgr_TrackAllocation (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine, BOOL fSig)
1146 if (!MemMgr_Initialize())
1149 EnterCriticalSection (l.pcs);
1151 // Ensure our hash table will be large enough to handle the new
1152 // MEMCHUNK we're about to assign.
1154 if (l.cBuckets < MIN_BUCKETS(l.cChunks+1))
1156 // Too small! Rebuild the hash table.
1158 REALLOC (l.aBuckets, l.cBuckets, TARGET_BUCKETS(l.cChunks+1), 1);
1161 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1162 l.aBuckets[ii].iFirst = iINVALID;
1164 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
1167 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1170 size_t iBucket = HASH(pChunk->pData,l.cBuckets);
1171 if ((pChunk->iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1174 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1175 pNext->iPrev = iChunk;
1177 l.aBuckets[iBucket].iFirst = iChunk;
1178 pChunk->iPrev = iINVALID;
1183 // If space was allocated for a trailing signature, write one
1186 *(DWORD *)( (PBYTE)pData + cb ) = dwSIG_AT_END;
1188 // Prepare a MEMCHUNK entry and shove it in our array
1190 size_t iChunk = l.cChunks;
1191 size_t iBucket = HASH(pData,l.cBuckets);
1192 BOOL fLinkIn = TRUE;
1195 Chunk.pData = pData;
1196 Chunk.fFreed = FALSE;
1198 Chunk.pszExpr = pszExpr;
1199 Chunk.pszFile = pszFile;
1201 Chunk.dwLine = dwLine;
1202 Chunk.dwTick = GetTickCount();
1203 Chunk.dwEndSig = (fSig) ? dwSIG_AT_END : 0;
1204 Chunk.fInList = FALSE;
1205 Chunk.fTared = FALSE;
1208 // Find the memchunk associated with this pData. That's what our
1209 // hash table is for.
1211 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1214 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) != NULL)
1216 if (pChunk->pData == pData)
1218 Chunk.iNext = pChunk->iNext;
1219 Chunk.iPrev = pChunk->iPrev;
1224 iChunk = (pChunk) ? pChunk->iNext : iINVALID;
1226 if (iChunk == iINVALID)
1230 l.cChunks = max (l.cChunks, 1+iChunk);
1234 if ((Chunk.iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1237 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(Chunk.iNext)) != NULL)
1238 pNext->iPrev = iChunk;
1240 l.aBuckets[iBucket].iFirst = iChunk;
1241 Chunk.iPrev = iINVALID;
1244 if (IsWindow (l.hManager))
1245 MemMgr_AddToList (&Chunk);
1247 l.pHeap->SetAt (iChunk, &Chunk);
1250 l.Stats.cAllocCpp ++;
1251 else // (!Chunk.fCPP)
1252 l.Stats.cAllocDyna ++;
1255 l.Stats.cbAllocCpp += Chunk.cbData;
1256 else // (!Chunk.fCPP)
1257 l.Stats.cbAllocDyna += Chunk.cbData;
1259 l.Stats.cAllocTotal ++;
1260 l.Stats.cbAllocTotal += Chunk.cbData;
1262 LeaveCriticalSection (l.pcs);
1264 if (IsWindow (l.hManager))
1265 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1269 BOOL MemMgr_TrackDestruction (PVOID pData, LPSTR pszFile, DWORD dwLine)
1271 if (MemMgr_Initialize())
1273 EnterCriticalSection (l.pcs);
1275 // Find the memchunk associated with this pData. That's what our
1276 // hash table is for.
1278 size_t iBucket = HASH(pData,l.cBuckets);
1280 PMEMCHUNK pChunk = NULL;
1281 for (size_t iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1283 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1285 if (pChunk->pData == pData)
1287 if ((iChunk = pChunk->iNext) == iINVALID)
1297 memset (&Sim, 0x00, sizeof(MEMCHUNK));
1299 Sim.pszExpr = "(unknown)";
1300 Sim.pszFile = "(unknown)";
1301 MemMgr_ShowWarning (&Sim, pszFile, dwLine, TEXT("An invalid memory address was freed."));
1303 else if (pChunk->dwEndSig && (*(DWORD*)((PBYTE)pData + pChunk->cbData) != pChunk->dwEndSig))
1305 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("The trailing signature on a block of memory was overwritten."));
1307 else if (pChunk->fFreed)
1309 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("A block of memory was freed more than once."));
1314 pChunk->fFreed = TRUE;
1316 if (IsWindow (l.hManager))
1318 if (pChunk->fInList)
1319 MemMgr_RemoveFromList (pChunk);
1323 l.Stats.cAllocCpp --;
1324 else // (!pChunk->fCPP)
1325 l.Stats.cAllocDyna --;
1328 l.Stats.cbAllocCpp -= pChunk->cbData;
1329 else // (!pChunk->fCPP)
1330 l.Stats.cbAllocDyna -= pChunk->cbData;
1332 l.Stats.cAllocTotal --;
1333 l.Stats.cbAllocTotal -= pChunk->cbData;
1337 // Unlink this chunk from the hash table
1339 if (pChunk->iNext != iINVALID)
1342 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1343 pNext->iPrev = pChunk->iPrev;
1345 if (pChunk->iPrev != iINVALID)
1348 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iPrev)) != NULL)
1349 pPrev->iNext = pChunk->iNext;
1351 if (l.aBuckets[iBucket].iFirst == iChunk)
1352 l.aBuckets[iBucket].iFirst = pChunk->iNext;
1354 // Empty this element in the expandarray. That means we need to
1355 // take the last element and shove it in here--so we'll have do
1356 // rework the hash table a little bit more.
1358 if (iChunk != l.cChunks-1)
1361 if ((pMove = (PMEMCHUNK)l.pHeap->GetAt(l.cChunks-1)) != NULL)
1363 size_t iBucket = HASH(pMove->pData,l.cBuckets);
1365 if (pMove->iNext != iINVALID)
1368 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pMove->iNext)) != NULL)
1369 pNext->iPrev = iChunk;
1371 if (pMove->iPrev != iINVALID)
1374 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pMove->iPrev)) != NULL)
1375 pPrev->iNext = iChunk;
1377 if (l.aBuckets[iBucket].iFirst == (l.cChunks-1))
1378 l.aBuckets[iBucket].iFirst = iChunk;
1380 l.pHeap->SetAt (iChunk, pMove);
1381 memset (pMove, 0x00, sizeof(MEMCHUNK));
1387 #endif // TRACK_FREED
1390 LeaveCriticalSection (l.pcs);
1393 if (IsWindow (l.hManager))
1394 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1400 * PUBLIC ROUTINES ____________________________________________________________
1404 void MEMMGR_CALLCONV ShowMemoryManager (void)
1406 if (MemMgr_Initialize())
1408 if (!IsWindow (l.hManager))
1410 MemMgr_RestoreSettings();
1411 l.hManager = MakeWindow (TEXT("Static"), cszTITLE, WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, &lr.rManager, 0, 0);
1412 SetWindowLong (l.hManager, GWL_WNDPROC, (LONG)MemMgr_DlgProc);
1413 PostMessage (l.hManager, WM_COMMAND, IDC_INITIALIZE, 0);
1414 ShowWindow (l.hManager, SW_SHOW);
1420 void MEMMGR_CALLCONV WhileMemoryManagerShowing (void)
1422 if (MemMgr_Initialize())
1424 while (IsWindow (l.hManager))
1427 if (!GetMessage (&msg, NULL, 0, 0))
1430 if (!IsDialogMessage (l.hManager, &msg))
1432 TranslateMessage (&msg);
1433 DispatchMessage (&msg);
1440 BOOL MEMMGR_CALLCONV IsMemoryManagerMessage (MSG *pMsg)
1442 if (IsWindow (l.hManager))
1444 if (pMsg->hwnd == l.hManager)
1446 // if (IsDialogMessage (l.hManager, pMsg))
1450 else if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_F8))
1452 ShowMemoryManager();
1459 PVOID MEMMGR_CALLCONV MemMgr_AllocateMemory (size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1461 PVOID pData = GlobalAlloc (GMEM_FIXED, cb + sizeof(DWORD));
1462 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, TRUE);
1467 void MEMMGR_CALLCONV MemMgr_FreeMemory (PVOID pData, LPSTR pszFile, DWORD dwLine)
1469 if (MemMgr_TrackDestruction (pData, pszFile, dwLine))
1471 GlobalFree ((HGLOBAL)pData);
1476 PVOID MEMMGR_CALLCONV MemMgr_TrackNew (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1478 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, FALSE);
1483 void MEMMGR_CALLCONV MemMgr_TrackDelete (PVOID pData, LPSTR pszFile, DWORD dwLine)
1485 MemMgr_TrackDestruction (pData, pszFile, dwLine);
1490 * EXPANDARRAY ________________________________________________________________
1492 * We'll use an EXPANDARRAY to manage our heap of allocation information.
1493 * Technically I would prefer to use a full HASHLIST here, but I don't want
1494 * this source file to be dependent upon yet another file. So we'll kinda
1495 * write a special-purpose hash system.
1499 #define cEXPANDARRAYHEAPELEMENTS 1024
1500 #define cREALLOC_EXPANDARRAYHEAPS 16
1502 ALLOCEXPANDARRAY::ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap)
1504 if ((m_cbElement = cbElement) == 0)
1505 m_cbElement = sizeof(DWORD);
1506 if ((m_cElementsPerHeap = cElementsPerHeap) == 0)
1507 m_cElementsPerHeap = cEXPANDARRAYHEAPELEMENTS;
1513 ALLOCEXPANDARRAY::~ALLOCEXPANDARRAY (void)
1517 for (size_t ii = 0; ii < m_cHeaps; ++ii)
1518 GlobalFree ((HGLOBAL)(m_aHeaps[ ii ]));
1519 GlobalFree ((HGLOBAL)m_aHeaps);
1523 PVOID ALLOCEXPANDARRAY::GetAt (size_t iElement)
1525 size_t iHeap = iElement / m_cElementsPerHeap;
1526 size_t iIndex = iElement % m_cElementsPerHeap;
1527 if ((iHeap >= m_cHeaps) || (!m_aHeaps[iHeap]))
1529 return (PVOID)&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ];
1532 void ALLOCEXPANDARRAY::SetAt (size_t iElement, PVOID pData)
1534 size_t iHeap = iElement / m_cElementsPerHeap;
1535 size_t iIndex = iElement % m_cElementsPerHeap;
1537 if (!REALLOC (m_aHeaps, m_cHeaps, 1+iHeap, cREALLOC_EXPANDARRAYHEAPS))
1540 if (!m_aHeaps[ iHeap ])
1542 size_t cbHeap = sizeof(EXPANDARRAYHEAP) + (m_cElementsPerHeap * m_cbElement);
1543 if ((m_aHeaps[ iHeap ] = (LPEXPANDARRAYHEAP)GlobalAlloc (GMEM_FIXED, cbHeap)) == NULL)
1545 memset (m_aHeaps[ iHeap ], 0x00, cbHeap);
1546 m_aHeaps[ iHeap ]->aElements = ((PBYTE)m_aHeaps[ iHeap ]) + sizeof(EXPANDARRAYHEAP);
1550 memset (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], 0x00, m_cbElement);
1552 memcpy (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], pData, m_cbElement);