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;
98 LONG cAllocTotalTared;
102 LONG cbAllocCppTared;
103 LONG cbAllocDynaTared;
104 LONG 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, HWND hParent, UINT idc, DWORD dwStyleEx = 0)
253 RECT rr = { 0, 0, 16, 16 };
256 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);
258 SendMessage (hWnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 1);
262 void SetWindowRect (HWND hWnd, RECT *pr)
264 SetWindowPos (hWnd, 0, pr->left, pr->top, pr->right - pr->left, pr->bottom - pr->top, SWP_NOZORDER | SWP_NOACTIVATE);
267 void FormatBytes (LPTSTR pszText, double lfValue)
272 *pszText++ = TEXT('-');
275 if (lfValue >= 1048576)
277 LONG Value = (LONG)(lfValue / 1048576);
278 lfValue -= Value * 1048576;
279 LONG Frac = (LONG)(lfValue * 100 / 1048576);
280 wsprintf (pszText, TEXT("%ld.%ld MB"), Value, Frac);
282 else if (lfValue >= 3072)
284 LONG Value = (LONG)(lfValue / 1024);
285 lfValue -= Value * 1024;
286 LONG Frac = (LONG)(lfValue * 100 / 1024);
287 wsprintf (pszText, TEXT("%ld.%ld kb"), Value, Frac);
289 else // (lfValue < 3072)
291 wsprintf (pszText, TEXT("%ld b"), (LONG)lfValue);
295 void FormatTime (LPTSTR pszText, DWORD dwTick)
297 static FILETIME ftTickZero = { 0, 0 };
298 if (!ftTickZero.dwHighDateTime && !ftTickZero.dwLowDateTime)
300 // We need to find out what FILETIME corresponds with a tick
301 // count of zero. To do that, first find the FILETIME and tick
302 // count that represent *now* (in local time).
305 GetLocalTime (&stNow);
306 SystemTimeToFileTime (&stNow, &ftTickZero);
308 DWORD dwTickNow = GetTickCount();
310 // A FILETIME is a count-of-100ns-intervals, and a tick count is
311 // a count of 1ms-intervals. So we need to subtract off a big
312 // number times our tick count.
314 if ((dwTickNow * 10000) < (dwTickNow))
315 ftTickZero.dwHighDateTime --;
316 dwTickNow *= 10000; // convert to 100ns intervals
317 if (dwTickNow > ftTickZero.dwLowDateTime)
318 ftTickZero.dwHighDateTime --;
319 ftTickZero.dwLowDateTime -= dwTickNow; // unsigned, so it'll wrap OK
322 // Convert the given tick count into 100ns intervals, and add it
323 // to our ftTickZero.
325 FILETIME ftTick = ftTickZero;
327 if ((dwTick * 10000) < (dwTick))
328 ftTick.dwHighDateTime ++;
329 dwTick *= 10000; // convert to 100ns intervals
330 if (dwTick > (DWORD)(0-ftTick.dwLowDateTime)) // too big to add?
331 ftTick.dwHighDateTime ++;
332 ftTick.dwLowDateTime += dwTick; // unsigned, so it'll wrap OK
334 // Convert to a SYSTEMTIME, and output the time component
337 FileTimeToSystemTime (&ftTick, &stTick);
339 wsprintf (pszText, TEXT("%ld:%02ld:%02ld.%02ld"),
341 (DWORD)stTick.wMinute,
342 (DWORD)stTick.wSecond,
343 (DWORD)(stTick.wMilliseconds / 100));
346 void SetDlgItemBytes (HWND hDlg, int idc, double lfValue)
349 FormatBytes (szText, lfValue);
350 SetDlgItemText (hDlg, idc, szText);
354 void MemMgr_ShowWarning (PMEMCHUNK pChunk, LPSTR pszFile, DWORD dwLine, LPTSTR pszDesc)
356 TCHAR szMessage[ 1024 ];
357 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, (long)pChunk->pData, pChunk->pszExpr, pChunk->pszFile, pChunk->dwLine, pszFile, dwLine);
358 if (MessageBox (NULL, szMessage, cszTITLE, MB_ICONHAND | MB_OKCANCEL | MB_DEFBUTTON2) == IDOK)
360 // TODO: Show Details
364 void MIX (RECT *pr, RECT *pr1, RECT *pr2)
366 pr->left = pr2->left;
368 pr->right = pr2->right;
369 pr->bottom = pr1->bottom;
372 void MemMgr_GetWindowSizes (WINDOWSIZES *pSizes)
375 GetClientRect (l.hManager, &rClient);
376 InflateRect (&rClient, 0-cBORDER, 0-cBORDER);
378 pSizes->rLabelAverage.right = rClient.right -cxBETWEEN*2;
379 pSizes->rLabelAverage.top = rClient.top +8 +cyBETWEEN;
380 pSizes->rLabelAverage.left = pSizes->rLabelAverage.right -cxVALUES;
381 pSizes->rLabelAverage.bottom = pSizes->rLabelAverage.top +cyLABELS;
383 pSizes->rLabelSize = pSizes->rLabelAverage;
384 pSizes->rLabelSize.left -= cxBETWEEN + cxVALUES;
385 pSizes->rLabelSize.right -= cxBETWEEN + cxVALUES;
387 pSizes->rLabelCount = pSizes->rLabelSize;
388 pSizes->rLabelCount.left -= cxBETWEEN + cxVALUES;
389 pSizes->rLabelCount.right -= cxBETWEEN + cxVALUES;
391 pSizes->rLabelCpp.left = rClient.left +cxBETWEEN;
392 pSizes->rLabelCpp.top = pSizes->rLabelCount.bottom +cyBETWEEN;
393 pSizes->rLabelCpp.right = pSizes->rLabelCpp.left +cxLABELS;
394 pSizes->rLabelCpp.bottom = pSizes->rLabelCpp.top +cyLABELS;
396 pSizes->rLabelOther = pSizes->rLabelCpp;
397 pSizes->rLabelOther.top += cyBETWEEN + cyLABELS;
398 pSizes->rLabelOther.bottom += cyBETWEEN + cyLABELS;
400 pSizes->rLabelTotal = pSizes->rLabelOther;
401 pSizes->rLabelTotal.top += cyBETWEEN + cyLABELS;
402 pSizes->rLabelTotal.bottom += cyBETWEEN + cyLABELS;
404 pSizes->rLabelTared = pSizes->rLabelTotal;
405 pSizes->rLabelTared.top += cyBETWEEN + cyLABELS;
406 pSizes->rLabelTared.bottom += cyBETWEEN + cyLABELS;
408 pSizes->rBoxAlloc = rClient;
409 pSizes->rBoxAlloc.bottom = pSizes->rLabelTared.bottom +cyBETWEEN;
411 MIX (&pSizes->rValueCppCount, &pSizes->rLabelCpp, &pSizes->rLabelCount);
412 MIX (&pSizes->rValueOtherCount, &pSizes->rLabelOther, &pSizes->rLabelCount);
413 MIX (&pSizes->rValueTaredCount, &pSizes->rLabelTared, &pSizes->rLabelCount);
414 MIX (&pSizes->rValueTotalCount, &pSizes->rLabelTotal, &pSizes->rLabelCount);
416 MIX (&pSizes->rValueCppSize, &pSizes->rLabelCpp, &pSizes->rLabelSize);
417 MIX (&pSizes->rValueOtherSize, &pSizes->rLabelOther, &pSizes->rLabelSize);
418 MIX (&pSizes->rValueTaredSize, &pSizes->rLabelTared, &pSizes->rLabelSize);
419 MIX (&pSizes->rValueTotalSize, &pSizes->rLabelTotal, &pSizes->rLabelSize);
421 MIX (&pSizes->rValueCppAverage, &pSizes->rLabelCpp, &pSizes->rLabelAverage);
422 MIX (&pSizes->rValueOtherAverage, &pSizes->rLabelOther, &pSizes->rLabelAverage);
423 MIX (&pSizes->rValueTaredAverage, &pSizes->rLabelTared, &pSizes->rLabelAverage);
424 MIX (&pSizes->rValueTotalAverage, &pSizes->rLabelTotal, &pSizes->rLabelAverage);
426 pSizes->rBoxDetails = rClient;
427 pSizes->rBoxDetails.top = pSizes->rBoxAlloc.bottom +cyBETWEEN;
428 pSizes->rBoxDetails.bottom -= cyBUTTONS +cyBETWEEN;
430 pSizes->rList = pSizes->rBoxDetails;
431 pSizes->rList.top += 8;
432 InflateRect (&pSizes->rList, 0-cBORDER, 0-cBORDER);
434 pSizes->rClose = rClient;
435 pSizes->rClose.top = pSizes->rClose.bottom - cyBUTTONS;
436 pSizes->rClose.left = pSizes->rClose.right - cxBUTTONS;
438 pSizes->rReset = pSizes->rClose;
439 pSizes->rReset.right = pSizes->rClose.left - cxBETWEEN;
440 pSizes->rReset.left = pSizes->rReset.right - cxBUTTONS;
442 pSizes->rTare = pSizes->rClose;
443 pSizes->rTare.right = pSizes->rReset.left - cxBETWEEN;
444 pSizes->rTare.left = pSizes->rTare.right - cxBUTTONS;
446 pSizes->rLabel = pSizes->rTare;
447 pSizes->rLabel.right = pSizes->rTare.left - cxBETWEEN;
448 pSizes->rLabel.left = pSizes->rLabel.right - cxBUTTONS;
450 pSizes->rHide = pSizes->rLabel;
451 pSizes->rHide.right = pSizes->rLabel.left - cxBETWEEN;
452 pSizes->rHide.left = pSizes->rHide.right - cxBUTTONS;
455 void MemMgr_OnSize (void)
458 MemMgr_GetWindowSizes (&Sizes);
459 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_ALLOC), &Sizes.rBoxAlloc);
460 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_CPP), &Sizes.rLabelCpp);
461 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_OTHER), &Sizes.rLabelOther);
462 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TARED), &Sizes.rLabelTared);
463 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TOTAL), &Sizes.rLabelTotal);
464 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_COUNT), &Sizes.rLabelCount);
465 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_SIZE), &Sizes.rLabelSize);
466 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_AVERAGE), &Sizes.rLabelAverage);
467 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_COUNT), &Sizes.rValueCppCount);
468 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_COUNT), &Sizes.rValueOtherCount);
469 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_COUNT), &Sizes.rValueTaredCount);
470 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_COUNT), &Sizes.rValueTotalCount);
471 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_SIZE), &Sizes.rValueCppSize);
472 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_SIZE), &Sizes.rValueOtherSize);
473 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_SIZE), &Sizes.rValueTaredSize);
474 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_SIZE), &Sizes.rValueTotalSize);
475 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_AVERAGE), &Sizes.rValueCppAverage);
476 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_AVERAGE), &Sizes.rValueOtherAverage);
477 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_AVERAGE), &Sizes.rValueTaredAverage);
478 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_AVERAGE), &Sizes.rValueTotalAverage);
479 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_DETAILS), &Sizes.rBoxDetails);
480 SetWindowRect (GetDlgItem (l.hManager, IDC_LIST), &Sizes.rList);
481 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL), &Sizes.rLabel);
482 SetWindowRect (GetDlgItem (l.hManager, IDC_HIDE), &Sizes.rHide);
483 SetWindowRect (GetDlgItem (l.hManager, IDC_TARE), &Sizes.rTare);
484 SetWindowRect (GetDlgItem (l.hManager, IDC_RESET), &Sizes.rReset);
485 SetWindowRect (GetDlgItem (l.hManager, IDCANCEL), &Sizes.rClose);
489 void MemMgr_OnListRemove (PVOID pData)
491 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
494 Find.flags = LVFI_PARAM;
495 Find.lParam = (LPARAM)pData;
498 if ((iItem = ListView_FindItem (hList, 0, &Find)) == -1)
500 // The listview's find feature sucks; I've seen with my own little
501 // eyes that it may miss an item if it's the only one in a list.
502 // Look for ourselves.
504 int cItems = ListView_GetItemCount(hList);
505 for (iItem = 0; iItem < cItems; ++iItem)
509 Item.mask = LVIF_PARAM;
510 ListView_GetItem (hList, &Item);
511 if (Item.lParam == (LPARAM)pData)
518 ListView_DeleteItem (hList, iItem);
523 void MemMgr_RemoveFromList (PMEMCHUNK pChunk)
525 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVE, (LPARAM)(pChunk->pData));
526 pChunk->fInList = FALSE;
530 LPTSTR MemMgr_GetItemKey (HWND hList, int iItem)
532 static TCHAR szText[ 256 ];
533 LPTSTR pszReturn = NULL;
542 Item.mask = LVIF_PARAM;
543 ListView_GetItem (hList, &Item);
545 EnterCriticalSection (l.pcs);
548 iBucket = HASH(Item.lParam,l.cBuckets);
554 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
556 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
558 if (pChunk->pData == (PVOID)Item.lParam)
560 if ((iChunk = pChunk->iNext) == iINVALID)
569 if (lr.iColSort == 0)
570 pszReturn = (LPTSTR)pChunk->dwTick;
571 else if (lr.iColSort == 4)
572 pszReturn = (LPTSTR)pChunk->cbData;
573 else // (lr.iColSort == 5)
574 pszReturn = (LPTSTR)pChunk->pData;
577 LeaveCriticalSection (l.pcs);
581 ListView_GetItemText (hList, iItem, lr.iColSort, szText, 256);
590 int MemMgr_CompareItems (LPTSTR pszKey1, LPTSTR pszKey2)
599 dw = (int)( (DWORD)pszKey1 - (DWORD)pszKey2 );
603 dw = lstrcmpi (pszKey1, pszKey2);
607 return (lr.fSortRev) ? (0-dw) : dw;
611 int MemMgr_PickListInsertionPoint (HWND hList, LPTSTR pszKey)
614 int iItemHigh = ListView_GetItemCount (hList) -1;
616 while (iItemLow <= iItemHigh)
618 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
620 LPTSTR pszAlternate = MemMgr_GetItemKey (hList, iItemTest);
622 int iCompare = MemMgr_CompareItems (pszKey, pszAlternate);
625 if ((iItemHigh = iItemTest-1) < iItemLow)
630 if ((iItemLow = iItemTest+1) > iItemHigh)
639 void MemMgr_OnListAdd (PMEMCHUNK pCopy)
641 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
644 FormatTime (szTime, pCopy->dwTick);
647 LPTSTR pszFlags = szFlags;
648 *pszFlags++ = (pCopy->fCPP) ? TEXT('C') : TEXT(' ');
649 *pszFlags++ = TEXT(' ');
650 *pszFlags++ = (pCopy->fFreed) ? TEXT('F') : TEXT(' ');
654 lstrcpy (szExpr, (pCopy->pszExpr) ? pCopy->pszExpr : TEXT("unknown"));
656 LPTSTR pszFile = pCopy->pszFile;
657 for (LPTSTR psz = pCopy->pszFile; *psz; ++psz)
659 if ((*psz == TEXT(':')) || (*psz == TEXT('\\')))
662 TCHAR szLocation[256];
663 if (!pszFile || !pCopy->dwLine)
664 lstrcpy (szLocation, TEXT("unknown"));
666 wsprintf (szLocation, TEXT("%s, %ld"), pszFile, pCopy->dwLine);
669 FormatBytes (szBytes, (double)pCopy->cbData);
671 TCHAR szAddress[256];
672 wsprintf (szAddress, TEXT("0x%08lX"), (long)pCopy->pData);
674 LPTSTR pszKey = NULL;
677 case 0: pszKey = (LPTSTR)pCopy->dwTick; break;
678 case 1: pszKey = (LPTSTR)szFlags; break;
679 case 2: pszKey = (LPTSTR)szExpr; break;
680 case 3: pszKey = (LPTSTR)szLocation; break;
681 case 4: pszKey = (LPTSTR)pCopy->cbData; break;
682 case 5: pszKey = (LPTSTR)pCopy->pData; break;
686 memset (&Item, 0x00, sizeof(Item));
687 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
688 Item.iItem = MemMgr_PickListInsertionPoint (hList, pszKey);
690 Item.cchTextMax = 256;
691 Item.lParam = (LPARAM)pCopy->pData;
693 Item.pszText = szTime;
694 DWORD iItem = ListView_InsertItem (hList, &Item);
695 ListView_SetItemText (hList, iItem, 1, szFlags);
696 ListView_SetItemText (hList, iItem, 2, szExpr);
697 ListView_SetItemText (hList, iItem, 3, szLocation);
698 ListView_SetItemText (hList, iItem, 4, szBytes);
699 ListView_SetItemText (hList, iItem, 5, szAddress);
705 void MemMgr_AddToList (PMEMCHUNK pChunk)
707 PMEMCHUNK pCopy = new MEMCHUNK;
708 memcpy (pCopy, pChunk, sizeof(MEMCHUNK));
711 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVEADD, (LPARAM)pCopy);
713 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_ADD, (LPARAM)pCopy);
714 pChunk->fInList = TRUE;
718 void MemMgr_RestoreSettings (void)
720 lr.rManager.left = 0;
722 lr.rManager.right = 510;
723 lr.rManager.bottom = 440;
724 lr.acxColumns[0] = 70;
725 lr.acxColumns[1] = 40;
726 lr.acxColumns[2] = 100;
727 lr.acxColumns[3] = 110;
728 lr.acxColumns[4] = 50;
729 lr.acxColumns[5] = 80;
734 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
736 DWORD dwType = REG_BINARY;
737 DWORD dwSize = sizeof(lr);
738 RegQueryValueEx (hk, TEXT("Settings"), 0, &dwType, (PBYTE)&lr, &dwSize);
743 void MemMgr_StoreSettings (void)
745 if (IsWindow (l.hManager))
747 GetWindowRect (l.hManager, &lr.rManager);
749 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
750 if (IsWindow (hList))
752 for (size_t ii = 0; ii < 6; ++ii)
753 lr.acxColumns[ ii ] = ListView_GetColumnWidth (hList, ii);
758 if (RegCreateKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
760 RegSetValueEx (hk, TEXT("Settings"), 0, REG_BINARY, (PBYTE)&lr, sizeof(lr));
765 void MemMgr_OnInit (void)
767 DWORD dwFlags = WS_CHILD | WS_TABSTOP | WS_VISIBLE;
768 MakeWindow (TEXT("Button"), TEXT("Allocation Statistics"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_ALLOC);
769 MakeWindow (TEXT("Static"), TEXT("C++ Objects:"), dwFlags, NULL, l.hManager, IDC_LABEL_CPP);
770 MakeWindow (TEXT("Static"), TEXT("Dynamic:"), dwFlags, NULL, l.hManager, IDC_LABEL_OTHER);
771 MakeWindow (TEXT("Static"), TEXT("Combined:"), dwFlags, NULL, l.hManager, IDC_LABEL_TOTAL);
772 MakeWindow (TEXT("Static"), TEXT("Tared:"), dwFlags, NULL, l.hManager, IDC_LABEL_TARED);
773 MakeWindow (TEXT("Static"), TEXT("Count"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_COUNT);
774 MakeWindow (TEXT("Static"), TEXT("Size"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_SIZE);
775 MakeWindow (TEXT("Static"), TEXT("Average"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_AVERAGE);
776 MakeWindow (TEXT("Static"), TEXT("0"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_COUNT);
777 MakeWindow (TEXT("Static"), TEXT("1"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_COUNT);
778 MakeWindow (TEXT("Static"), TEXT("2"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_COUNT);
779 MakeWindow (TEXT("Static"), TEXT("3"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_COUNT);
780 MakeWindow (TEXT("Static"), TEXT("4"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_SIZE);
781 MakeWindow (TEXT("Static"), TEXT("5"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_SIZE);
782 MakeWindow (TEXT("Static"), TEXT("6"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_SIZE);
783 MakeWindow (TEXT("Static"), TEXT("7"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_SIZE);
784 MakeWindow (TEXT("Static"), TEXT("8"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_AVERAGE);
785 MakeWindow (TEXT("Static"), TEXT("9"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_AVERAGE);
786 MakeWindow (TEXT("Static"), TEXT("10"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_AVERAGE);
787 MakeWindow (TEXT("Static"), TEXT("11"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_AVERAGE);
788 MakeWindow (TEXT("Button"), TEXT("Details"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_DETAILS);
789 MakeWindow (WC_LISTVIEW, TEXT(""), dwFlags | LVS_REPORT | LVS_SINGLESEL, NULL, l.hManager, IDC_LIST, WS_EX_CLIENTEDGE);
790 // MakeWindow (TEXT("Button"), TEXT("Label"), dwFlags, NULL, l.hManager, IDC_LABEL);
791 // MakeWindow (TEXT("Button"), TEXT("Hidden"), dwFlags, NULL, l.hManager, IDC_HIDE);
792 MakeWindow (TEXT("Button"), TEXT("Tare"), dwFlags, NULL, l.hManager, IDC_TARE);
793 MakeWindow (TEXT("Button"), TEXT("Restore"), dwFlags, NULL, l.hManager, IDC_RESET);
794 MakeWindow (TEXT("Button"), TEXT("Close"), dwFlags, NULL, l.hManager, IDCANCEL);
797 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
800 Col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM;
801 Col.fmt = LVCFMT_LEFT;
803 Col.cx = lr.acxColumns[0];
804 Col.pszText = TEXT("Time");
805 ListView_InsertColumn (hList, Col.iSubItem, &Col);
807 Col.cx = lr.acxColumns[1];
808 Col.pszText = TEXT("Flags");
810 ListView_InsertColumn (hList, Col.iSubItem, &Col);
812 Col.cx = lr.acxColumns[2];
813 Col.pszText = TEXT("Expression");
815 ListView_InsertColumn (hList, Col.iSubItem, &Col);
817 Col.cx = lr.acxColumns[3];
818 Col.pszText = TEXT("Location");
820 ListView_InsertColumn (hList, Col.iSubItem, &Col);
822 Col.fmt = LVCFMT_RIGHT;
823 Col.cx = lr.acxColumns[4];
824 Col.pszText = TEXT("Size");
826 ListView_InsertColumn (hList, Col.iSubItem, &Col);
828 Col.cx = lr.acxColumns[5];
829 Col.pszText = TEXT("Address");
831 ListView_InsertColumn (hList, Col.iSubItem, &Col);
833 EnterCriticalSection (l.pcs);
834 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
836 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
839 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
842 pChunk->fInList = FALSE;
843 if (!pChunk->fTared && !pChunk->fFreed)
844 MemMgr_AddToList (pChunk);
847 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
848 LeaveCriticalSection (l.pcs);
850 l.idTimer = SetTimer (l.hManager, 0, cmsecREFRESH, NULL);
853 void MemMgr_OnRefresh (void)
855 // Fill in the statistics at the top of the manager dialog
857 SetDlgItemInt (l.hManager, IDC_VALUE_CPP_COUNT, l.Stats.cAllocCpp, TRUE);
858 SetDlgItemInt (l.hManager, IDC_VALUE_OTHER_COUNT, l.Stats.cAllocDyna, TRUE);
859 SetDlgItemInt (l.hManager, IDC_VALUE_TARED_COUNT, l.Stats.cAllocTotalTared, TRUE);
860 SetDlgItemInt (l.hManager, IDC_VALUE_TOTAL_COUNT, l.Stats.cAllocTotal, TRUE);
862 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_SIZE, (double)l.Stats.cbAllocCpp);
863 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_SIZE, (double)l.Stats.cbAllocDyna);
864 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_SIZE, (double)l.Stats.cbAllocTotalTared);
865 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_SIZE, (double)l.Stats.cbAllocTotal);
867 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_AVERAGE, (l.Stats.cAllocCpp) ? ((double)l.Stats.cbAllocCpp / l.Stats.cAllocCpp) : 0);
868 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_AVERAGE, (l.Stats.cAllocDyna) ? ((double)l.Stats.cbAllocDyna / l.Stats.cAllocDyna) : 0);
869 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_AVERAGE, (l.Stats.cAllocTotalTared) ? ((double)l.Stats.cbAllocTotalTared / l.Stats.cAllocTotalTared) : 0);
870 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_AVERAGE, (l.Stats.cAllocTotal) ? ((double)l.Stats.cbAllocTotal / l.Stats.cAllocTotal) : 0);
873 void MemMgr_OnLabel (void)
878 void MemMgr_OnHide (void)
883 void MemMgr_OnReset (void)
885 l.Stats.cAllocCpp += l.Stats.cAllocCppTared;
886 l.Stats.cAllocDyna += l.Stats.cAllocDynaTared;
887 l.Stats.cAllocTotal += l.Stats.cAllocTotalTared;
888 l.Stats.cbAllocCpp += l.Stats.cbAllocCppTared;
889 l.Stats.cbAllocDyna += l.Stats.cbAllocDynaTared;
890 l.Stats.cbAllocTotal += l.Stats.cbAllocTotalTared;
892 l.Stats.cAllocCppTared = 0;
893 l.Stats.cAllocDynaTared = 0;
894 l.Stats.cAllocTotalTared = 0;
895 l.Stats.cbAllocCppTared = 0;
896 l.Stats.cbAllocDynaTared = 0;
897 l.Stats.cbAllocTotalTared = 0;
899 EnterCriticalSection (l.pcs);
900 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
902 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
904 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
907 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
910 pChunk->fInList = FALSE;
911 pChunk->fTared = FALSE;
913 MemMgr_AddToList (pChunk);
916 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
917 LeaveCriticalSection (l.pcs);
922 void MemMgr_OnTare (void)
924 l.Stats.cAllocCppTared += l.Stats.cAllocCpp;
925 l.Stats.cAllocDynaTared += l.Stats.cAllocDyna;
926 l.Stats.cAllocTotalTared += l.Stats.cAllocTotal;
927 l.Stats.cbAllocCppTared += l.Stats.cbAllocCpp;
928 l.Stats.cbAllocDynaTared += l.Stats.cbAllocDyna;
929 l.Stats.cbAllocTotalTared += l.Stats.cbAllocTotal;
931 l.Stats.cAllocCpp = 0;
932 l.Stats.cAllocDyna = 0;
933 l.Stats.cAllocTotal = 0;
934 l.Stats.cbAllocCpp = 0;
935 l.Stats.cbAllocDyna = 0;
936 l.Stats.cbAllocTotal = 0;
938 EnterCriticalSection (l.pcs);
939 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
941 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
943 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
946 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
949 pChunk->fInList = FALSE;
950 pChunk->fTared = TRUE;
953 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
954 LeaveCriticalSection (l.pcs);
960 void MemMgr_OnSort (void)
962 EnterCriticalSection (l.pcs);
963 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
965 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
967 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
970 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
973 pChunk->fInList = FALSE;
974 if (!pChunk->fTared && !pChunk->fFreed)
975 MemMgr_AddToList (pChunk);
978 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
979 LeaveCriticalSection (l.pcs);
983 void MemMgr_OnPaint (void)
986 HDC hdc = BeginPaint (l.hManager, &ps);
988 static HBRUSH hbr = (HBRUSH)CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
989 FillRect (hdc, &ps.rcPaint, hbr);
991 EndPaint (l.hManager, &ps);
995 void MemMgr_OnTimer (void)
997 if (GetWindowLong (l.hManager, GWL_USERDATA))
999 SetWindowLong (l.hManager, GWL_USERDATA, 0);
1005 void MemMgr_OnDelayedRefresh (void)
1007 SetWindowLong (l.hManager, GWL_USERDATA, 1);
1011 BOOL CALLBACK MemMgr_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1016 MemMgr_StoreSettings();
1018 KillTimer (hDlg, l.idTimer);
1024 MemMgr_StoreSettings();
1028 MemMgr_StoreSettings();
1031 case WM_GETMINMAXINFO:
1033 lpmmi = (LPMINMAXINFO)lp;
1034 lpmmi->ptMinTrackSize.x = cxBUTTONS*5 + cxBETWEEN*4 + cBORDER*2 + 8;
1035 lpmmi->ptMinTrackSize.y = 270;
1043 switch (((NMHDR *)lp)->code)
1045 case LVN_COLUMNCLICK:
1046 if (((NM_LISTVIEW*)lp)->iSubItem == lr.iColSort)
1047 lr.fSortRev = !lr.fSortRev;
1050 lr.iColSort = ((NM_LISTVIEW*)lp)->iSubItem;
1051 lr.fSortRev = FALSE;
1054 MemMgr_StoreSettings();
1067 DestroyWindow (hDlg);
1070 case IDC_INITIALIZE:
1076 MemMgr_OnDelayedRefresh();
1095 case IDC_LIST_REMOVEADD:
1096 MemMgr_OnListRemove (((PMEMCHUNK)lp)->pData);
1097 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1101 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1104 case IDC_LIST_REMOVE:
1105 MemMgr_OnListRemove ((PVOID)lp);
1111 return DefWindowProc (hDlg, msg, wp, lp);
1116 * MANAGEMENT ROUTINES ________________________________________________________
1120 BOOL MemMgr_Initialize (void)
1124 l.pcs = new CRITICAL_SECTION;
1125 InitializeCriticalSection (l.pcs);
1127 l.pHeap = new ALLOCEXPANDARRAY (sizeof(MEMCHUNK));
1129 REALLOC (l.aBuckets, l.cBuckets, cDEFAULT_BUCKETS, 1);
1132 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1133 l.aBuckets[ii].iFirst = iINVALID;
1137 return (l.pHeap) && (l.aBuckets);
1141 void MemMgr_TrackAllocation (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine, BOOL fSig)
1145 if (!MemMgr_Initialize())
1148 EnterCriticalSection (l.pcs);
1150 // Ensure our hash table will be large enough to handle the new
1151 // MEMCHUNK we're about to assign.
1153 if (l.cBuckets < MIN_BUCKETS(l.cChunks+1))
1155 // Too small! Rebuild the hash table.
1157 REALLOC (l.aBuckets, l.cBuckets, TARGET_BUCKETS(l.cChunks+1), 1);
1160 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1161 l.aBuckets[ii].iFirst = iINVALID;
1163 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
1166 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1169 size_t iBucket = HASH(pChunk->pData,l.cBuckets);
1170 if ((pChunk->iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1173 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1174 pNext->iPrev = iChunk;
1176 l.aBuckets[iBucket].iFirst = iChunk;
1177 pChunk->iPrev = iINVALID;
1182 // If space was allocated for a trailing signature, write one
1185 *(DWORD *)( (PBYTE)pData + cb ) = dwSIG_AT_END;
1187 // Prepare a MEMCHUNK entry and shove it in our array
1189 size_t iChunk = l.cChunks;
1190 size_t iBucket = HASH(pData,l.cBuckets);
1191 BOOL fLinkIn = TRUE;
1194 Chunk.pData = pData;
1195 Chunk.fFreed = FALSE;
1197 Chunk.pszExpr = pszExpr;
1198 Chunk.pszFile = pszFile;
1200 Chunk.dwLine = dwLine;
1201 Chunk.dwTick = GetTickCount();
1202 Chunk.dwEndSig = (fSig) ? dwSIG_AT_END : 0;
1203 Chunk.fInList = FALSE;
1204 Chunk.fTared = FALSE;
1207 // Find the memchunk associated with this pData. That's what our
1208 // hash table is for.
1210 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1213 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) != NULL)
1215 if (pChunk->pData == pData)
1217 Chunk.iNext = pChunk->iNext;
1218 Chunk.iPrev = pChunk->iPrev;
1223 iChunk = (pChunk) ? pChunk->iNext : iINVALID;
1225 if (iChunk == iINVALID)
1229 l.cChunks = max (l.cChunks, 1+iChunk);
1233 if ((Chunk.iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1236 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(Chunk.iNext)) != NULL)
1237 pNext->iPrev = iChunk;
1239 l.aBuckets[iBucket].iFirst = iChunk;
1240 Chunk.iPrev = iINVALID;
1243 if (IsWindow (l.hManager))
1244 MemMgr_AddToList (&Chunk);
1246 l.pHeap->SetAt (iChunk, &Chunk);
1249 l.Stats.cAllocCpp ++;
1250 else // (!Chunk.fCPP)
1251 l.Stats.cAllocDyna ++;
1254 l.Stats.cbAllocCpp += Chunk.cbData;
1255 else // (!Chunk.fCPP)
1256 l.Stats.cbAllocDyna += Chunk.cbData;
1258 l.Stats.cAllocTotal ++;
1259 l.Stats.cbAllocTotal += Chunk.cbData;
1261 LeaveCriticalSection (l.pcs);
1263 if (IsWindow (l.hManager))
1264 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1268 BOOL MemMgr_TrackDestruction (PVOID pData, LPSTR pszFile, DWORD dwLine)
1270 if (MemMgr_Initialize())
1272 EnterCriticalSection (l.pcs);
1274 // Find the memchunk associated with this pData. That's what our
1275 // hash table is for.
1277 size_t iBucket = HASH(pData,l.cBuckets);
1279 PMEMCHUNK pChunk = NULL;
1280 for (size_t iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1282 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1284 if (pChunk->pData == pData)
1286 if ((iChunk = pChunk->iNext) == iINVALID)
1296 memset (&Sim, 0x00, sizeof(MEMCHUNK));
1298 Sim.pszExpr = "(unknown)";
1299 Sim.pszFile = "(unknown)";
1300 MemMgr_ShowWarning (&Sim, pszFile, dwLine, TEXT("An invalid memory address was freed."));
1302 else if (pChunk->dwEndSig && (*(DWORD*)((PBYTE)pData + pChunk->cbData) != pChunk->dwEndSig))
1304 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("The trailing signature on a block of memory was overwritten."));
1306 else if (pChunk->fFreed)
1308 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("A block of memory was freed more than once."));
1313 pChunk->fFreed = TRUE;
1315 if (IsWindow (l.hManager))
1317 if (pChunk->fInList)
1318 MemMgr_RemoveFromList (pChunk);
1322 l.Stats.cAllocCpp --;
1323 else // (!pChunk->fCPP)
1324 l.Stats.cAllocDyna --;
1327 l.Stats.cbAllocCpp -= pChunk->cbData;
1328 else // (!pChunk->fCPP)
1329 l.Stats.cbAllocDyna -= pChunk->cbData;
1331 l.Stats.cAllocTotal --;
1332 l.Stats.cbAllocTotal -= pChunk->cbData;
1336 // Unlink this chunk from the hash table
1338 if (pChunk->iNext != iINVALID)
1341 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1342 pNext->iPrev = pChunk->iPrev;
1344 if (pChunk->iPrev != iINVALID)
1347 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iPrev)) != NULL)
1348 pPrev->iNext = pChunk->iNext;
1350 if (l.aBuckets[iBucket].iFirst == iChunk)
1351 l.aBuckets[iBucket].iFirst = pChunk->iNext;
1353 // Empty this element in the expandarray. That means we need to
1354 // take the last element and shove it in here--so we'll have do
1355 // rework the hash table a little bit more.
1357 if (iChunk != l.cChunks-1)
1360 if ((pMove = (PMEMCHUNK)l.pHeap->GetAt(l.cChunks-1)) != NULL)
1362 size_t iBucket = HASH(pMove->pData,l.cBuckets);
1364 if (pMove->iNext != iINVALID)
1367 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pMove->iNext)) != NULL)
1368 pNext->iPrev = iChunk;
1370 if (pMove->iPrev != iINVALID)
1373 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pMove->iPrev)) != NULL)
1374 pPrev->iNext = iChunk;
1376 if (l.aBuckets[iBucket].iFirst == (l.cChunks-1))
1377 l.aBuckets[iBucket].iFirst = iChunk;
1379 l.pHeap->SetAt (iChunk, pMove);
1380 memset (pMove, 0x00, sizeof(MEMCHUNK));
1386 #endif // TRACK_FREED
1389 LeaveCriticalSection (l.pcs);
1392 if (IsWindow (l.hManager))
1393 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1399 * PUBLIC ROUTINES ____________________________________________________________
1403 void MEMMGR_CALLCONV ShowMemoryManager (void)
1405 if (MemMgr_Initialize())
1407 if (!IsWindow (l.hManager))
1409 MemMgr_RestoreSettings();
1410 l.hManager = MakeWindow (TEXT("Static"), cszTITLE, WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, &lr.rManager, 0, 0);
1411 SetWindowLong (l.hManager, GWL_WNDPROC, (LONG)MemMgr_DlgProc);
1412 PostMessage (l.hManager, WM_COMMAND, IDC_INITIALIZE, 0);
1413 ShowWindow (l.hManager, SW_SHOW);
1419 void MEMMGR_CALLCONV WhileMemoryManagerShowing (void)
1421 if (MemMgr_Initialize())
1423 while (IsWindow (l.hManager))
1426 if (!GetMessage (&msg, NULL, 0, 0))
1429 if (!IsDialogMessage (l.hManager, &msg))
1431 TranslateMessage (&msg);
1432 DispatchMessage (&msg);
1439 BOOL MEMMGR_CALLCONV IsMemoryManagerMessage (MSG *pMsg)
1441 if (IsWindow (l.hManager))
1443 if (pMsg->hwnd == l.hManager)
1445 // if (IsDialogMessage (l.hManager, pMsg))
1449 else if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_F8))
1451 ShowMemoryManager();
1458 PVOID MEMMGR_CALLCONV MemMgr_AllocateMemory (size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1460 PVOID pData = GlobalAlloc (GMEM_FIXED, cb + sizeof(DWORD));
1461 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, TRUE);
1466 void MEMMGR_CALLCONV MemMgr_FreeMemory (PVOID pData, LPSTR pszFile, DWORD dwLine)
1468 if (MemMgr_TrackDestruction (pData, pszFile, dwLine))
1470 GlobalFree ((HGLOBAL)pData);
1475 PVOID MEMMGR_CALLCONV MemMgr_TrackNew (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1477 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, FALSE);
1482 void MEMMGR_CALLCONV MemMgr_TrackDelete (PVOID pData, LPSTR pszFile, DWORD dwLine)
1484 MemMgr_TrackDestruction (pData, pszFile, dwLine);
1489 * EXPANDARRAY ________________________________________________________________
1491 * We'll use an EXPANDARRAY to manage our heap of allocation information.
1492 * Technically I would prefer to use a full HASHLIST here, but I don't want
1493 * this source file to be dependent upon yet another file. So we'll kinda
1494 * write a special-purpose hash system.
1498 #define cEXPANDARRAYHEAPELEMENTS 1024
1499 #define cREALLOC_EXPANDARRAYHEAPS 16
1501 ALLOCEXPANDARRAY::ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap)
1503 if ((m_cbElement = cbElement) == 0)
1504 m_cbElement = sizeof(DWORD);
1505 if ((m_cElementsPerHeap = cElementsPerHeap) == 0)
1506 m_cElementsPerHeap = cEXPANDARRAYHEAPELEMENTS;
1512 ALLOCEXPANDARRAY::~ALLOCEXPANDARRAY (void)
1516 for (size_t ii = 0; ii < m_cHeaps; ++ii)
1517 GlobalFree ((HGLOBAL)(m_aHeaps[ ii ]));
1518 GlobalFree ((HGLOBAL)m_aHeaps);
1522 PVOID ALLOCEXPANDARRAY::GetAt (size_t iElement)
1524 size_t iHeap = iElement / m_cElementsPerHeap;
1525 size_t iIndex = iElement % m_cElementsPerHeap;
1526 if ((iHeap >= m_cHeaps) || (!m_aHeaps[iHeap]))
1528 return (PVOID)&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ];
1531 void ALLOCEXPANDARRAY::SetAt (size_t iElement, PVOID pData)
1533 size_t iHeap = iElement / m_cElementsPerHeap;
1534 size_t iIndex = iElement % m_cElementsPerHeap;
1536 if (!REALLOC (m_aHeaps, m_cHeaps, 1+iHeap, cREALLOC_EXPANDARRAYHEAPS))
1539 if (!m_aHeaps[ iHeap ])
1541 size_t cbHeap = sizeof(EXPANDARRAYHEAP) + (m_cElementsPerHeap * m_cbElement);
1542 if ((m_aHeaps[ iHeap ] = (LPEXPANDARRAYHEAP)GlobalAlloc (GMEM_FIXED, cbHeap)) == NULL)
1544 memset (m_aHeaps[ iHeap ], 0x00, cbHeap);
1545 m_aHeaps[ iHeap ]->aElements = ((PBYTE)m_aHeaps[ iHeap ]) + sizeof(EXPANDARRAYHEAP);
1549 memset (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], 0x00, m_cbElement);
1551 memcpy (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], pData, m_cbElement);