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

Last change on this file since 108 was 91, checked in by umoeller, 24 years ago

Misc changes

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