source: trunk/src/helpers/memdebug_win.c@ 22

Last change on this file since 22 was 13, checked in by umoeller, 25 years ago

Updates for V0.9.6.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 28.1 KB
Line 
1
2/*
3 *@@sourcefile memdebug_win.c:
4 * implementation of the PM heap debugging window,
5 * if the __XWPMEMDEBUG__ #define is set in setup.h.
6 *
7 * This has been extracted from memdebug.c to allow
8 * linking with non-PM programs.
9 *
10 *@@added V0.9.6 (2000-11-12) [umoeller]
11 */
12
13/*
14 * Copyright (C) 2000 Ulrich M”ller.
15 * This program is part of the XWorkplace package.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, in version 2 as it comes in the COPYING
19 * file of the XWorkplace main distribution.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 */
25
26#define OS2EMX_PLAIN_CHAR
27 // this is needed for "os2emx.h"; if this is defined,
28 // emx will define PSZ as _signed_ char, otherwise
29 // as unsigned char
30
31#define INCL_DOSSEMAPHORES
32#define INCL_DOSEXCEPTIONS
33#define INCL_DOSPROCESS
34#define INCL_DOSERRORS
35
36#define INCL_WINWINDOWMGR
37#define INCL_WINFRAMEMGR
38#define INCL_WINCOUNTRY
39#define INCL_WINSYS
40#define INCL_WINMENUS
41#define INCL_WINSTDCNR
42#include <os2.h>
43
44#include <stdio.h>
45#include <string.h>
46// #include <malloc.h>
47#include <setjmp.h>
48
49#define DONT_REPLACE_MALLOC // never do debug memory for this
50#define MEMDEBUG_PRIVATE
51#include "setup.h"
52
53#ifdef __XWPMEMDEBUG__
54
55#include "helpers\cnrh.h"
56#include "helpers\except.h"
57// #include "helpers\memdebug.h" // included by setup.h already
58#include "helpers\stringh.h"
59#include "helpers\winh.h"
60
61/*
62 *@@category: Helpers\C helpers\Heap debugging
63 */
64
65/* ******************************************************************
66 *
67 * Global variables
68 *
69 ********************************************************************/
70
71PSZ G_pszMemCnrTitle = NULL;
72HWND G_hwndMemDebugMenu = NULLHANDLE;
73
74/* ******************************************************************
75 *
76 * Heap debugging window
77 *
78 ********************************************************************/
79
80/*
81 *@@ MEMRECORD:
82 *
83 *@@added V0.9.1 (99-12-04) [umoeller]
84 */
85
86typedef struct _MEMRECORD
87{
88 RECORDCORE recc;
89
90 ULONG ulIndex;
91
92 CDATE cdateAllocated;
93 CTIME ctimeAllocated;
94
95 PSZ pszFreed;
96
97 ULONG ulTID;
98
99 PSZ pszFunction; // points to szFunction
100 CHAR szFunction[400];
101
102 PSZ pszSource; // points to szSource
103 CHAR szSource[CCHMAXPATH];
104
105 ULONG ulLine;
106
107 PSZ pszAddress; // points to szAddress
108 CHAR szAddress[20];
109
110 ULONG ulSize;
111
112} MEMRECORD, *PMEMRECORD;
113
114/* ULONG ulHeapItemsCount1,
115 ulHeapItemsCount2;
116ULONG ulTotalAllocated,
117 ulTotalFreed;
118PMEMRECORD pMemRecordThis = NULL;
119PSZ pszMemCnrTitle = NULL; */
120
121#if 0
122 /*
123 *@@ fncbMemHeapWalkCount:
124 * callback func for _heap_walk function used for
125 * fnwpMemDebug.
126 *
127 *@@added V0.9.1 (99-12-04) [umoeller]
128 */
129
130 int fncbMemHeapWalkCount(const void *pObject,
131 size_t Size,
132 int useflag,
133 int status,
134 const char *filename,
135 size_t line)
136 {
137 // skip all the items which seem to be
138 // internal to the runtime
139 if ((filename) || (useflag == _FREEENTRY))
140 {
141 ulHeapItemsCount1++;
142 if (useflag == _FREEENTRY)
143 ulTotalFreed += Size;
144 else
145 ulTotalAllocated += Size;
146 }
147 return (0);
148 }
149
150 /*
151 *@@ fncbMemHeapWalkFill:
152 * callback func for _heap_walk function used for
153 * fnwpMemDebug.
154 *
155 *@@added V0.9.1 (99-12-04) [umoeller]
156 */
157
158 int fncbMemHeapWalkFill(const void *pObject,
159 size_t Size,
160 int useflag,
161 int status,
162 const char *filename,
163 size_t line)
164 {
165 // skip all the items which seem to be
166 // internal to the runtime
167 if ((filename) || (useflag == _FREEENTRY))
168 {
169 ulHeapItemsCount2++;
170 if ((pMemRecordThis) && (ulHeapItemsCount2 < ulHeapItemsCount1))
171 {
172 pMemRecordThis->ulIndex = ulHeapItemsCount2 - 1;
173
174 pMemRecordThis->pObject = pObject;
175 pMemRecordThis->useflag = useflag;
176 pMemRecordThis->status = status;
177 pMemRecordThis->filename = filename;
178
179 pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
180
181 pMemRecordThis->ulSize = Size;
182
183 pMemRecordThis->pszSource = pMemRecordThis->szSource;
184
185 pMemRecordThis->ulLine = line;
186
187 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
188 }
189 else
190 return (1); // stop
191 }
192
193 return (0);
194 }
195
196 /*
197 *@@ memdCreateRecordsVAC:
198 *
199 *@@added V0.9.3 (2000-04-10) [umoeller]
200 */
201
202 VOID memdCreateRecordsVAC(HWND hwndCnr)
203 {
204 // count heap items
205 ulHeapItemsCount1 = 0;
206 ulTotalFreed = 0;
207 ulTotalAllocated = 0;
208 _heap_walk(fncbMemHeapWalkCount);
209
210 pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
211 sizeof(MEMRECORD),
212 ulHeapItemsCount1);
213 if (pMemRecordFirst)
214 {
215 ulHeapItemsCount2 = 0;
216 pMemRecordThis = pMemRecordFirst;
217 _heap_walk(fncbMemHeapWalkFill);
218
219 // the following doesn't work while _heap_walk is running
220 pMemRecordThis = pMemRecordFirst;
221 while (pMemRecordThis)
222 {
223 switch (pMemRecordThis->useflag)
224 {
225 case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
226 case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
227 }
228
229 switch (pMemRecordThis->status)
230 {
231 case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
232 case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
233 case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
234 case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
235 }
236
237 sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
238 strcpy(pMemRecordThis->szSource,
239 (pMemRecordThis->filename)
240 ? pMemRecordThis->filename
241 : "?");
242
243 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
244 }
245
246 cnrhInsertRecords(hwndCnr,
247 NULL, // parent
248 (PRECORDCORE)pMemRecordFirst,
249 TRUE,
250 NULL,
251 CRA_RECORDREADONLY,
252 ulHeapItemsCount2);
253 }
254 }
255
256#endif
257
258/*
259 *@@ memdCreateRecords:
260 *
261 *@@added V0.9.3 (2000-04-10) [umoeller]
262 */
263
264VOID memdCreateRecords(HWND hwndCnr,
265 PULONG pulTotalItems,
266 PULONG pulAllocatedItems,
267 PULONG pulFreedItems,
268 PULONG pulTotalBytes,
269 PULONG pulAllocatedBytes,
270 PULONG pulFreedBytes)
271{
272 // count heap items
273 ULONG ulHeapItemsCount1 = 0;
274 PMEMRECORD pMemRecordFirst;
275
276 if (memdLock())
277 {
278 PHEAPITEM pHeapItem = G_pHeapItemsRoot;
279
280 *pulTotalItems = 0;
281 *pulAllocatedItems = 0;
282 *pulFreedItems = 0;
283
284 *pulTotalBytes = 0;
285 *pulAllocatedBytes = 0;
286 *pulFreedBytes = 0;
287
288 while (pHeapItem)
289 {
290 ulHeapItemsCount1++;
291 if (pHeapItem->fFreed)
292 {
293 (*pulFreedItems)++;
294 (*pulFreedBytes) += pHeapItem->ulSize;
295 }
296 else
297 {
298 (*pulAllocatedItems)++;
299 (*pulAllocatedBytes) += pHeapItem->ulSize;
300 }
301
302 (*pulTotalBytes) += pHeapItem->ulSize;
303
304 pHeapItem = pHeapItem->pNext;
305 }
306
307 *pulTotalItems = ulHeapItemsCount1;
308
309 pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
310 sizeof(MEMRECORD),
311 ulHeapItemsCount1);
312 if (pMemRecordFirst)
313 {
314 ULONG ulHeapItemsCount2 = 0;
315 PMEMRECORD pMemRecordThis = pMemRecordFirst;
316 pHeapItem = G_pHeapItemsRoot;
317 // PLISTNODE pMemNode = lstQueryFirstNode(&G_llHeapItems);
318
319 while ((pMemRecordThis) && (pHeapItem))
320 {
321 // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;
322
323 pMemRecordThis->ulIndex = ulHeapItemsCount2++;
324
325 cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
326 &pMemRecordThis->cdateAllocated,
327 &pMemRecordThis->ctimeAllocated);
328
329 if (pHeapItem->fFreed)
330 pMemRecordThis->pszFreed = "yes";
331
332 pMemRecordThis->ulTID = pHeapItem->ulTID;
333
334 strcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
335 pMemRecordThis->pszSource = pMemRecordThis->szSource;
336
337 pMemRecordThis->ulLine = pHeapItem->ulLine;
338
339 strcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
340 pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
341
342 sprintf(pMemRecordThis->szAddress, "0x%lX", pHeapItem->pAfterMagic);
343 pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
344
345 pMemRecordThis->ulSize = pHeapItem->ulSize;
346
347
348 /* switch (pMemRecordThis->useflag)
349 {
350 case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
351 case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
352 }
353
354 switch (pMemRecordThis->status)
355 {
356 case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
357 case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
358 case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
359 case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
360 }
361
362 sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
363 strcpy(pMemRecordThis->szSource,
364 (pMemRecordThis->filename)
365 ? pMemRecordThis->filename
366 : "?"); */
367
368 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
369 pHeapItem = pHeapItem->pNext;
370 }
371
372 cnrhInsertRecords(hwndCnr,
373 NULL, // parent
374 (PRECORDCORE)pMemRecordFirst,
375 TRUE,
376 NULL,
377 CRA_RECORDREADONLY,
378 ulHeapItemsCount2);
379 }
380
381 memdUnlock();
382 }
383}
384
385/*
386 *@@ mnu_fnCompareIndex:
387 *
388 *@@added V0.9.1 (99-12-03) [umoeller]
389 */
390
391SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
392{
393 // HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
394 pStorage = pStorage; // to keep the compiler happy
395 if ((pmrc1) && (pmrc2))
396 if (pmrc1->ulIndex < pmrc2->ulIndex)
397 return (-1);
398 else if (pmrc1->ulIndex > pmrc2->ulIndex)
399 return (1);
400
401 return (0);
402}
403
404/*
405 *@@ mnu_fnCompareSourceFile:
406 *
407 *@@added V0.9.1 (99-12-03) [umoeller]
408 */
409
410SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
411{
412 HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
413 pStorage = pStorage; // to keep the compiler happy
414 if ((pmrc1) && (pmrc2))
415 switch (WinCompareStrings(habDesktop, 0, 0,
416 pmrc1->szSource,
417 pmrc2->szSource,
418 0))
419 {
420 case WCS_LT: return (-1);
421 case WCS_GT: return (1);
422 default: // equal
423 if (pmrc1->ulLine < pmrc2->ulLine)
424 return (-1);
425 else if (pmrc1->ulLine > pmrc2->ulLine)
426 return (1);
427
428 }
429
430 return (0);
431}
432
433/*
434 *@@ mnu_fnCompareSourceFile:
435 *
436 *V0.9.6 (2000-11-12) [umoeller]
437 */
438
439SHORT EXPENTRY mnu_fnCompareSize(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
440{
441 HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
442 pStorage = pStorage; // to keep the compiler happy
443 if ((pmrc1) && (pmrc2))
444 {
445 if (pmrc1->ulSize > pmrc2->ulSize)
446 return (1);
447 else if (pmrc1->ulSize < pmrc2->ulSize)
448 return (-1);
449 }
450
451 return (0);
452}
453
454#define ID_MEMCNR 1000
455
456/*
457 *@@ memd_fnwpMemDebug:
458 * client window proc for the heap debugger window
459 * accessible from the Desktop context menu if
460 * __XWPMEMDEBUG__ is defined. Otherwise, this is not
461 * compiled.
462 *
463 * Usage: this is a regular PM client window procedure
464 * to be used with WinRegisterClass and WinCreateStdWindow.
465 * See dtpMenuItemSelected, which uses this.
466 *
467 * This creates a container with all the memory objects
468 * with the size of the client area in turn.
469 *
470 *@@added V0.9.1 (99-12-04) [umoeller]
471 */
472
473MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
474{
475 MRESULT mrc = 0;
476
477 switch (msg)
478 {
479 case WM_CREATE:
480 {
481 TRY_LOUD(excpt1, NULL)
482 {
483 // PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
484 HWND hwndCnr;
485 hwndCnr = WinCreateWindow(hwndClient, // parent
486 WC_CONTAINER,
487 "",
488 WS_VISIBLE | CCS_MINIICONS | CCS_READONLY | CCS_SINGLESEL,
489 0, 0, 0, 0,
490 hwndClient, // owner
491 HWND_TOP,
492 ID_MEMCNR,
493 NULL, NULL);
494 if (hwndCnr)
495 {
496 XFIELDINFO xfi[11];
497 PFIELDINFO pfi = NULL;
498 PMEMRECORD pMemRecordFirst;
499 int i = 0;
500
501 ULONG ulTotalItems = 0,
502 ulAllocatedItems = 0,
503 ulFreedItems = 0;
504 ULONG ulTotalBytes = 0,
505 ulAllocatedBytes = 0,
506 ulFreedBytes = 0;
507
508 // set up cnr details view
509 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulIndex);
510 xfi[i].pszColumnTitle = "No.";
511 xfi[i].ulDataType = CFA_ULONG;
512 xfi[i++].ulOrientation = CFA_RIGHT;
513
514 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, cdateAllocated);
515 xfi[i].pszColumnTitle = "Date";
516 xfi[i].ulDataType = CFA_DATE;
517 xfi[i++].ulOrientation = CFA_LEFT;
518
519 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ctimeAllocated);
520 xfi[i].pszColumnTitle = "Time";
521 xfi[i].ulDataType = CFA_TIME;
522 xfi[i++].ulOrientation = CFA_LEFT;
523
524 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFreed);
525 xfi[i].pszColumnTitle = "Freed";
526 xfi[i].ulDataType = CFA_STRING;
527 xfi[i++].ulOrientation = CFA_CENTER;
528
529 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulTID);
530 xfi[i].pszColumnTitle = "TID";
531 xfi[i].ulDataType = CFA_ULONG;
532 xfi[i++].ulOrientation = CFA_RIGHT;
533
534 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFunction);
535 xfi[i].pszColumnTitle = "Function";
536 xfi[i].ulDataType = CFA_STRING;
537 xfi[i++].ulOrientation = CFA_LEFT;
538
539 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszSource);
540 xfi[i].pszColumnTitle = "Source";
541 xfi[i].ulDataType = CFA_STRING;
542 xfi[i++].ulOrientation = CFA_LEFT;
543
544 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulLine);
545 xfi[i].pszColumnTitle = "Line";
546 xfi[i].ulDataType = CFA_ULONG;
547 xfi[i++].ulOrientation = CFA_RIGHT;
548
549 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulSize);
550 xfi[i].pszColumnTitle = "Size";
551 xfi[i].ulDataType = CFA_ULONG;
552 xfi[i++].ulOrientation = CFA_RIGHT;
553
554 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszAddress);
555 xfi[i].pszColumnTitle = "Address";
556 xfi[i].ulDataType = CFA_STRING;
557 xfi[i++].ulOrientation = CFA_LEFT;
558
559 pfi = cnrhSetFieldInfos(hwndCnr,
560 &xfi[0],
561 i, // array item count
562 TRUE, // no draw lines
563 3); // return column
564
565 {
566 PSZ pszFont = "9.WarpSans";
567 WinSetPresParam(hwndCnr,
568 PP_FONTNAMESIZE,
569 strlen(pszFont),
570 pszFont);
571 }
572
573 memdCreateRecords(hwndCnr,
574 &ulTotalItems,
575 &ulAllocatedItems,
576 &ulFreedItems,
577 &ulTotalBytes,
578 &ulAllocatedBytes,
579 &ulFreedBytes);
580
581 BEGIN_CNRINFO()
582 {
583 CHAR szCnrTitle[1000];
584 CHAR szTotalItems[100],
585 szAllocatedItems[100],
586 szFreedItems[100],
587 szReleasedItems[100];
588 CHAR szTotalBytes[100],
589 szAllocatedBytes[100],
590 szFreedBytes[100],
591 szReleasedBytes[100];
592 sprintf(szCnrTitle,
593 "Total memory log entries in use: %s items = %s bytes\n"
594 " Total memory logs allocated: %s items = %s bytes\n"
595 " Total memory logs freed: %s items = %s bytes\n"
596 "Total memory logs freed and discarded: %s items = %s bytes",
597 strhThousandsDouble(szTotalItems,
598 ulTotalItems,
599 '.'),
600 strhThousandsDouble(szTotalBytes,
601 ulTotalBytes,
602 '.'),
603 strhThousandsDouble(szAllocatedItems,
604 ulAllocatedItems,
605 '.'),
606 strhThousandsDouble(szAllocatedBytes,
607 ulAllocatedBytes,
608 '.'),
609 strhThousandsDouble(szFreedItems,
610 ulFreedItems,
611 '.'),
612 strhThousandsDouble(szFreedBytes,
613 ulFreedBytes,
614 '.'),
615 strhThousandsDouble(szReleasedItems,
616 G_ulItemsReleased,
617 '.'),
618 strhThousandsDouble(szReleasedBytes,
619 G_ulBytesReleased,
620 '.'));
621 G_pszMemCnrTitle = strdup(szCnrTitle);
622 cnrhSetTitle(G_pszMemCnrTitle);
623 cnrhSetView(CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES
624 | CA_DRAWICON
625 | CA_CONTAINERTITLE | CA_TITLEREADONLY
626 | CA_TITLESEPARATOR | CA_TITLELEFT);
627 cnrhSetSplitBarAfter(pfi);
628 cnrhSetSplitBarPos(250);
629 } END_CNRINFO(hwndCnr);
630
631 // create menu
632 G_hwndMemDebugMenu = WinCreateMenu(HWND_DESKTOP,
633 NULL); // no menu template
634
635 winhInsertMenuItem(G_hwndMemDebugMenu,
636 MIT_END,
637 1001,
638 "Sort by index",
639 MIS_TEXT, 0);
640 winhInsertMenuItem(G_hwndMemDebugMenu,
641 MIT_END,
642 1002,
643 "Sort by source file",
644 MIS_TEXT, 0);
645 winhInsertMenuItem(G_hwndMemDebugMenu,
646 MIT_END,
647 1003,
648 "Sort by object size",
649 MIS_TEXT, 0);
650
651 WinSetFocus(HWND_DESKTOP, hwndCnr);
652 }
653 }
654 CATCH(excpt1) {} END_CATCH();
655
656 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
657 break; }
658
659 case WM_WINDOWPOSCHANGED:
660 {
661 PSWP pswp = (PSWP)mp1;
662 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
663 if (pswp->fl & SWP_SIZE)
664 {
665 WinSetWindowPos(WinWindowFromID(hwndClient, ID_MEMCNR), // cnr
666 HWND_TOP,
667 0, 0, pswp->cx, pswp->cy,
668 SWP_SIZE | SWP_MOVE | SWP_SHOW);
669 }
670 break; }
671
672 case WM_CONTROL:
673 {
674 USHORT usItemID = SHORT1FROMMP(mp1),
675 usNotifyCode = SHORT2FROMMP(mp1);
676 if (usItemID == ID_MEMCNR) // cnr
677 {
678 switch (usNotifyCode)
679 {
680 case CN_CONTEXTMENU:
681 {
682 PMEMRECORD precc = (PMEMRECORD)mp2;
683 if (precc == NULL)
684 {
685 // whitespace:
686 cnrhShowContextMenu(WinWindowFromID(hwndClient, ID_MEMCNR),
687 NULL, // record
688 G_hwndMemDebugMenu,
689 hwndClient);
690 }
691 }
692 }
693 }
694 break; }
695
696 case WM_COMMAND:
697 switch (SHORT1FROMMP(mp1))
698 {
699 case 1001: // sort by index
700 WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
701 CM_SORTRECORD,
702 (MPARAM)mnu_fnCompareIndex,
703 0);
704 break;
705
706 case 1002: // sort by source file
707 WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
708 CM_SORTRECORD,
709 (MPARAM)mnu_fnCompareSourceFile,
710 0);
711 break;
712
713 case 1003: // sort by object size
714 WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
715 CM_SORTRECORD,
716 (MPARAM)mnu_fnCompareSize,
717 0);
718 break;
719 }
720 break;
721
722 case WM_CLOSE:
723 WinDestroyWindow(WinWindowFromID(hwndClient, ID_MEMCNR));
724 WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT));
725 free(G_pszMemCnrTitle);
726 WinDestroyWindow(G_hwndMemDebugMenu);
727 G_pszMemCnrTitle = NULL;
728 break;
729
730 default:
731 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
732 }
733
734 return (mrc);
735}
736
737/*
738 *@@ memdCreateMemDebugWindow:
739 * creates a heap debugging window which
740 * is a standard frame with a container,
741 * listing all heap objects ever allocated.
742 *
743 * The client of this standard frame is in
744 * memd_fnwpMemDebug.
745 *
746 * This thing lists all calls to malloc()
747 * which were ever made, including the
748 * source file and source line number which
749 * made the call. Extreeeemely useful for
750 * detecting memory leaks.
751 *
752 * This only works if the memory functions
753 * have been replaced with the debug versions
754 * in this file.
755 */
756
757VOID memdCreateMemDebugWindow(VOID)
758{
759 ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_HIDEMAX
760 | FCF_SIZEBORDER | FCF_SHELLPOSITION
761 | FCF_NOBYTEALIGN | FCF_TASKLIST;
762 if (WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),
763 "XWPMemDebug",
764 memd_fnwpMemDebug, 0L, 0))
765 {
766 HWND hwndClient;
767 HWND hwndMemFrame = WinCreateStdWindow(HWND_DESKTOP,
768 0L,
769 &flStyle,
770 "XWPMemDebug",
771 "Allocated XWorkplace Memory Objects",
772 0L,
773 NULLHANDLE, // resource
774 0,
775 &hwndClient);
776 if (hwndMemFrame)
777 {
778 WinSetWindowPos(hwndMemFrame,
779 HWND_TOP,
780 0, 0, 0, 0,
781 SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);
782 }
783 }
784}
785
786#else
787void memdDummy2(void)
788{
789 int i = 0;
790}
791#endif
792
Note: See TracBrowser for help on using the repository browser.