11 #include <WINNT/tal_alloc.h>
15 * PARAMETERS _________________________________________________________________
19 #define cDEFAULT_BUCKETS 128
21 #define dwSIG_AT_END 'Okay'
23 #define iINVALID ((size_t)-1)
25 #define MIN_BUCKETS(_cObjects) ((_cObjects) / 23)
26 #define TARGET_BUCKETS(_cObjects) ((_cObjects) / 5)
30 #define cmsecREFRESH 1000
34 * DEFINITIONS ________________________________________________________________
40 PVOID aElements; // = EXPANDARRAYHEAP.aElements + 4;
41 // Followed by allocated space for aElements
42 } EXPANDARRAYHEAP, *LPEXPANDARRAYHEAP;
44 class ALLOCEXPANDARRAY
47 ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap = 0);
48 ~ALLOCEXPANDARRAY (void);
50 PVOID GetAt (size_t iElement);
51 void SetAt (size_t iElement, PVOID pData);
55 size_t m_cElementsPerHeap;
58 LPEXPANDARRAYHEAP *m_aHeaps;
76 } MEMCHUNK, *PMEMCHUNK;
90 LONG cAllocTotalTared;
95 LONG cbAllocDynaTared;
96 LONG cbAllocTotalTared;
101 CRITICAL_SECTION *pcs;
105 ALLOCEXPANDARRAY *pHeap;
122 #define HASH(_dw,_cTable) (((DWORD)(_dw) >> 4) % (_cTable))
126 * REALLOC ____________________________________________________________________
131 #define REALLOC(_a,_c,_r,_i) Alloc_ReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
132 BOOL Alloc_ReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
137 if (cReq <= *pcTarget)
140 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
143 if ((pNew = (LPVOID)GlobalAlloc (GMEM_FIXED, cbElement * cNew)) == NULL)
145 memset (pNew, 0x00, cbElement * cNew);
148 memset (pNew, 0x00, cbElement * cNew);
151 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
152 memset (&((char*)pNew)[ cbElement * (*pcTarget) ], 0x00, cbElement * (cNew - *pcTarget));
153 GlobalFree ((HGLOBAL)*ppTarget);
164 * USER INTERFACE ROUTINES ____________________________________________________
168 #define IDC_INITIALIZE 100
169 #define IDC_BOX_ALLOC 101
170 #define IDC_LABEL_CPP 102
171 #define IDC_LABEL_OTHER 103
172 #define IDC_LABEL_TARED 104
173 #define IDC_LABEL_TOTAL 106
174 #define IDC_LABEL_COUNT 107
175 #define IDC_LABEL_SIZE 108
176 #define IDC_LABEL_AVERAGE 109
177 #define IDC_VALUE_CPP_COUNT 110
178 #define IDC_VALUE_OTHER_COUNT 111
179 #define IDC_VALUE_TARED_COUNT 112
180 #define IDC_VALUE_TOTAL_COUNT 113
181 #define IDC_VALUE_CPP_SIZE 114
182 #define IDC_VALUE_OTHER_SIZE 115
183 #define IDC_VALUE_TARED_SIZE 116
184 #define IDC_VALUE_TOTAL_SIZE 117
185 #define IDC_VALUE_CPP_AVERAGE 118
186 #define IDC_VALUE_OTHER_AVERAGE 119
187 #define IDC_VALUE_TARED_AVERAGE 120
188 #define IDC_VALUE_TOTAL_AVERAGE 121
189 #define IDC_BOX_DETAILS 122
191 #define IDC_LABEL 124
194 #define IDC_RESET 127
195 #define IDC_REFRESH 128
196 #define IDC_LIST_ADD 129
197 #define IDC_LIST_REMOVE 130
198 #define IDC_LIST_REMOVEADD 131
200 #define cszTITLE TEXT("Memory Manager")
213 RECT rValueOtherCount;
214 RECT rValueTaredCount;
215 RECT rValueTotalCount;
217 RECT rValueOtherSize;
218 RECT rValueTaredSize;
219 RECT rValueTotalSize;
220 RECT rValueCppAverage;
221 RECT rValueOtherAverage;
222 RECT rValueTaredAverage;
223 RECT rValueTotalAverage;
243 HWND MakeWindow (LPCTSTR pszClass, LPCTSTR pszTitle, DWORD dwStyle, RECT *prSource, HWND hParent, UINT idc, DWORD dwStyleEx = 0)
245 RECT rr = { 0, 0, 16, 16 };
248 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);
250 SendMessage (hWnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 1);
254 void SetWindowRect (HWND hWnd, RECT *pr)
256 SetWindowPos (hWnd, 0, pr->left, pr->top, pr->right - pr->left, pr->bottom - pr->top, SWP_NOZORDER | SWP_NOACTIVATE);
259 void FormatBytes (LPTSTR pszText, double lfValue)
264 *pszText++ = TEXT('-');
267 if (lfValue >= 1048576)
269 LONG Value = (LONG)(lfValue / 1048576);
270 lfValue -= Value * 1048576;
271 LONG Frac = (LONG)(lfValue * 100 / 1048576);
272 wsprintf (pszText, TEXT("%ld.%ld MB"), Value, Frac);
274 else if (lfValue >= 3072)
276 LONG Value = (LONG)(lfValue / 1024);
277 lfValue -= Value * 1024;
278 LONG Frac = (LONG)(lfValue * 100 / 1024);
279 wsprintf (pszText, TEXT("%ld.%ld kb"), Value, Frac);
281 else // (lfValue < 3072)
283 wsprintf (pszText, TEXT("%ld b"), (LONG)lfValue);
287 void FormatTime (LPTSTR pszText, DWORD dwTick)
289 static FILETIME ftTickZero = { 0, 0 };
290 if (!ftTickZero.dwHighDateTime && !ftTickZero.dwLowDateTime)
292 // We need to find out what FILETIME corresponds with a tick
293 // count of zero. To do that, first find the FILETIME and tick
294 // count that represent *now* (in local time).
297 GetLocalTime (&stNow);
298 SystemTimeToFileTime (&stNow, &ftTickZero);
300 DWORD dwTickNow = GetTickCount();
302 // A FILETIME is a count-of-100ns-intervals, and a tick count is
303 // a count of 1ms-intervals. So we need to subtract off a big
304 // number times our tick count.
306 if ((dwTickNow * 10000) < (dwTickNow))
307 ftTickZero.dwHighDateTime --;
308 dwTickNow *= 10000; // convert to 100ns intervals
309 if (dwTickNow > ftTickZero.dwLowDateTime)
310 ftTickZero.dwHighDateTime --;
311 ftTickZero.dwLowDateTime -= dwTickNow; // unsigned, so it'll wrap OK
314 // Convert the given tick count into 100ns intervals, and add it
315 // to our ftTickZero.
317 FILETIME ftTick = ftTickZero;
319 if ((dwTick * 10000) < (dwTick))
320 ftTick.dwHighDateTime ++;
321 dwTick *= 10000; // convert to 100ns intervals
322 if (dwTick > (DWORD)(0-ftTick.dwLowDateTime)) // too big to add?
323 ftTick.dwHighDateTime ++;
324 ftTick.dwLowDateTime += dwTick; // unsigned, so it'll wrap OK
326 // Convert to a SYSTEMTIME, and output the time component
329 FileTimeToSystemTime (&ftTick, &stTick);
331 wsprintf (pszText, TEXT("%ld:%02ld:%02ld.%02ld"),
333 (DWORD)stTick.wMinute,
334 (DWORD)stTick.wSecond,
335 (DWORD)(stTick.wMilliseconds / 100));
338 void SetDlgItemBytes (HWND hDlg, int idc, double lfValue)
341 FormatBytes (szText, lfValue);
342 SetDlgItemText (hDlg, idc, szText);
346 void MemMgr_ShowWarning (PMEMCHUNK pChunk, LPSTR pszFile, DWORD dwLine, LPTSTR pszDesc)
348 TCHAR szMessage[ 1024 ];
349 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);
350 if (MessageBox (NULL, szMessage, cszTITLE, MB_ICONHAND | MB_OKCANCEL | MB_DEFBUTTON2) == IDOK)
352 // TODO: Show Details
356 void MIX (RECT *pr, RECT *pr1, RECT *pr2)
358 pr->left = pr2->left;
360 pr->right = pr2->right;
361 pr->bottom = pr1->bottom;
364 void MemMgr_GetWindowSizes (WINDOWSIZES *pSizes)
367 GetClientRect (l.hManager, &rClient);
368 InflateRect (&rClient, 0-cBORDER, 0-cBORDER);
370 pSizes->rLabelAverage.right = rClient.right -cxBETWEEN*2;
371 pSizes->rLabelAverage.top = rClient.top +8 +cyBETWEEN;
372 pSizes->rLabelAverage.left = pSizes->rLabelAverage.right -cxVALUES;
373 pSizes->rLabelAverage.bottom = pSizes->rLabelAverage.top +cyLABELS;
375 pSizes->rLabelSize = pSizes->rLabelAverage;
376 pSizes->rLabelSize.left -= cxBETWEEN + cxVALUES;
377 pSizes->rLabelSize.right -= cxBETWEEN + cxVALUES;
379 pSizes->rLabelCount = pSizes->rLabelSize;
380 pSizes->rLabelCount.left -= cxBETWEEN + cxVALUES;
381 pSizes->rLabelCount.right -= cxBETWEEN + cxVALUES;
383 pSizes->rLabelCpp.left = rClient.left +cxBETWEEN;
384 pSizes->rLabelCpp.top = pSizes->rLabelCount.bottom +cyBETWEEN;
385 pSizes->rLabelCpp.right = pSizes->rLabelCpp.left +cxLABELS;
386 pSizes->rLabelCpp.bottom = pSizes->rLabelCpp.top +cyLABELS;
388 pSizes->rLabelOther = pSizes->rLabelCpp;
389 pSizes->rLabelOther.top += cyBETWEEN + cyLABELS;
390 pSizes->rLabelOther.bottom += cyBETWEEN + cyLABELS;
392 pSizes->rLabelTotal = pSizes->rLabelOther;
393 pSizes->rLabelTotal.top += cyBETWEEN + cyLABELS;
394 pSizes->rLabelTotal.bottom += cyBETWEEN + cyLABELS;
396 pSizes->rLabelTared = pSizes->rLabelTotal;
397 pSizes->rLabelTared.top += cyBETWEEN + cyLABELS;
398 pSizes->rLabelTared.bottom += cyBETWEEN + cyLABELS;
400 pSizes->rBoxAlloc = rClient;
401 pSizes->rBoxAlloc.bottom = pSizes->rLabelTared.bottom +cyBETWEEN;
403 MIX (&pSizes->rValueCppCount, &pSizes->rLabelCpp, &pSizes->rLabelCount);
404 MIX (&pSizes->rValueOtherCount, &pSizes->rLabelOther, &pSizes->rLabelCount);
405 MIX (&pSizes->rValueTaredCount, &pSizes->rLabelTared, &pSizes->rLabelCount);
406 MIX (&pSizes->rValueTotalCount, &pSizes->rLabelTotal, &pSizes->rLabelCount);
408 MIX (&pSizes->rValueCppSize, &pSizes->rLabelCpp, &pSizes->rLabelSize);
409 MIX (&pSizes->rValueOtherSize, &pSizes->rLabelOther, &pSizes->rLabelSize);
410 MIX (&pSizes->rValueTaredSize, &pSizes->rLabelTared, &pSizes->rLabelSize);
411 MIX (&pSizes->rValueTotalSize, &pSizes->rLabelTotal, &pSizes->rLabelSize);
413 MIX (&pSizes->rValueCppAverage, &pSizes->rLabelCpp, &pSizes->rLabelAverage);
414 MIX (&pSizes->rValueOtherAverage, &pSizes->rLabelOther, &pSizes->rLabelAverage);
415 MIX (&pSizes->rValueTaredAverage, &pSizes->rLabelTared, &pSizes->rLabelAverage);
416 MIX (&pSizes->rValueTotalAverage, &pSizes->rLabelTotal, &pSizes->rLabelAverage);
418 pSizes->rBoxDetails = rClient;
419 pSizes->rBoxDetails.top = pSizes->rBoxAlloc.bottom +cyBETWEEN;
420 pSizes->rBoxDetails.bottom -= cyBUTTONS +cyBETWEEN;
422 pSizes->rList = pSizes->rBoxDetails;
423 pSizes->rList.top += 8;
424 InflateRect (&pSizes->rList, 0-cBORDER, 0-cBORDER);
426 pSizes->rClose = rClient;
427 pSizes->rClose.top = pSizes->rClose.bottom - cyBUTTONS;
428 pSizes->rClose.left = pSizes->rClose.right - cxBUTTONS;
430 pSizes->rReset = pSizes->rClose;
431 pSizes->rReset.right = pSizes->rClose.left - cxBETWEEN;
432 pSizes->rReset.left = pSizes->rReset.right - cxBUTTONS;
434 pSizes->rTare = pSizes->rClose;
435 pSizes->rTare.right = pSizes->rReset.left - cxBETWEEN;
436 pSizes->rTare.left = pSizes->rTare.right - cxBUTTONS;
438 pSizes->rLabel = pSizes->rTare;
439 pSizes->rLabel.right = pSizes->rTare.left - cxBETWEEN;
440 pSizes->rLabel.left = pSizes->rLabel.right - cxBUTTONS;
442 pSizes->rHide = pSizes->rLabel;
443 pSizes->rHide.right = pSizes->rLabel.left - cxBETWEEN;
444 pSizes->rHide.left = pSizes->rHide.right - cxBUTTONS;
447 void MemMgr_OnSize (void)
450 MemMgr_GetWindowSizes (&Sizes);
451 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_ALLOC), &Sizes.rBoxAlloc);
452 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_CPP), &Sizes.rLabelCpp);
453 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_OTHER), &Sizes.rLabelOther);
454 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TARED), &Sizes.rLabelTared);
455 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_TOTAL), &Sizes.rLabelTotal);
456 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_COUNT), &Sizes.rLabelCount);
457 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_SIZE), &Sizes.rLabelSize);
458 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL_AVERAGE), &Sizes.rLabelAverage);
459 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_COUNT), &Sizes.rValueCppCount);
460 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_COUNT), &Sizes.rValueOtherCount);
461 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_COUNT), &Sizes.rValueTaredCount);
462 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_COUNT), &Sizes.rValueTotalCount);
463 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_SIZE), &Sizes.rValueCppSize);
464 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_SIZE), &Sizes.rValueOtherSize);
465 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_SIZE), &Sizes.rValueTaredSize);
466 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_SIZE), &Sizes.rValueTotalSize);
467 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_CPP_AVERAGE), &Sizes.rValueCppAverage);
468 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_OTHER_AVERAGE), &Sizes.rValueOtherAverage);
469 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TARED_AVERAGE), &Sizes.rValueTaredAverage);
470 SetWindowRect (GetDlgItem (l.hManager, IDC_VALUE_TOTAL_AVERAGE), &Sizes.rValueTotalAverage);
471 SetWindowRect (GetDlgItem (l.hManager, IDC_BOX_DETAILS), &Sizes.rBoxDetails);
472 SetWindowRect (GetDlgItem (l.hManager, IDC_LIST), &Sizes.rList);
473 SetWindowRect (GetDlgItem (l.hManager, IDC_LABEL), &Sizes.rLabel);
474 SetWindowRect (GetDlgItem (l.hManager, IDC_HIDE), &Sizes.rHide);
475 SetWindowRect (GetDlgItem (l.hManager, IDC_TARE), &Sizes.rTare);
476 SetWindowRect (GetDlgItem (l.hManager, IDC_RESET), &Sizes.rReset);
477 SetWindowRect (GetDlgItem (l.hManager, IDCANCEL), &Sizes.rClose);
481 void MemMgr_OnListRemove (PVOID pData)
483 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
486 Find.flags = LVFI_PARAM;
487 Find.lParam = (LPARAM)pData;
490 if ((iItem = ListView_FindItem (hList, 0, &Find)) == -1)
492 // The listview's find feature sucks; I've seen with my own little
493 // eyes that it may miss an item if it's the only one in a list.
494 // Look for ourselves.
496 int cItems = ListView_GetItemCount(hList);
497 for (iItem = 0; iItem < cItems; ++iItem)
501 Item.mask = LVIF_PARAM;
502 ListView_GetItem (hList, &Item);
503 if (Item.lParam == (LPARAM)pData)
510 ListView_DeleteItem (hList, iItem);
515 void MemMgr_RemoveFromList (PMEMCHUNK pChunk)
517 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVE, (LPARAM)(pChunk->pData));
518 pChunk->fInList = FALSE;
522 LPTSTR MemMgr_GetItemKey (HWND hList, int iItem)
524 static TCHAR szText[ 256 ];
525 LPTSTR pszReturn = NULL;
534 Item.mask = LVIF_PARAM;
535 ListView_GetItem (hList, &Item);
537 EnterCriticalSection (l.pcs);
540 iBucket = HASH(Item.lParam,l.cBuckets);
546 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
548 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
550 if (pChunk->pData == (PVOID)Item.lParam)
552 if ((iChunk = pChunk->iNext) == iINVALID)
561 if (lr.iColSort == 0)
562 pszReturn = (LPTSTR)pChunk->dwTick;
563 else if (lr.iColSort == 4)
564 pszReturn = (LPTSTR)pChunk->cbData;
565 else // (lr.iColSort == 5)
566 pszReturn = (LPTSTR)pChunk->pData;
569 LeaveCriticalSection (l.pcs);
573 ListView_GetItemText (hList, iItem, lr.iColSort, szText, 256);
582 int MemMgr_CompareItems (LPTSTR pszKey1, LPTSTR pszKey2)
591 dw = (int)( (DWORD)pszKey1 - (DWORD)pszKey2 );
595 dw = lstrcmpi (pszKey1, pszKey2);
599 return (lr.fSortRev) ? (0-dw) : dw;
603 int MemMgr_PickListInsertionPoint (HWND hList, LPTSTR pszKey)
606 int iItemHigh = ListView_GetItemCount (hList) -1;
608 while (iItemLow <= iItemHigh)
610 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
612 LPTSTR pszAlternate = MemMgr_GetItemKey (hList, iItemTest);
614 int iCompare = MemMgr_CompareItems (pszKey, pszAlternate);
617 if ((iItemHigh = iItemTest-1) < iItemLow)
622 if ((iItemLow = iItemTest+1) > iItemHigh)
631 void MemMgr_OnListAdd (PMEMCHUNK pCopy)
633 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
636 FormatTime (szTime, pCopy->dwTick);
639 LPTSTR pszFlags = szFlags;
640 *pszFlags++ = (pCopy->fCPP) ? TEXT('C') : TEXT(' ');
641 *pszFlags++ = TEXT(' ');
642 *pszFlags++ = (pCopy->fFreed) ? TEXT('F') : TEXT(' ');
646 lstrcpy (szExpr, (pCopy->pszExpr) ? pCopy->pszExpr : TEXT("unknown"));
648 LPTSTR pszFile = pCopy->pszFile;
649 for (LPTSTR psz = pCopy->pszFile; *psz; ++psz)
651 if ((*psz == TEXT(':')) || (*psz == TEXT('\\')))
654 TCHAR szLocation[256];
655 if (!pszFile || !pCopy->dwLine)
656 lstrcpy (szLocation, TEXT("unknown"));
658 wsprintf (szLocation, TEXT("%s, %ld"), pszFile, pCopy->dwLine);
661 FormatBytes (szBytes, pCopy->cbData);
663 TCHAR szAddress[256];
664 wsprintf (szAddress, TEXT("0x%08lX"), pCopy->pData);
666 LPTSTR pszKey = NULL;
669 case 0: pszKey = (LPTSTR)pCopy->dwTick; break;
670 case 1: pszKey = (LPTSTR)szFlags; break;
671 case 2: pszKey = (LPTSTR)szExpr; break;
672 case 3: pszKey = (LPTSTR)szLocation; break;
673 case 4: pszKey = (LPTSTR)pCopy->cbData; break;
674 case 5: pszKey = (LPTSTR)pCopy->pData; break;
678 memset (&Item, 0x00, sizeof(Item));
679 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
680 Item.iItem = MemMgr_PickListInsertionPoint (hList, pszKey);
682 Item.cchTextMax = 256;
683 Item.lParam = (LPARAM)pCopy->pData;
685 Item.pszText = szTime;
686 DWORD iItem = ListView_InsertItem (hList, &Item);
687 ListView_SetItemText (hList, iItem, 1, szFlags);
688 ListView_SetItemText (hList, iItem, 2, szExpr);
689 ListView_SetItemText (hList, iItem, 3, szLocation);
690 ListView_SetItemText (hList, iItem, 4, szBytes);
691 ListView_SetItemText (hList, iItem, 5, szAddress);
697 void MemMgr_AddToList (PMEMCHUNK pChunk)
699 PMEMCHUNK pCopy = new MEMCHUNK;
700 memcpy (pCopy, pChunk, sizeof(MEMCHUNK));
703 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_REMOVEADD, (LPARAM)pCopy);
705 PostMessage (l.hManager, WM_COMMAND, IDC_LIST_ADD, (LPARAM)pCopy);
706 pChunk->fInList = TRUE;
710 void MemMgr_RestoreSettings (void)
712 lr.rManager.left = 0;
714 lr.rManager.right = 510;
715 lr.rManager.bottom = 440;
716 lr.acxColumns[0] = 70;
717 lr.acxColumns[1] = 40;
718 lr.acxColumns[2] = 100;
719 lr.acxColumns[3] = 110;
720 lr.acxColumns[4] = 50;
721 lr.acxColumns[5] = 80;
726 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
728 DWORD dwType = REG_BINARY;
729 DWORD dwSize = sizeof(lr);
730 RegQueryValueEx (hk, TEXT("Settings"), 0, &dwType, (PBYTE)&lr, &dwSize);
735 void MemMgr_StoreSettings (void)
737 if (IsWindow (l.hManager))
739 GetWindowRect (l.hManager, &lr.rManager);
741 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
742 if (IsWindow (hList))
744 for (size_t ii = 0; ii < 6; ++ii)
745 lr.acxColumns[ ii ] = ListView_GetColumnWidth (hList, ii);
750 if (RegCreateKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Random\\MemMgr"), &hk) == 0)
752 RegSetValueEx (hk, TEXT("Settings"), 0, REG_BINARY, (PBYTE)&lr, sizeof(lr));
757 void MemMgr_OnInit (void)
759 DWORD dwFlags = WS_CHILD | WS_TABSTOP | WS_VISIBLE;
760 MakeWindow (TEXT("Button"), TEXT("Allocation Statistics"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_ALLOC);
761 MakeWindow (TEXT("Static"), TEXT("C++ Objects:"), dwFlags, NULL, l.hManager, IDC_LABEL_CPP);
762 MakeWindow (TEXT("Static"), TEXT("Dynamic:"), dwFlags, NULL, l.hManager, IDC_LABEL_OTHER);
763 MakeWindow (TEXT("Static"), TEXT("Combined:"), dwFlags, NULL, l.hManager, IDC_LABEL_TOTAL);
764 MakeWindow (TEXT("Static"), TEXT("Tared:"), dwFlags, NULL, l.hManager, IDC_LABEL_TARED);
765 MakeWindow (TEXT("Static"), TEXT("Count"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_COUNT);
766 MakeWindow (TEXT("Static"), TEXT("Size"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_SIZE);
767 MakeWindow (TEXT("Static"), TEXT("Average"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_LABEL_AVERAGE);
768 MakeWindow (TEXT("Static"), TEXT("0"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_COUNT);
769 MakeWindow (TEXT("Static"), TEXT("1"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_COUNT);
770 MakeWindow (TEXT("Static"), TEXT("2"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_COUNT);
771 MakeWindow (TEXT("Static"), TEXT("3"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_COUNT);
772 MakeWindow (TEXT("Static"), TEXT("4"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_SIZE);
773 MakeWindow (TEXT("Static"), TEXT("5"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_SIZE);
774 MakeWindow (TEXT("Static"), TEXT("6"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_SIZE);
775 MakeWindow (TEXT("Static"), TEXT("7"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_SIZE);
776 MakeWindow (TEXT("Static"), TEXT("8"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_CPP_AVERAGE);
777 MakeWindow (TEXT("Static"), TEXT("9"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_OTHER_AVERAGE);
778 MakeWindow (TEXT("Static"), TEXT("10"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TARED_AVERAGE);
779 MakeWindow (TEXT("Static"), TEXT("11"), dwFlags | SS_CENTER, NULL, l.hManager, IDC_VALUE_TOTAL_AVERAGE);
780 MakeWindow (TEXT("Button"), TEXT("Details"), dwFlags | BS_GROUPBOX, NULL, l.hManager, IDC_BOX_DETAILS);
781 MakeWindow (WC_LISTVIEW, TEXT(""), dwFlags | LVS_REPORT | LVS_SINGLESEL, NULL, l.hManager, IDC_LIST, WS_EX_CLIENTEDGE);
782 // MakeWindow (TEXT("Button"), TEXT("Label"), dwFlags, NULL, l.hManager, IDC_LABEL);
783 // MakeWindow (TEXT("Button"), TEXT("Hidden"), dwFlags, NULL, l.hManager, IDC_HIDE);
784 MakeWindow (TEXT("Button"), TEXT("Tare"), dwFlags, NULL, l.hManager, IDC_TARE);
785 MakeWindow (TEXT("Button"), TEXT("Restore"), dwFlags, NULL, l.hManager, IDC_RESET);
786 MakeWindow (TEXT("Button"), TEXT("Close"), dwFlags, NULL, l.hManager, IDCANCEL);
789 HWND hList = GetDlgItem (l.hManager, IDC_LIST);
792 Col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM;
793 Col.fmt = LVCFMT_LEFT;
795 Col.cx = lr.acxColumns[0];
796 Col.pszText = TEXT("Time");
797 ListView_InsertColumn (hList, Col.iSubItem, &Col);
799 Col.cx = lr.acxColumns[1];
800 Col.pszText = TEXT("Flags");
802 ListView_InsertColumn (hList, Col.iSubItem, &Col);
804 Col.cx = lr.acxColumns[2];
805 Col.pszText = TEXT("Expression");
807 ListView_InsertColumn (hList, Col.iSubItem, &Col);
809 Col.cx = lr.acxColumns[3];
810 Col.pszText = TEXT("Location");
812 ListView_InsertColumn (hList, Col.iSubItem, &Col);
814 Col.fmt = LVCFMT_RIGHT;
815 Col.cx = lr.acxColumns[4];
816 Col.pszText = TEXT("Size");
818 ListView_InsertColumn (hList, Col.iSubItem, &Col);
820 Col.cx = lr.acxColumns[5];
821 Col.pszText = TEXT("Address");
823 ListView_InsertColumn (hList, Col.iSubItem, &Col);
825 EnterCriticalSection (l.pcs);
826 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
828 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
831 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
834 pChunk->fInList = FALSE;
835 if (!pChunk->fTared && !pChunk->fFreed)
836 MemMgr_AddToList (pChunk);
839 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
840 LeaveCriticalSection (l.pcs);
842 l.idTimer = SetTimer (l.hManager, 0, cmsecREFRESH, NULL);
845 void MemMgr_OnRefresh (void)
847 // Fill in the statistics at the top of the manager dialog
849 SetDlgItemInt (l.hManager, IDC_VALUE_CPP_COUNT, l.Stats.cAllocCpp, TRUE);
850 SetDlgItemInt (l.hManager, IDC_VALUE_OTHER_COUNT, l.Stats.cAllocDyna, TRUE);
851 SetDlgItemInt (l.hManager, IDC_VALUE_TARED_COUNT, l.Stats.cAllocTotalTared, TRUE);
852 SetDlgItemInt (l.hManager, IDC_VALUE_TOTAL_COUNT, l.Stats.cAllocTotal, TRUE);
854 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_SIZE, (double)l.Stats.cbAllocCpp);
855 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_SIZE, (double)l.Stats.cbAllocDyna);
856 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_SIZE, (double)l.Stats.cbAllocTotalTared);
857 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_SIZE, (double)l.Stats.cbAllocTotal);
859 SetDlgItemBytes (l.hManager, IDC_VALUE_CPP_AVERAGE, (l.Stats.cAllocCpp) ? ((double)l.Stats.cbAllocCpp / l.Stats.cAllocCpp) : 0);
860 SetDlgItemBytes (l.hManager, IDC_VALUE_OTHER_AVERAGE, (l.Stats.cAllocDyna) ? ((double)l.Stats.cbAllocDyna / l.Stats.cAllocDyna) : 0);
861 SetDlgItemBytes (l.hManager, IDC_VALUE_TARED_AVERAGE, (l.Stats.cAllocTotalTared) ? ((double)l.Stats.cbAllocTotalTared / l.Stats.cAllocTotalTared) : 0);
862 SetDlgItemBytes (l.hManager, IDC_VALUE_TOTAL_AVERAGE, (l.Stats.cAllocTotal) ? ((double)l.Stats.cbAllocTotal / l.Stats.cAllocTotal) : 0);
865 void MemMgr_OnLabel (void)
870 void MemMgr_OnHide (void)
875 void MemMgr_OnReset (void)
877 l.Stats.cAllocCpp += l.Stats.cAllocCppTared;
878 l.Stats.cAllocDyna += l.Stats.cAllocDynaTared;
879 l.Stats.cAllocTotal += l.Stats.cAllocTotalTared;
880 l.Stats.cbAllocCpp += l.Stats.cbAllocCppTared;
881 l.Stats.cbAllocDyna += l.Stats.cbAllocDynaTared;
882 l.Stats.cbAllocTotal += l.Stats.cbAllocTotalTared;
884 l.Stats.cAllocCppTared = 0;
885 l.Stats.cAllocDynaTared = 0;
886 l.Stats.cAllocTotalTared = 0;
887 l.Stats.cbAllocCppTared = 0;
888 l.Stats.cbAllocDynaTared = 0;
889 l.Stats.cbAllocTotalTared = 0;
891 EnterCriticalSection (l.pcs);
892 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
894 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
896 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
899 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
902 pChunk->fInList = FALSE;
903 pChunk->fTared = FALSE;
905 MemMgr_AddToList (pChunk);
908 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
909 LeaveCriticalSection (l.pcs);
914 void MemMgr_OnTare (void)
916 l.Stats.cAllocCppTared += l.Stats.cAllocCpp;
917 l.Stats.cAllocDynaTared += l.Stats.cAllocDyna;
918 l.Stats.cAllocTotalTared += l.Stats.cAllocTotal;
919 l.Stats.cbAllocCppTared += l.Stats.cbAllocCpp;
920 l.Stats.cbAllocDynaTared += l.Stats.cbAllocDyna;
921 l.Stats.cbAllocTotalTared += l.Stats.cbAllocTotal;
923 l.Stats.cAllocCpp = 0;
924 l.Stats.cAllocDyna = 0;
925 l.Stats.cAllocTotal = 0;
926 l.Stats.cbAllocCpp = 0;
927 l.Stats.cbAllocDyna = 0;
928 l.Stats.cbAllocTotal = 0;
930 EnterCriticalSection (l.pcs);
931 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
933 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
935 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
938 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
941 pChunk->fInList = FALSE;
942 pChunk->fTared = TRUE;
945 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
946 LeaveCriticalSection (l.pcs);
952 void MemMgr_OnSort (void)
954 EnterCriticalSection (l.pcs);
955 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, FALSE, 0);
957 ListView_DeleteAllItems (GetDlgItem (l.hManager, IDC_LIST));
959 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
962 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
965 pChunk->fInList = FALSE;
966 if (!pChunk->fTared && !pChunk->fFreed)
967 MemMgr_AddToList (pChunk);
970 SendMessage (GetDlgItem (l.hManager, IDC_LIST), WM_SETREDRAW, TRUE, 0);
971 LeaveCriticalSection (l.pcs);
975 void MemMgr_OnPaint (void)
978 HDC hdc = BeginPaint (l.hManager, &ps);
980 static HBRUSH hbr = (HBRUSH)CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
981 FillRect (hdc, &ps.rcPaint, hbr);
983 EndPaint (l.hManager, &ps);
987 void MemMgr_OnTimer (void)
989 if (GetWindowLong (l.hManager, GWL_USERDATA))
991 SetWindowLong (l.hManager, GWL_USERDATA, 0);
997 void MemMgr_OnDelayedRefresh (void)
999 SetWindowLong (l.hManager, GWL_USERDATA, 1);
1003 BOOL CALLBACK MemMgr_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1008 MemMgr_StoreSettings();
1010 KillTimer (hDlg, l.idTimer);
1016 MemMgr_StoreSettings();
1020 MemMgr_StoreSettings();
1023 case WM_GETMINMAXINFO:
1025 lpmmi = (LPMINMAXINFO)lp;
1026 lpmmi->ptMinTrackSize.x = cxBUTTONS*5 + cxBETWEEN*4 + cBORDER*2 + 8;
1027 lpmmi->ptMinTrackSize.y = 270;
1035 switch (((NMHDR *)lp)->code)
1037 case LVN_COLUMNCLICK:
1038 if (((NM_LISTVIEW*)lp)->iSubItem == lr.iColSort)
1039 lr.fSortRev = !lr.fSortRev;
1042 lr.iColSort = ((NM_LISTVIEW*)lp)->iSubItem;
1043 lr.fSortRev = FALSE;
1046 MemMgr_StoreSettings();
1059 DestroyWindow (hDlg);
1062 case IDC_INITIALIZE:
1068 MemMgr_OnDelayedRefresh();
1087 case IDC_LIST_REMOVEADD:
1088 MemMgr_OnListRemove (((PMEMCHUNK)lp)->pData);
1089 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1093 MemMgr_OnListAdd ((PMEMCHUNK)lp);
1096 case IDC_LIST_REMOVE:
1097 MemMgr_OnListRemove ((PVOID)lp);
1103 return DefWindowProc (hDlg, msg, wp, lp);
1108 * MANAGEMENT ROUTINES ________________________________________________________
1112 BOOL MemMgr_Initialize (void)
1116 l.pcs = new CRITICAL_SECTION;
1117 InitializeCriticalSection (l.pcs);
1119 l.pHeap = new ALLOCEXPANDARRAY (sizeof(MEMCHUNK));
1121 REALLOC (l.aBuckets, l.cBuckets, cDEFAULT_BUCKETS, 1);
1124 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1125 l.aBuckets[ii].iFirst = iINVALID;
1129 return (l.pHeap) && (l.aBuckets);
1133 void MemMgr_TrackAllocation (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine, BOOL fSig)
1137 if (!MemMgr_Initialize())
1140 EnterCriticalSection (l.pcs);
1142 // Ensure our hash table will be large enough to handle the new
1143 // MEMCHUNK we're about to assign.
1145 if (l.cBuckets < MIN_BUCKETS(l.cChunks+1))
1147 // Too small! Rebuild the hash table.
1149 REALLOC (l.aBuckets, l.cBuckets, TARGET_BUCKETS(l.cChunks+1), 1);
1152 for (size_t ii = 0; ii < l.cBuckets; ++ii)
1153 l.aBuckets[ii].iFirst = iINVALID;
1155 for (size_t iChunk = 0; iChunk < l.cChunks; ++iChunk)
1158 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1161 size_t iBucket = HASH(pChunk->pData,l.cBuckets);
1162 if ((pChunk->iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1165 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1166 pNext->iPrev = iChunk;
1168 l.aBuckets[iBucket].iFirst = iChunk;
1169 pChunk->iPrev = iINVALID;
1174 // If space was allocated for a trailing signature, write one
1177 *(DWORD *)( (PBYTE)pData + cb ) = dwSIG_AT_END;
1179 // Prepare a MEMCHUNK entry and shove it in our array
1181 size_t iChunk = l.cChunks;
1182 size_t iBucket = HASH(pData,l.cBuckets);
1183 BOOL fLinkIn = TRUE;
1186 Chunk.pData = pData;
1187 Chunk.fFreed = FALSE;
1189 Chunk.pszExpr = pszExpr;
1190 Chunk.pszFile = pszFile;
1192 Chunk.dwLine = dwLine;
1193 Chunk.dwTick = GetTickCount();
1194 Chunk.dwEndSig = (fSig) ? dwSIG_AT_END : 0;
1195 Chunk.fInList = FALSE;
1196 Chunk.fTared = FALSE;
1199 // Find the memchunk associated with this pData. That's what our
1200 // hash table is for.
1202 for (iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1205 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) != NULL)
1207 if (pChunk->pData == pData)
1209 Chunk.iNext = pChunk->iNext;
1210 Chunk.iPrev = pChunk->iPrev;
1215 iChunk = (pChunk) ? pChunk->iNext : iINVALID;
1217 if (iChunk == iINVALID)
1221 l.cChunks = max (l.cChunks, 1+iChunk);
1225 if ((Chunk.iNext = l.aBuckets[iBucket].iFirst) != iINVALID)
1228 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(Chunk.iNext)) != NULL)
1229 pNext->iPrev = iChunk;
1231 l.aBuckets[iBucket].iFirst = iChunk;
1232 Chunk.iPrev = iINVALID;
1235 if (IsWindow (l.hManager))
1236 MemMgr_AddToList (&Chunk);
1238 l.pHeap->SetAt (iChunk, &Chunk);
1241 l.Stats.cAllocCpp ++;
1242 else // (!Chunk.fCPP)
1243 l.Stats.cAllocDyna ++;
1246 l.Stats.cbAllocCpp += Chunk.cbData;
1247 else // (!Chunk.fCPP)
1248 l.Stats.cbAllocDyna += Chunk.cbData;
1250 l.Stats.cAllocTotal ++;
1251 l.Stats.cbAllocTotal += Chunk.cbData;
1253 LeaveCriticalSection (l.pcs);
1255 if (IsWindow (l.hManager))
1256 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1260 BOOL MemMgr_TrackDestruction (PVOID pData, LPSTR pszFile, DWORD dwLine)
1262 if (MemMgr_Initialize())
1264 EnterCriticalSection (l.pcs);
1266 // Find the memchunk associated with this pData. That's what our
1267 // hash table is for.
1269 size_t iBucket = HASH(pData,l.cBuckets);
1271 PMEMCHUNK pChunk = NULL;
1272 for (size_t iChunk = l.aBuckets[iBucket].iFirst; iChunk != iINVALID; )
1274 if ((pChunk = (PMEMCHUNK)l.pHeap->GetAt(iChunk)) == NULL)
1276 if (pChunk->pData == pData)
1278 if ((iChunk = pChunk->iNext) == iINVALID)
1288 memset (&Sim, 0x00, sizeof(MEMCHUNK));
1290 Sim.pszExpr = "(unknown)";
1291 Sim.pszFile = "(unknown)";
1292 MemMgr_ShowWarning (&Sim, pszFile, dwLine, TEXT("An invalid memory address was freed."));
1294 else if (pChunk->dwEndSig && (*(DWORD*)((PBYTE)pData + pChunk->cbData) != pChunk->dwEndSig))
1296 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("The trailing signature on a block of memory was overwritten."));
1298 else if (pChunk->fFreed)
1300 MemMgr_ShowWarning (pChunk, pszFile, dwLine, TEXT("A block of memory was freed more than once."));
1305 pChunk->fFreed = TRUE;
1307 if (IsWindow (l.hManager))
1309 if (pChunk->fInList)
1310 MemMgr_RemoveFromList (pChunk);
1314 l.Stats.cAllocCpp --;
1315 else // (!pChunk->fCPP)
1316 l.Stats.cAllocDyna --;
1319 l.Stats.cbAllocCpp -= pChunk->cbData;
1320 else // (!pChunk->fCPP)
1321 l.Stats.cbAllocDyna -= pChunk->cbData;
1323 l.Stats.cAllocTotal --;
1324 l.Stats.cbAllocTotal -= pChunk->cbData;
1328 // Unlink this chunk from the hash table
1330 if (pChunk->iNext != iINVALID)
1333 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iNext)) != NULL)
1334 pNext->iPrev = pChunk->iPrev;
1336 if (pChunk->iPrev != iINVALID)
1339 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pChunk->iPrev)) != NULL)
1340 pPrev->iNext = pChunk->iNext;
1342 if (l.aBuckets[iBucket].iFirst == iChunk)
1343 l.aBuckets[iBucket].iFirst = pChunk->iNext;
1345 // Empty this element in the expandarray. That means we need to
1346 // take the last element and shove it in here--so we'll have do
1347 // rework the hash table a little bit more.
1349 if (iChunk != l.cChunks-1)
1352 if ((pMove = (PMEMCHUNK)l.pHeap->GetAt(l.cChunks-1)) != NULL)
1354 size_t iBucket = HASH(pMove->pData,l.cBuckets);
1356 if (pMove->iNext != iINVALID)
1359 if ((pNext = (PMEMCHUNK)l.pHeap->GetAt(pMove->iNext)) != NULL)
1360 pNext->iPrev = iChunk;
1362 if (pMove->iPrev != iINVALID)
1365 if ((pPrev = (PMEMCHUNK)l.pHeap->GetAt(pMove->iPrev)) != NULL)
1366 pPrev->iNext = iChunk;
1368 if (l.aBuckets[iBucket].iFirst == (l.cChunks-1))
1369 l.aBuckets[iBucket].iFirst = iChunk;
1371 l.pHeap->SetAt (iChunk, pMove);
1372 memset (pMove, 0x00, sizeof(MEMCHUNK));
1378 #endif // TRACK_FREED
1381 LeaveCriticalSection (l.pcs);
1384 if (IsWindow (l.hManager))
1385 PostMessage (l.hManager, WM_COMMAND, IDC_REFRESH, 0);
1391 * PUBLIC ROUTINES ____________________________________________________________
1395 void MEMMGR_CALLCONV ShowMemoryManager (void)
1397 if (MemMgr_Initialize())
1399 if (!IsWindow (l.hManager))
1401 MemMgr_RestoreSettings();
1402 l.hManager = MakeWindow (TEXT("Static"), cszTITLE, WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU, &lr.rManager, 0, 0);
1403 SetWindowLong (l.hManager, GWL_WNDPROC, (LONG)MemMgr_DlgProc);
1404 PostMessage (l.hManager, WM_COMMAND, IDC_INITIALIZE, 0);
1405 ShowWindow (l.hManager, SW_SHOW);
1411 void MEMMGR_CALLCONV WhileMemoryManagerShowing (void)
1413 if (MemMgr_Initialize())
1415 while (IsWindow (l.hManager))
1418 if (!GetMessage (&msg, NULL, 0, 0))
1421 if (!IsDialogMessage (l.hManager, &msg))
1423 TranslateMessage (&msg);
1424 DispatchMessage (&msg);
1431 BOOL MEMMGR_CALLCONV IsMemoryManagerMessage (MSG *pMsg)
1433 if (IsWindow (l.hManager))
1435 if (pMsg->hwnd == l.hManager)
1437 // if (IsDialogMessage (l.hManager, pMsg))
1441 else if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_F8))
1443 ShowMemoryManager();
1450 PVOID MEMMGR_CALLCONV MemMgr_AllocateMemory (size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1452 PVOID pData = GlobalAlloc (GMEM_FIXED, cb + sizeof(DWORD));
1453 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, TRUE);
1458 void MEMMGR_CALLCONV MemMgr_FreeMemory (PVOID pData, LPSTR pszFile, DWORD dwLine)
1460 if (MemMgr_TrackDestruction (pData, pszFile, dwLine))
1462 GlobalFree ((HGLOBAL)pData);
1467 PVOID MEMMGR_CALLCONV MemMgr_TrackNew (PVOID pData, size_t cb, LPSTR pszExpr, LPSTR pszFile, DWORD dwLine)
1469 MemMgr_TrackAllocation (pData, cb, pszExpr, pszFile, dwLine, FALSE);
1474 void MEMMGR_CALLCONV MemMgr_TrackDelete (PVOID pData, LPSTR pszFile, DWORD dwLine)
1476 MemMgr_TrackDestruction (pData, pszFile, dwLine);
1481 * EXPANDARRAY ________________________________________________________________
1483 * We'll use an EXPANDARRAY to manage our heap of allocation information.
1484 * Technically I would prefer to use a full HASHLIST here, but I don't want
1485 * this source file to be dependent upon yet another file. So we'll kinda
1486 * write a special-purpose hash system.
1490 #define cEXPANDARRAYHEAPELEMENTS 1024
1491 #define cREALLOC_EXPANDARRAYHEAPS 16
1493 ALLOCEXPANDARRAY::ALLOCEXPANDARRAY (size_t cbElement, size_t cElementsPerHeap)
1495 if ((m_cbElement = cbElement) == 0)
1496 m_cbElement = sizeof(DWORD);
1497 if ((m_cElementsPerHeap = cElementsPerHeap) == 0)
1498 m_cElementsPerHeap = cEXPANDARRAYHEAPELEMENTS;
1504 ALLOCEXPANDARRAY::~ALLOCEXPANDARRAY (void)
1508 for (size_t ii = 0; ii < m_cHeaps; ++ii)
1509 GlobalFree ((HGLOBAL)(m_aHeaps[ ii ]));
1510 GlobalFree ((HGLOBAL)m_aHeaps);
1514 PVOID ALLOCEXPANDARRAY::GetAt (size_t iElement)
1516 size_t iHeap = iElement / m_cElementsPerHeap;
1517 size_t iIndex = iElement % m_cElementsPerHeap;
1518 if ((iHeap >= m_cHeaps) || (!m_aHeaps[iHeap]))
1520 return (PVOID)&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ];
1523 void ALLOCEXPANDARRAY::SetAt (size_t iElement, PVOID pData)
1525 size_t iHeap = iElement / m_cElementsPerHeap;
1526 size_t iIndex = iElement % m_cElementsPerHeap;
1528 if (!REALLOC (m_aHeaps, m_cHeaps, 1+iHeap, cREALLOC_EXPANDARRAYHEAPS))
1531 if (!m_aHeaps[ iHeap ])
1533 size_t cbHeap = sizeof(EXPANDARRAYHEAP) + (m_cElementsPerHeap * m_cbElement);
1534 if ((m_aHeaps[ iHeap ] = (LPEXPANDARRAYHEAP)GlobalAlloc (GMEM_FIXED, cbHeap)) == NULL)
1536 memset (m_aHeaps[ iHeap ], 0x00, cbHeap);
1537 m_aHeaps[ iHeap ]->aElements = ((PBYTE)m_aHeaps[ iHeap ]) + sizeof(EXPANDARRAYHEAP);
1541 memset (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], 0x00, m_cbElement);
1543 memcpy (&((PBYTE)m_aHeaps[ iHeap ]->aElements)[ iIndex * m_cbElement ], pData, m_cbElement);