source: branches/branch-1-0/src/helpers/memdebug_win.c

Last change on this file was 297, checked in by pr, 20 years ago

Update functions using exception handlers to force non-register variables

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