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>
23 * PARAMETERS _________________________________________________________________
27 #define cDEFAULT_BUCKETS 128
29 #define dwSIG_AT_END 'Okay'
31 #define iINVALID ((size_t)-1)
33 #define MIN_BUCKETS(_cObjects) ((_cObjects) / 23)
34 #define TARGET_BUCKETS(_cObjects) ((_cObjects) / 5)
38 #define cmsecREFRESH 1000
42 * DEFINITIONS ________________________________________________________________
48 PVOID aElements; // = EXPANDARRAYHEAP.aElements + 4;
49 // Followed by allocated space for aElements
50 } EXPANDARRAYHEAP, *LPEXPANDARRAYHEAP;
52 class ALLOCEXPANDARRAY
55 ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap = 0);
56 ~ALLOCEXPANDARRAY (void);
58 PVOID GetAt (size_t iElement);
59 void SetAt (size_t iElement, PVOID pData);
63 size_t m_cElementsPerHeap;
66 LPEXPANDARRAYHEAP *m_aHeaps;
84 } MEMCHUNK, *PMEMCHUNK;
96 size_t cAllocCppTared;
97 size_t cAllocDynaTared;
98 size_t cAllocTotalTared;
102 size_t cbAllocCppTared;
103 size_t cbAllocDynaTared;
104 size_t cbAllocTotalTared;
109 CRITICAL_SECTION *pcs;
113 ALLOCEXPANDARRAY *pHeap;
130 #define HASH(_dw,_cTable) (((DWORD)(_dw) >> 4) % (_cTable))
134 * REALLOC ____________________________________________________________________
139 #define REALLOC(_a,_c,_r,_i) Alloc_ReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
140 BOOL Alloc_ReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
145 if (cReq <= *pcTarget)
148 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
151 if ((pNew = (LPVOID)GlobalAlloc (GMEM_FIXED, cbElement * cNew)) == NULL)
153 memset (pNew, 0x00, cbElement * cNew);
156 memset (pNew, 0x00, cbElement * cNew);
159 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
160 memset (&((char*)pNew)[ cbElement * (*pcTarget) ], 0x00, cbElement * (cNew - *pcTarget));
161 GlobalFree ((HGLOBAL)*ppTarget);
172 * USER INTERFACE ROUTINES ____________________________________________________
176 #define IDC_INITIALIZE 100
177 #define IDC_BOX_ALLOC 101
178 #define IDC_LABEL_CPP 102
179 #define IDC_LABEL_OTHER 103
180 #define IDC_LABEL_TARED 104
181 #define IDC_LABEL_TOTAL 106
182 #define IDC_LABEL_COUNT 107
183 #define IDC_LABEL_SIZE 108
184 #define IDC_LABEL_AVERAGE 109
185 #define IDC_VALUE_CPP_COUNT 110
186 #define IDC_VALUE_OTHER_COUNT 111
187 #define IDC_VALUE_TARED_COUNT 112
188 #define IDC_VALUE_TOTAL_COUNT 113
189 #define IDC_VALUE_CPP_SIZE 114
190 #define IDC_VALUE_OTHER_SIZE 115
191 #define IDC_VALUE_TARED_SIZE 116
192 #define IDC_VALUE_TOTAL_SIZE 117
193 #define IDC_VALUE_CPP_AVERAGE 118
194 #define IDC_VALUE_OTHER_AVERAGE 119
195 #define IDC_VALUE_TARED_AVERAGE 120
196 #define IDC_VALUE_TOTAL_AVERAGE 121
197 #define IDC_BOX_DETAILS 122
199 #define IDC_LABEL 124
202 #define IDC_RESET 127
203 #define IDC_REFRESH 128
204 #define IDC_LIST_ADD 129
205 #define IDC_LIST_REMOVE 130
206 #define IDC_LIST_REMOVEADD 131
208 #define cszTITLE TEXT("Memory Manager")
221 RECT rValueOtherCount;
222 RECT rValueTaredCount;
223 RECT rValueTotalCount;
225 RECT rValueOtherSize;
226 RECT rValueTaredSize;
227 RECT rValueTotalSize;
228 RECT rValueCppAverage;
229 RECT rValueOtherAverage;
230 RECT rValueTaredAverage;
231 RECT rValueTotalAverage;
251 HWND MakeWindow (LPCTSTR pszClass, LPCTSTR pszTitle, DWORD dwStyle, RECT *prSource,
252 HWND hParent, UINT idc, DWORD dwStyleEx = 0)
254 RECT rr = { 0, 0, 16, 16 };
257 HWND hWnd = CreateWindowEx (dwStyleEx, pszClass, pszTitle, dwStyle,
258 rr.left, rr.top, rr.right - rr.left, rr.bottom - rr.top,
259 hParent, (HMENU)UIntToPtr(idc), GetModuleHandle(0), 0);
261 SendMessage (hWnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 1);
265 void SetWindowRect (HWND hWnd, RECT *pr)
267 SetWindowPos (hWnd, 0, pr->left, pr->top, pr->right - pr->left,
268 pr->bottom - pr->top, SWP_NOZORDER | SWP_NOACTIVATE);
271 void FormatBytes (LPTSTR pszText, double lfValue)
276 *pszText++ = TEXT('-');
279 if (lfValue >= 1048576)
281 LONG Value = (LONG)(lfValue / 1048576);
282 lfValue -= Value * 1048576;
283 LONG Frac = (LONG)(lfValue * 100 / 1048576);
284 wsprintf (pszText, TEXT("%ld.%ld MB"), Value, Frac);
286 else if (lfValue >= 3072)
288 LONG Value = (LONG)(lfValue / 1024);
289 lfValue -= Value * 1024;
290 LONG Frac = (LONG)(lfValue * 100 / 1024);
291 wsprintf (pszText, TEXT("%ld.%ld kb"), Value, Frac);
293 else // (lfValue < 3072)
295 wsprintf (pszText, TEXT("%ld b"), (LONG)lfValue);
299 void FormatTime (LPTSTR pszText, DWORD dwTick)
301 static FILETIME ftTickZero = { 0, 0 };
302 if (!ftTickZero.dwHighDateTime && !ftTickZero.dwLowDateTime)
304 // We need to find out what FILETIME corresponds with a tick
305 // count of zero. To do that, first find the FILETIME and tick
306 // count that represent *now* (in local time).
309 GetLocalTime (&stNow);
310 SystemTimeToFileTime (&stNow, &ftTickZero);
312 DWORD dwTickNow = GetTickCount();
314 // A FILETIME is a count-of-100ns-intervals, and a tick count is
315 // a count of 1ms-intervals. So we need to subtract off a big
316 // number times our tick count.
318 if ((dwTickNow * 10000) < (dwTickNow))
319 ftTickZero.dwHighDateTime --;
320 dwTickNow *= 10000; // convert to 100ns intervals
321 if (dwTickNow > ftTickZero.dwLowDateTime)
322 ftTickZero.dwHighDateTime --;
323 ftTickZero.dwLowDateTime -= dwTickNow; // unsigned, so it'll wrap OK
326 // Convert the given tick count into 100ns intervals, and add it
327 // to our ftTickZero.
329 FILETIME ftTick = ftTickZero;
331 if ((dwTick * 10000) < (dwTick))
332 ftTick.dwHighDateTime ++;
333 dwTick *= 10000; // convert to 100ns intervals
334 if (dwTick > (DWORD)(0-ftTick.dwLowDateTime)) // too big to add?
335 ftTick.dwHighDateTime ++;
336 ftTick.dwLowDateTime += dwTick; // unsigned, so it'll wrap OK
338 // Convert to a SYSTEMTIME, and output the time component
341 FileTimeToSystemTime (&ftTick, &stTick);
343 wsprintf (pszText, TEXT("%ld:%02ld:%02ld.%02ld"),
345 (DWORD)stTick.wMinute,
346 (DWORD)stTick.wSecond,
347 (DWORD)(stTick.wMilliseconds / 100));
350 void SetDlgItemBytes (HWND hDlg, int idc, double lfValue)
353 FormatBytes (szText, lfValue);
354 SetDlgItemText (hDlg, idc, szText);
358 void MemMgr_ShowWarning (PMEMCHUNK pChunk, LPTSTR pszFile, DWORD dwLine, LPTSTR pszDesc)
360 TCHAR szMessage[ 1024 ];
361 wsprintf (szMessage, TEXT("%s\n\n Address: 0x%08p (%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);
362 if (MessageBox (NULL, szMessage, cszTITLE, MB_ICONHAND | MB_OKCANCEL | MB_DEFBUTTON2) == IDOK)
364 // TODO: Show Details
368 void MIX (RECT *pr, RECT *pr1, RECT *pr2)
370 pr->left = pr2->left;
372 pr->right = pr2->right;
373 pr->bottom = pr1->bottom;
376 void MemMgr_GetWindowSizes (WINDOWSIZES *pSizes)
379 GetClientRect (l.hManager, &rClient);
380 InflateRect (&rClient, 0-cBORDER, 0-cBORDER);
382 pSizes->rLabelAverage.right = rClient.right -cxBETWEEN*2;
383 pSizes->rLabelAverage.top = rClient.top +8 +cyBETWEEN;
384 pSizes->rLabelAverage.left = pSizes->rLabelAverage.right -cxVALUES;
385 pSizes->rLabelAverage.bottom = pSizes->rLabelAverage.top +cyLABELS;
387 pSizes->rLabelSize = pSizes->rLabelAverage;
388 pSizes->rLabelSize.left -= cxBETWEEN + cxVALUES;
389 pSizes->rLabelSize.right -= cxBETWEEN + cxVALUES;
391 pSizes->rLabelCount = pSizes->rLabelSize;
392 pSizes->rLabelCount.left -= cxBETWEEN + cxVALUES;
393 pSizes->rLabelCount.right -= cxBETWEEN + cxVALUES;
395 pSizes->rLabelCpp.left = rClient.left +cxBETWEEN;
396 pSizes->rLabelCpp.top = pSizes->rLabelCount.bottom +cyBETWEEN;
397 pSizes->rLabelCpp.right = pSizes->rLabelCpp.left +cxLABELS;
398 pSizes->rLabelCpp.bottom = pSizes->rLabelCpp.top +cyLABELS;
400 pSizes->rLabelOther = pSizes->rLabelCpp;
401 pSizes->rLabelOther.top += cyBETWEEN + cyLABELS;
402 pSizes->rLabelOther.bottom += cyBETWEEN + cyLABELS;
404 pSizes->rLabelTotal = pSizes->rLabelOther;
405 pSizes->rLabelTotal.top += cyBETWEEN + cyLABELS;
406 pSizes->rLabelTotal.bottom += cyBETWEEN + cyLABELS;
408 pSizes->rLabelTared = pSizes->rLabelTotal;
409 pSizes->rLabelTared.top += cyBETWEEN + cyLABELS;
410 pSizes->rLabelTared.bottom += cyBETWEEN + cyLABELS;
412 pSizes->rBoxAlloc = rClient;
413 pSizes->rBoxAlloc.bottom = pSizes->rLabelTared.bottom +cyBETWEEN;
415 MIX (&pSizes->rValueCppCount, &pSizes->rLabelCpp, &pSizes->rLabelCount);
416 MIX (&pSizes->rValueOtherCount, &pSizes->rLabelOther, &pSizes->rLabelCount);
417 MIX (&pSizes->rValueTaredCount, &pSizes->rLabelTared, &pSizes->rLabelCount);
418 MIX (&pSizes->rValueTotalCount, &pSizes->rLabelTotal, &pSizes->rLabelCount);
420 MIX (&pSizes->rValueCppSize, &pSizes->rLabelCpp, &pSizes->rLabelSize);
421 MIX (&pSizes->rValueOtherSize, &pSizes->rLabelOther, &pSizes->rLabelSize);
422 MIX (&pSizes->rValueTaredSize, &pSizes->rLabelTared, &pSizes->rLabelSize);
423 MIX (&pSizes->rValueTotalSize, &pSizes->rLabelTotal, &pSizes->rLabelSize);
425 MIX (&pSizes->rValueCppAverage, &pSizes->rLabelCpp, &pSizes->rLabelAverage);
426 MIX (&pSizes->rValueOtherAverage, &pSizes->rLabelOther, &pSizes->rLabelAverage);
427 MIX (&pSizes->rValueTaredAverage, &pSizes->rLabelTared, &pSizes->rLabelAverage);
428 MIX (&pSizes->rValueTotalAverage, &pSizes->rLabelTotal, &pSizes->rLabelAverage);
430 pSizes->rBoxDetails = rClient;
431 pSizes->rBoxDetails.top = pSizes->rBoxAlloc.bottom +cyBETWEEN;
432 pSizes->rBoxDetails.bottom -= cyBUTTONS +cyBETWEEN;
434 pSizes->rList = pSizes->rBoxDetails;
435 pSizes->rList.top += 8;
436 InflateRect (&pSizes->rList, 0-cBORDER, 0-cBORDER);
438 pSizes->rClose = rClient;
439 pSizes->rClose.top = pSizes->rClose.bottom - cyBUTTONS;
440 pSizes->rClose.left = pSizes->rClose.right - cxBUTTONS;
442 pSizes->rReset = pSizes->rClose;
443 pSizes->rReset.right = pSizes->rClose.left - cxBETWEEN;
444 pSizes->rReset.left = pSizes->rReset.right - cxBUTTONS;
446 pSizes->rTare = pSizes->rClose;
447 pSizes->rTare.right = pSizes->rReset.left - cxBETWEEN;
448 pSizes->rTare.left = pSizes->rTare.right - cxBUTTONS;
450 pSizes->rLabel = pSizes->rTare;
451 pSizes->rLabel.right = pSizes->rTare.left - cxBETWEEN;
452 pSizes->rLabel.left = pSizes->rLabel.right - cxBUTTONS;
454 pSizes->rHide = pSizes->rLabel;
455 pSizes->rHide.right = pSizes->rLabel.left - cxBETWEEN;
456 pSizes->rHide.left = pSizes->rHide.right - cxBUTTONS;
459 void MemMgr_OnSize (void)
462 MemMgr_GetWindowSizes (&Sizes);
463 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_ALLOC), &Sizes.rBoxAlloc);
464 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_CPP), &Sizes.rLabelCpp);
465 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_OTHER), &Sizes.rLabelOther);
466 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TARED), &Sizes.rLabelTared);
467 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TOTAL), &Sizes.rLabelTotal);
468 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_COUNT), &Sizes.rLabelCount);
469 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_SIZE), &Sizes.rLabelSize);
470 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_AVERAGE), &Sizes.rLabelAverage);
471 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_COUNT), &Sizes.rValueCppCount);
472 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_COUNT), &Sizes.rValueOtherCount);
473 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_COUNT), &Sizes.rValueTaredCount);
474 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_COUNT), &Sizes.rValueTotalCount);
475 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_SIZE), &Sizes.rValueCppSize);
476 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_SIZE), &Sizes.rValueOtherSize);
477 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_SIZE), &Sizes.rValueTaredSize);
478 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_SIZE), &Sizes.rValueTotalSize);
479 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_AVERAGE), &Sizes.rValueCppAverage);
480 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_AVERAGE), &Sizes.rValueOtherAverage);
481 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_AVERAGE), &Sizes.rValueTaredAverage);
482 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_AVERAGE), &Sizes.rValueTotalAverage);
483 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_DETAILS), &Sizes.rBoxDetails);
484 SetWindowRect (GetDlgItem (l.hManager, IDC_LIST), &Sizes.rList);
485 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL), &Sizes.rLabel);
486 SetWindowRect (GetDlgItem (l.hManager, IDC_HIDE), &Sizes.rHide);
487 SetWindowRect (GetDlgItem (l.hManager, IDC_TARE), &Sizes.rTare);
488 SetWindowRect (GetDlgItem (l.hManager, IDC_RESET), &Sizes.rReset);
489 SetWindowRect (GetDlgItem (l.hManager, IDCANCEL), &Sizes.rClose);
493 void MemMgr_OnListRemove (PVOID pData)
495 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
498 Find.flags = LVFI_PARAM;
499 Find.lParam = (LPARAM)pData;
502 if ((iItem = ListView_FindItem (hList, 0, &Find)) == -1)
504 // The listview's find feature sucks; I've seen with my own little
505 // eyes that it may miss an item if it's the only one in a list.
506 // Look for ourselves.
508 int cItems = ListView_GetItemCount(hList);
509 for (iItem = 0; iItem < cItems; ++iItem)
513 Item.mask = LVIF_PARAM;
514 ListView_GetItem (hList, &Item);
515 if (Item.lParam == (LPARAM)pData)
522 ListView_DeleteItem (hList, iItem);
527 void MemMgr_RemoveFromList (PMEMCHUNK pChunk)
529 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVE, (LPARAM)(pChunk->pData));
530 pChunk->fInList = FALSE;
534 LPTSTR MemMgr_GetItemKey (HWND hList, int iItem)
536 static TCHAR szText[ 256 ];
537 LPTSTR pszReturn = NULL;
546 Item.mask = LVIF_PARAM;
547 ListView_GetItem (hList, &Item);
549 EnterCriticalSection (l.pcs);
552 iBucket = HASH(Item.lParam,l.cBuckets);
558 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
560 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
562 if (pChunk->pData == (PVOID)Item.lParam)
564 if ((iChunk = pChunk->iNext) == iINVALID)
573 if (lr.iColSort == 0)
574 pszReturn = (LPTSTR)UlongToPtr(pChunk->dwTick);
575 else if (lr.iColSort == 4)
576 pszReturn = (LPTSTR)pChunk->cbData;
577 else // (lr.iColSort == 5)
578 pszReturn = (LPTSTR)pChunk->pData;
581 LeaveCriticalSection (l.pcs);
585 ListView_GetItemText (hList, iItem, lr.iColSort, szText, 256);
594 int MemMgr_CompareItems (LPTSTR pszKey1, LPTSTR pszKey2)
603 dw = (int)( pszKey1 - pszKey2 );
607 dw = lstrcmpi (pszKey1, pszKey2);
611 return (lr.fSortRev) ? (0-dw) : dw;
615 int MemMgr_PickListInsertionPoint (HWND hList, LPTSTR pszKey)
618 int iItemHigh = ListView_GetItemCount (hList) -1;
620 while (iItemLow <= iItemHigh)
622 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
624 LPTSTR pszAlternate = MemMgr_GetItemKey (hList, iItemTest);
626 int iCompare = MemMgr_CompareItems (pszKey, pszAlternate);
629 if ((iItemHigh = iItemTest-1) < iItemLow)
634 if ((iItemLow = iItemTest+1) > iItemHigh)
643 void MemMgr_OnListAdd (PMEMCHUNK pCopy)
645 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
648 FormatTime (szTime, pCopy->dwTick);
651 LPTSTR pszFlags = szFlags;
652 *pszFlags++ = (pCopy->fCPP) ? TEXT('C') : TEXT(' ');
653 *pszFlags++ = TEXT(' ');
654 *pszFlags++ = (pCopy->fFreed) ? TEXT('F') : TEXT(' ');
658 lstrcpy (szExpr, (pCopy->pszExpr) ? pCopy->pszExpr : TEXT("unknown"));
660 LPTSTR pszFile = pCopy->pszFile;
661 for (LPTSTR psz = pCopy->pszFile; *psz; ++psz)
663 if ((*psz == TEXT(':')) || (*psz == TEXT('\\')))
666 TCHAR szLocation[256];
667 if (!pszFile || !pCopy->dwLine)
668 lstrcpy (szLocation, TEXT("unknown"));
670 wsprintf (szLocation, TEXT("%s, %ld"), pszFile, pCopy->dwLine);
673 FormatBytes (szBytes, (double)pCopy->cbData);
675 TCHAR szAddress[256];
676 wsprintf (szAddress, TEXT("0x%08p"), pCopy->pData);
678 LPTSTR pszKey = NULL;
681 case 0: pszKey = (LPTSTR)UlongToPtr(pCopy->dwTick); break;
682 case 1: pszKey = (LPTSTR)szFlags; break;
683 case 2: pszKey = (LPTSTR)szExpr; break;
684 case 3: pszKey = (LPTSTR)szLocation; break;
685 case 4: pszKey = (LPTSTR)pCopy->cbData; break;
686 case 5: pszKey = (LPTSTR)pCopy->pData; break;
690 memset (&Item, 0x00, sizeof(Item));
691 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
692 Item.iItem = MemMgr_PickListInsertionPoint (hList, pszKey);
694 Item.cchTextMax = 256;
695 Item.lParam = (LPARAM)pCopy->pData;
697 Item.pszText = szTime;
698 DWORD iItem = ListView_InsertItem (hList, &Item);
699 ListView_SetItemText (hList, iItem, 1, szFlags);
700 ListView_SetItemText (hList, iItem, 2, szExpr);
701 ListView_SetItemText (hList, iItem, 3, szLocation);
702 ListView_SetItemText (hList, iItem, 4, szBytes);
703 ListView_SetItemText (hList, iItem, 5, szAddress);
709 void MemMgr_AddToList (PMEMCHUNK pChunk)
711 PMEMCHUNK pCopy = new MEMCHUNK;
712 memcpy (pCopy, pChunk, sizeof(MEMCHUNK));
715 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVEADD, (LPARAM)pCopy);
717 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_ADD, (LPARAM)pCopy);
718 pChunk->fInList = TRUE;
722 void MemMgr_RestoreSettings (void)
724 lr.rManager.left = 0;
726 lr.rManager.right = 510;
727 lr.rManager.bottom = 440;
728 lr.acxColumns[0] = 70;
729 lr.acxColumns[1] = 40;
730 lr.acxColumns[2] = 100;
731 lr.acxColumns[3] = 110;
732 lr.acxColumns[4] = 50;
733 lr.acxColumns[5] = 80;
738 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
740 DWORD dwType = REG_BINARY;
741 DWORD dwSize = sizeof(lr);
742 RegQueryValueEx (hk, TEXT("Settings"), 0, &dwType, (PBYTE)&lr, &dwSize);
747 void MemMgr_StoreSettings (void)
749 if (IsWindow (l.hManager))
751 GetWindowRect (l.hManager, &lr.rManager);
753 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
754 if (IsWindow (hList))
756 for (size_t ii = 0; ii < 6; ++ii)
757 lr.acxColumns[ ii ] = ListView_GetColumnWidth (hList, ii);
762 if (RegCreateKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
764 RegSetValueEx (hk, TEXT("Settings"), 0, REG_BINARY, (PBYTE)&lr, sizeof(lr));
769 void MemMgr_OnInit (void)
771 DWORD dwFlags = WS_CHILD | WS_TABSTOP | WS_VISIBLE;
772 MakeWindow (TEXT("Button"), TEXT("Allocation Statistics"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_ALLOC);
773 MakeWindow (TEXT("Static"), TEXT("C++ Objects:"), dwFlags, NULL, l.hManager, IDC_LABEL_CPP);
774 MakeWindow (TEXT("Static"), TEXT("Dynamic:"), dwFlags, NULL, l.hManager, IDC_LABEL_OTHER);
775 MakeWindow (TEXT("Static"), TEXT("Combined:"), dwFlags, NULL, l.hManager, IDC_LABEL_TOTAL);
776 MakeWindow (TEXT("Static"), TEXT("Tared:"), dwFlags, NULL, l.hManager, IDC_LABEL_TARED);
777 MakeWindow (TEXT("Static"), TEXT("Count"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_COUNT);
778 MakeWindow (TEXT("Static"), TEXT("Size"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_SIZE);
779 MakeWindow (TEXT("Static"), TEXT("Average"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_AVERAGE);
780 MakeWindow (TEXT("Static"), TEXT("0"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_COUNT);
781 MakeWindow (TEXT("Static"), TEXT("1"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_COUNT);
782 MakeWindow (TEXT("Static"), TEXT("2"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_COUNT);
783 MakeWindow (TEXT("Static"), TEXT("3"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_COUNT);
784 MakeWindow (TEXT("Static"), TEXT("4"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_SIZE);
785 MakeWindow (TEXT("Static"), TEXT("5"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_SIZE);
786 MakeWindow (TEXT("Static"), TEXT("6"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_SIZE);
787 MakeWindow (TEXT("Static"), TEXT("7"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_SIZE);
788 MakeWindow (TEXT("Static"), TEXT("8"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_AVERAGE);
789 MakeWindow (TEXT("Static"), TEXT("9"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_AVERAGE);
790 MakeWindow (TEXT("Static"), TEXT("10"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_AVERAGE);
791 MakeWindow (TEXT("Static"), TEXT("11"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_AVERAGE);
792 MakeWindow (TEXT("Button"), TEXT("Details"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_DETAILS);
793 MakeWindow (WC_LISTVIEW, TEXT(""), dwFlags | LVS_REPORT | LVS_SINGLESEL, NULL, l.hManager, IDC_LIST, WS_EX_CLIENTEDGE);
794 // MakeWindow (TEXT("Button"), TEXT("Label"), dwFlags, NULL, l.hManager, IDC_LABEL);
795 // MakeWindow (TEXT("Button"), TEXT("Hidden"), dwFlags, NULL, l.hManager, IDC_HIDE);
796 MakeWindow (TEXT("Button"), TEXT("Tare"), dwFlags, NULL, l.hManager, IDC_TARE);
797 MakeWindow (TEXT("Button"), TEXT("Restore"), dwFlags, NULL, l.hManager, IDC_RESET);
798 MakeWindow (TEXT("Button"), TEXT("Close"), dwFlags, NULL, l.hManager, IDCANCEL);
801 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
804 Col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM;
805 Col.fmt = LVCFMT_LEFT;
807 Col.cx = lr.acxColumns[0];
808 Col.pszText = TEXT("Time");
809 ListView_InsertColumn (hList, Col.iSubItem, &Col);
811 Col.cx = lr.acxColumns[1];
812 Col.pszText = TEXT("Flags");
814 ListView_InsertColumn (hList, Col.iSubItem, &Col);
816 Col.cx = lr.acxColumns[2];
817 Col.pszText = TEXT("Expression");
819 ListView_InsertColumn (hList, Col.iSubItem, &Col);
821 Col.cx = lr.acxColumns[3];
822 Col.pszText = TEXT("Location");
824 ListView_InsertColumn (hList, Col.iSubItem, &Col);
826 Col.fmt = LVCFMT_RIGHT;
827 Col.cx = lr.acxColumns[4];
828 Col.pszText = TEXT("Size");
830 ListView_InsertColumn (hList, Col.iSubItem, &Col);
832 Col.cx = lr.acxColumns[5];
833 Col.pszText = TEXT("Address");
835 ListView_InsertColumn (hList, Col.iSubItem, &Col);
837 EnterCriticalSection (l.pcs);
838 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
840 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
843 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
846 pChunk->fInList = FALSE;
847 if (!pChunk->fTared && !pChunk->fFreed)
848 MemMgr_AddToList (pChunk);
851 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
852 LeaveCriticalSection (l.pcs);
854 l.idTimer = SetTimer (l.hManager, 0, cmsecREFRESH, NULL);
857 void MemMgr_OnRefresh (void)
859 // Fill in the statistics at the top of the manager dialog
861 SetDlgItemInt (l.hManager, IDC_VALUE_CPP_COUNT, (INT)l.Stats.cAllocCpp, TRUE);
862 SetDlgItemInt (l.hManager, IDC_VALUE_OTHER_COUNT, (INT)l.Stats.cAllocDyna, TRUE);
863 SetDlgItemInt (l.hManager, IDC_VALUE_TARED_COUNT, (INT)l.Stats.cAllocTotalTared, TRUE);
864 SetDlgItemInt (l.hManager, IDC_VALUE_TOTAL_COUNT, (INT)l.Stats.cAllocTotal, TRUE);
866 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_SIZE, (double)l.Stats.cbAllocCpp);
867 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_SIZE, (double)l.Stats.cbAllocDyna);
868 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_SIZE, (double)l.Stats.cbAllocTotalTared);
869 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_SIZE, (double)l.Stats.cbAllocTotal);
871 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_AVERAGE, (l.Stats.cAllocCpp) ? ((double)l.Stats.cbAllocCpp / l.Stats.cAllocCpp) : 0);
872 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_AVERAGE, (l.Stats.cAllocDyna) ? ((double)l.Stats.cbAllocDyna / l.Stats.cAllocDyna) : 0);
873 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_AVERAGE, (l.Stats.cAllocTotalTared) ? ((double)l.Stats.cbAllocTotalTared / l.Stats.cAllocTotalTared) : 0);
874 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_AVERAGE, (l.Stats.cAllocTotal) ? ((double)l.Stats.cbAllocTotal / l.Stats.cAllocTotal) : 0);
877 void MemMgr_OnLabel (void)
882 void MemMgr_OnHide (void)
887 void MemMgr_OnReset (void)
889 l.Stats.cAllocCpp += l.Stats.cAllocCppTared;
890 l.Stats.cAllocDyna += l.Stats.cAllocDynaTared;
891 l.Stats.cAllocTotal += l.Stats.cAllocTotalTared;
892 l.Stats.cbAllocCpp += l.Stats.cbAllocCppTared;
893 l.Stats.cbAllocDyna += l.Stats.cbAllocDynaTared;
894 l.Stats.cbAllocTotal += l.Stats.cbAllocTotalTared;
896 l.Stats.cAllocCppTared = 0;
897 l.Stats.cAllocDynaTared = 0;
898 l.Stats.cAllocTotalTared = 0;
899 l.Stats.cbAllocCppTared = 0;
900 l.Stats.cbAllocDynaTared = 0;
901 l.Stats.cbAllocTotalTared = 0;
903 EnterCriticalSection (l.pcs);
904 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
906 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
908 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
911 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
914 pChunk->fInList = FALSE;
915 pChunk->fTared = FALSE;
917 MemMgr_AddToList (pChunk);
920 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
921 LeaveCriticalSection (l.pcs);
926 void MemMgr_OnTare (void)
928 l.Stats.cAllocCppTared += l.Stats.cAllocCpp;
929 l.Stats.cAllocDynaTared += l.Stats.cAllocDyna;
930 l.Stats.cAllocTotalTared += l.Stats.cAllocTotal;
931 l.Stats.cbAllocCppTared += l.Stats.cbAllocCpp;
932 l.Stats.cbAllocDynaTared += l.Stats.cbAllocDyna;
933 l.Stats.cbAllocTotalTared += l.Stats.cbAllocTotal;
935 l.Stats.cAllocCpp = 0;
936 l.Stats.cAllocDyna = 0;
937 l.Stats.cAllocTotal = 0;
938 l.Stats.cbAllocCpp = 0;
939 l.Stats.cbAllocDyna = 0;
940 l.Stats.cbAllocTotal = 0;
942 EnterCriticalSection (l.pcs);
943 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
945 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
947 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
950 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
953 pChunk->fInList = FALSE;
954 pChunk->fTared = TRUE;
957 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
958 LeaveCriticalSection (l.pcs);
964 void MemMgr_OnSort (void)
966 EnterCriticalSection (l.pcs);
967 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
969 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
971 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
974 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
977 pChunk->fInList = FALSE;
978 if (!pChunk->fTared && !pChunk->fFreed)
979 MemMgr_AddToList (pChunk);
982 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
983 LeaveCriticalSection (l.pcs);
987 void MemMgr_OnPaint (void)
990 HDC hdc = BeginPaint (l.hManager, &ps);
992 static HBRUSH hbr = (HBRUSH)CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
993 FillRect (hdc, &ps.rcPaint, hbr);
995 EndPaint (l.hManager, &ps);
999 void MemMgr_OnTimer (void)
1001 if (GetWindowLongPtr (l.hManager, GWLP_USERDATA))
1003 SetWindowLongPtr (l.hManager, GWLP_USERDATA, 0);
1009 void MemMgr_OnDelayedRefresh (void)
1011 SetWindowLongPtr (l.hManager, GWLP_USERDATA, 1);
1015 BOOL CALLBACK MemMgr_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1020 MemMgr_StoreSettings();
1022 KillTimer (hDlg, l.idTimer);
1023 l.idTimer = (UINT_PTR)-1;
1028 MemMgr_StoreSettings();
1032 MemMgr_StoreSettings();
1035 case WM_GETMINMAXINFO:
1037 lpmmi = (LPMINMAXINFO)lp;
1038 lpmmi->ptMinTrackSize.x = cxBUTTONS*5 + cxBETWEEN*4 + cBORDER*2 + 8;
1039 lpmmi->ptMinTrackSize.y = 270;
1047 switch (((NMHDR *)lp)->code)
1049 case LVN_COLUMNCLICK:
1050 if (((NM_LISTVIEW*)lp)->iSubItem == lr.iColSort)
1051 lr.fSortRev = !lr.fSortRev;
1054 lr.iColSort = ((NM_LISTVIEW*)lp)->iSubItem;
1055 lr.fSortRev = FALSE;
1058 MemMgr_StoreSettings();
1071 DestroyWindow (hDlg);
1074 case IDC_INITIALIZE:
1080 MemMgr_OnDelayedRefresh();
1099 case IDC_LIST_REMOVEADD:
1100 MemMgr_OnListRemove (((PMEMCHUNK)lp)->pData);
1101 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1105 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1108 case IDC_LIST_REMOVE:
1109 MemMgr_OnListRemove ((PVOID)lp);
1115 return (BOOL) DefWindowProc (hDlg, msg, wp, lp);
1120 * MANAGEMENT ROUTINES ________________________________________________________
1124 BOOL MemMgr_Initialize (void)
1128 l.pcs = new CRITICAL_SECTION;
1129 InitializeCriticalSection (l.pcs);
1131 l.pHeap = new ALLOCEXPANDARRAY (sizeof(MEMCHUNK));
1133 REALLOC (l.aBuckets, l.cBuckets, cDEFAULT_BUCKETS, 1);
1136 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1137 l.aBuckets[ii].iFirst = iINVALID;
1141 return (l.pHeap) && (l.aBuckets);
1145 void MemMgr_TrackAllocation (PVOID pData, size_t cb, LPTSTR pszExpr, LPTSTR pszFile, DWORD dwLine, BOOL fSig)
1149 if (!MemMgr_Initialize())
1152 EnterCriticalSection (l.pcs);
1154 // Ensure our hash table will be large enough to handle the new
1155 // MEMCHUNK we're about to assign.
1157 if (l.cBuckets < MIN_BUCKETS(l.cChunks+1))
1159 // Too small! Rebuild the hash table.
1161 REALLOC (l.aBuckets, l.cBuckets, TARGET_BUCKETS(l.cChunks+1), 1);
1164 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1165 l.aBuckets[ii].iFirst = iINVALID;
1167 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
1170 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1173 size_t iBucket = HASH(PtrToUlong(pChunk->pData),l.cBuckets);
1174 if ((pChunk->iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1177 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1178 pNext->iPrev = iChunk;
1180 l.aBuckets[iBucket].iFirst = iChunk;
1181 pChunk->iPrev = iINVALID;
1186 // If space was allocated for a trailing signature, write one
1189 *(DWORD *)( (PBYTE)pData + cb ) = dwSIG_AT_END;
1191 // Prepare a MEMCHUNK entry and shove it in our array
1193 size_t iChunk = l.cChunks;
1194 size_t iBucket = HASH(PtrToUlong(pData),l.cBuckets);
1195 BOOL fLinkIn = TRUE;
1198 Chunk.pData = pData;
1199 Chunk.fFreed = FALSE;
1201 Chunk.pszExpr = pszExpr;
1202 Chunk.pszFile = pszFile;
1204 Chunk.dwLine = dwLine;
1205 Chunk.dwTick = GetTickCount();
1206 Chunk.dwEndSig = (fSig) ? dwSIG_AT_END : 0;
1207 Chunk.fInList = FALSE;
1208 Chunk.fTared = FALSE;
1211 // Find the memchunk associated with this pData. That's what our
1212 // hash table is for.
1214 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1217 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) != NULL)
1219 if (pChunk->pData == pData)
1221 Chunk.iNext = pChunk->iNext;
1222 Chunk.iPrev = pChunk->iPrev;
1227 iChunk = (pChunk) ? pChunk->iNext : iINVALID;
1229 if (iChunk == iINVALID)
1233 l.cChunks = max (l.cChunks, 1+iChunk);
1237 if ((Chunk.iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1240 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(Chunk.iNext)) != NULL)
1241 pNext->iPrev = iChunk;
1243 l.aBuckets[iBucket].iFirst = iChunk;
1244 Chunk.iPrev = iINVALID;
1247 if (IsWindow (l.hManager))
1248 MemMgr_AddToList (&Chunk);
1250 l.pHeap->SetAt (iChunk, &Chunk);
1253 l.Stats.cAllocCpp ++;
1254 else // (!Chunk.fCPP)
1255 l.Stats.cAllocDyna ++;
1258 l.Stats.cbAllocCpp += Chunk.cbData;
1259 else // (!Chunk.fCPP)
1260 l.Stats.cbAllocDyna += Chunk.cbData;
1262 l.Stats.cAllocTotal ++;
1263 l.Stats.cbAllocTotal += Chunk.cbData;
1265 LeaveCriticalSection (l.pcs);
1267 if (IsWindow (l.hManager))
1268 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1272 BOOL MemMgr_TrackDestruction (PVOID pData, LPTSTR pszFile, DWORD dwLine)
1274 if (MemMgr_Initialize())
1276 EnterCriticalSection (l.pcs);
1278 // Find the memchunk associated with this pData. That's what our
1279 // hash table is for.
1281 size_t iBucket = HASH(PtrToUlong(pData),l.cBuckets);
1283 PMEMCHUNK pChunk = NULL;
1284 for (size_t iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1286 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1288 if (pChunk->pData == pData)
1290 if ((iChunk = pChunk->iNext) == iINVALID)
1300 memset (&Sim, 0x00, sizeof(MEMCHUNK));
1302 Sim.pszExpr = TEXT("(unknown)");
1303 Sim.pszFile = TEXT("(unknown)");
1304 MemMgr_ShowWarning (&Sim, pszFile, dwLine, TEXT("An invalid memory address was freed."));
1306 else if (pChunk->dwEndSig && (*(DWORD*)((PBYTE)pData + pChunk->cbData) != pChunk->dwEndSig))
1308 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("The trailing signature on a block of memory was overwritten."));
1310 else if (pChunk->fFreed)
1312 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("A block of memory was freed more than once."));
1317 pChunk->fFreed = TRUE;
1319 if (IsWindow (l.hManager))
1321 if (pChunk->fInList)
1322 MemMgr_RemoveFromList (pChunk);
1326 l.Stats.cAllocCpp --;
1327 else // (!pChunk->fCPP)
1328 l.Stats.cAllocDyna --;
1331 l.Stats.cbAllocCpp -= pChunk->cbData;
1332 else // (!pChunk->fCPP)
1333 l.Stats.cbAllocDyna -= pChunk->cbData;
1335 l.Stats.cAllocTotal --;
1336 l.Stats.cbAllocTotal -= pChunk->cbData;
1340 // Unlink this chunk from the hash table
1342 if (pChunk->iNext != iINVALID)
1345 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1346 pNext->iPrev = pChunk->iPrev;
1348 if (pChunk->iPrev != iINVALID)
1351 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iPrev)) != NULL)
1352 pPrev->iNext = pChunk->iNext;
1354 if (l.aBuckets[iBucket].iFirst == iChunk)
1355 l.aBuckets[iBucket].iFirst = pChunk->iNext;
1357 // Empty this element in the expandarray. That means we need to
1358 // take the last element and shove it in here--so we'll have do
1359 // rework the hash table a little bit more.
1361 if (iChunk != l.cChunks-1)
1364 if ((pMove = (PMEMCHUNK)l.pHeap->GetAt(l.cChunks-1)) != NULL)
1366 size_t iBucket = HASH(pMove->pData,l.cBuckets);
1368 if (pMove->iNext != iINVALID)
1371 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pMove->iNext)) != NULL)
1372 pNext->iPrev = iChunk;
1374 if (pMove->iPrev != iINVALID)
1377 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pMove->iPrev)) != NULL)
1378 pPrev->iNext = iChunk;
1380 if (l.aBuckets[iBucket].iFirst == (l.cChunks-1))
1381 l.aBuckets[iBucket].iFirst = iChunk;
1383 l.pHeap->SetAt (iChunk, pMove);
1384 memset (pMove, 0x00, sizeof(MEMCHUNK));
1390 #endif // TRACK_FREED
1393 LeaveCriticalSection (l.pcs);
1396 if (IsWindow (l.hManager))
1397 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1403 * PUBLIC ROUTINES ____________________________________________________________
1407 void MEMMGR_CALLCONV ShowMemoryManager (void)
1409 if (MemMgr_Initialize())
1411 if (!IsWindow (l.hManager))
1413 MemMgr_RestoreSettings();
1414 l.hManager = MakeWindow (TEXT("Static"), cszTITLE, WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, &lr.rManager, 0, 0);
1415 SetWindowLongPtr (l.hManager, GWLP_WNDPROC, (LONG)PtrToUlong(MemMgr_DlgProc));
1416 PostMessage (l.hManager, WM_COMMAND, IDC_INITIALIZE, 0);
1417 ShowWindow (l.hManager, SW_SHOW);
1423 void MEMMGR_CALLCONV WhileMemoryManagerShowing (void)
1425 if (MemMgr_Initialize())
1427 while (IsWindow (l.hManager))
1430 if (!GetMessage (&msg, NULL, 0, 0))
1433 if (!IsDialogMessage (l.hManager, &msg))
1435 TranslateMessage (&msg);
1436 DispatchMessage (&msg);
1443 BOOL MEMMGR_CALLCONV IsMemoryManagerMessage (MSG *pMsg)
1445 if (IsWindow (l.hManager))
1447 if (pMsg->hwnd == l.hManager)
1449 // if (IsDialogMessage (l.hManager, pMsg))
1453 else if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_F8))
1455 ShowMemoryManager();
1462 PVOID MEMMGR_CALLCONV MemMgr_AllocateMemory (size_t cb, LPTSTR pszExpr, LPTSTR pszFile, DWORD dwLine)
1464 PVOID pData = GlobalAlloc (GMEM_FIXED, cb + sizeof(DWORD));
1465 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, TRUE);
1470 void MEMMGR_CALLCONV MemMgr_FreeMemory (PVOID pData, LPTSTR pszFile, DWORD dwLine)
1472 if (MemMgr_TrackDestruction (pData, pszFile, dwLine))
1474 GlobalFree ((HGLOBAL)pData);
1479 PVOID MEMMGR_CALLCONV MemMgr_TrackNew (PVOID pData, size_t cb, LPTSTR pszExpr, LPTSTR pszFile, DWORD dwLine)
1481 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, FALSE);
1486 void MEMMGR_CALLCONV MemMgr_TrackDelete (PVOID pData, LPTSTR pszFile, DWORD dwLine)
1488 MemMgr_TrackDestruction (pData, pszFile, dwLine);
1493 * EXPANDARRAY ________________________________________________________________
1495 * We'll use an EXPANDARRAY to manage our heap of allocation information.
1496 * Technically I would prefer to use a full HASHLIST here, but I don't want
1497 * this source file to be dependent upon yet another file. So we'll kinda
1498 * write a special-purpose hash system.
1502 #define cEXPANDARRAYHEAPELEMENTS 1024
1503 #define cREALLOC_EXPANDARRAYHEAPS 16
1505 ALLOCEXPANDARRAY::ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap)
1507 if ((m_cbElement = cbElement) == 0)
1508 m_cbElement = sizeof(DWORD);
1509 if ((m_cElementsPerHeap = cElementsPerHeap) == 0)
1510 m_cElementsPerHeap = cEXPANDARRAYHEAPELEMENTS;
1516 ALLOCEXPANDARRAY::~ALLOCEXPANDARRAY (void)
1520 for (size_t ii = 0; ii < m_cHeaps; ++ii)
1521 GlobalFree ((HGLOBAL)(m_aHeaps[ ii ]));
1522 GlobalFree ((HGLOBAL)m_aHeaps);
1526 PVOID ALLOCEXPANDARRAY::GetAt (size_t iElement)
1528 size_t iHeap = iElement / m_cElementsPerHeap;
1529 size_t iIndex = iElement % m_cElementsPerHeap;
1530 if ((iHeap >= m_cHeaps) || (!m_aHeaps[iHeap]))
1532 return (PVOID)&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ];
1535 void ALLOCEXPANDARRAY::SetAt (size_t iElement, PVOID pData)
1537 size_t iHeap = iElement / m_cElementsPerHeap;
1538 size_t iIndex = iElement % m_cElementsPerHeap;
1540 if (!REALLOC (m_aHeaps, m_cHeaps, 1+iHeap, cREALLOC_EXPANDARRAYHEAPS))
1543 if (!m_aHeaps[ iHeap ])
1545 size_t cbHeap = sizeof(EXPANDARRAYHEAP) + (m_cElementsPerHeap * m_cbElement);
1546 if ((m_aHeaps[ iHeap ] = (LPEXPANDARRAYHEAP)GlobalAlloc (GMEM_FIXED, cbHeap)) == NULL)
1548 memset (m_aHeaps[ iHeap ], 0x00, cbHeap);
1549 m_aHeaps[ iHeap ]->aElements = ((PBYTE)m_aHeaps[ iHeap ]) + sizeof(EXPANDARRAYHEAP);
1553 memset (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], 0x00, m_cbElement);
1555 memcpy (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], pData, m_cbElement);