source: trunk/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
RevLine 
[13]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/*
[297]14 * Copyright (C) 2000-2005 Ulrich M”ller.
[13]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
[123]49#include "helpers\tree.h"
50
[13]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
[123]60#include "helpers\nls.h"
[13]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
[91]110 ULONG ulAddress; // has pAfterMagic, invisible, only
111 // for sorting V0.9.14 (2001-08-01) [umoeller]
112
[13]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 }
[238]153 return 0;
[13]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
[238]196 return 1; // stop
[13]197 }
198
[238]199 return 0;
[13]200 }
201
202 /*
[142]203 *@@ CreateRecordsVAC:
[13]204 *
205 *@@added V0.9.3 (2000-04-10) [umoeller]
206 */
207
[142]208 VOID CreateRecordsVAC(HWND hwndCnr)
[13]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
[91]243 pMemRecordThis->ulAddress = (ULONG)pMemRecordThis->pObject;
244
245 sprintf(pMemRecordThis->szAddress,
246 "0x%lX",
247 pMemRecordThis->pObject);
248 strhcpy(pMemRecordThis->szSource,
[13]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/*
[142]269 *@@ CreateRecords:
[13]270 *
271 *@@added V0.9.3 (2000-04-10) [umoeller]
272 */
273
[222]274STATIC VOID CreateRecords(HWND hwndCnr,
[142]275 PULONG pulTotalItems,
276 PULONG pulAllocatedItems,
277 PULONG pulFreedItems,
278 PULONG pulTotalBytes,
279 PULONG pulAllocatedBytes,
280 PULONG pulFreedBytes)
[13]281{
282 // count heap items
[123]283 // ULONG ulHeapItemsCount1 = 0;
[13]284 PMEMRECORD pMemRecordFirst;
285
[123]286 ULONG cHeapItems = 0;
[297]287 volatile BOOL fLocked = FALSE; // XWP V1.0.4 (2005-10-09) [pr]
[123]288
289 TRY_LOUD(excpt1)
[13]290 {
[123]291 if (fLocked = memdLock())
292 {
293 PHEAPITEM pHeapItem = (PHEAPITEM)treeFirst(G_pHeapItemsRoot);
[13]294
[123]295 *pulTotalItems = 0;
296 *pulAllocatedItems = 0;
297 *pulFreedItems = 0;
[13]298
[123]299 *pulTotalBytes = 0;
300 *pulAllocatedBytes = 0;
301 *pulFreedBytes = 0;
[13]302
[123]303 *pulTotalItems = G_cHeapItems;
304
305 if (pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
306 sizeof(MEMRECORD),
307 G_cHeapItems))
[13]308 {
[123]309 PMEMRECORD pMemRecordThis = pMemRecordFirst;
310 pHeapItem = (PHEAPITEM)treeFirst(G_pHeapItemsRoot);
[13]311
[123]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 }
[13]324
[123]325 (*pulTotalBytes) += pHeapItem->ulSize;
[13]326
[123]327 pMemRecordThis->ulIndex = cHeapItems++;
[13]328
[123]329 cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
330 &pMemRecordThis->cdateAllocated,
331 &pMemRecordThis->ctimeAllocated);
[13]332
[123]333 if (pHeapItem->fFreed)
334 pMemRecordThis->pszFreed = "yes";
[13]335
[123]336 pMemRecordThis->ulTID = pHeapItem->ulTID;
[13]337
[123]338 strhcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
339 pMemRecordThis->pszSource = pMemRecordThis->szSource;
[13]340
[123]341 pMemRecordThis->ulLine = pHeapItem->ulLine;
[13]342
[123]343 strhcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
344 pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
[13]345
[123]346 pMemRecordThis->ulAddress = pHeapItem->Tree.ulKey;
[13]347
[123]348 sprintf(pMemRecordThis->szAddress,
349 "0x%lX",
350 pHeapItem->Tree.ulKey);
351 pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
[13]352
[123]353 pMemRecordThis->ulSize = pHeapItem->ulSize;
[13]354
[91]355
[123]356 /* switch (pMemRecordThis->useflag)
357 {
358 case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
359 case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
360 }
[13]361
[123]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 }
[13]369
[123]370 sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
371 strhcpy(pMemRecordThis->szSource,
372 (pMemRecordThis->filename)
373 ? pMemRecordThis->filename
374 : "?"); */
[13]375
[123]376 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
377 pHeapItem = (PHEAPITEM)treeNext((TREE*)pHeapItem);
[13]378 }
379
[123]380 cnrhInsertRecords(hwndCnr,
381 NULL, // parent
382 (PRECORDCORE)pMemRecordFirst,
383 TRUE,
384 NULL,
385 CRA_RECORDREADONLY,
386 cHeapItems);
[13]387 }
388 }
[123]389 }
390 CATCH(excpt1)
391 {
392 if (G_pMemdLogFunc)
393 {
394 CHAR szMsg[1000];
395 sprintf(szMsg,
[265]396 "Crash occurred at object #%d out of %d",
[123]397 cHeapItems,
398 G_cHeapItems);
399 G_pMemdLogFunc(szMsg);
400 }
401 } END_CATCH();
[13]402
[123]403 if (fLocked)
[13]404 memdUnlock();
405}
406
407/*
408 *@@ mnu_fnCompareIndex:
409 *
410 *@@added V0.9.1 (99-12-03) [umoeller]
411 */
412
[222]413STATIC SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
[13]414{
415 pStorage = pStorage; // to keep the compiler happy
416 if ((pmrc1) && (pmrc2))
417 if (pmrc1->ulIndex < pmrc2->ulIndex)
[238]418 return -1;
[13]419 else if (pmrc1->ulIndex > pmrc2->ulIndex)
[238]420 return 1;
[13]421
[238]422 return 0;
[13]423}
424
425/*
426 *@@ mnu_fnCompareSourceFile:
427 *
428 *@@added V0.9.1 (99-12-03) [umoeller]
429 */
430
[222]431STATIC SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
[13]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 {
[238]441 case WCS_LT: return -1;
442 case WCS_GT: return 1;
[13]443 default: // equal
444 if (pmrc1->ulLine < pmrc2->ulLine)
[238]445 return -1;
[13]446 else if (pmrc1->ulLine > pmrc2->ulLine)
[238]447 return 1;
[13]448
449 }
450
[238]451 return 0;
[13]452}
453
454/*
455 *@@ mnu_fnCompareSourceFile:
456 *
[91]457 *@@added V0.9.6 (2000-11-12) [umoeller]
[13]458 */
459
[222]460STATIC SHORT EXPENTRY mnu_fnCompareSize(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
[13]461{
462 pStorage = pStorage; // to keep the compiler happy
463 if ((pmrc1) && (pmrc2))
464 {
465 if (pmrc1->ulSize > pmrc2->ulSize)
[238]466 return 1;
[13]467 else if (pmrc1->ulSize < pmrc2->ulSize)
[238]468 return -1;
[13]469 }
470
[238]471 return 0;
[13]472}
473
[91]474/*
475 *@@ mnu_fnCompareAddress:
476 *
477 *@@added V0.9.14 (2001-08-01) [umoeller]
478 */
479
[222]480STATIC SHORT EXPENTRY mnu_fnCompareAddress(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
[91]481{
482 pStorage = pStorage; // to keep the compiler happy
483 if ((pmrc1) && (pmrc2))
484 {
485 if (pmrc1->ulAddress > pmrc2->ulAddress)
[238]486 return 1;
[91]487 else if (pmrc1->ulAddress < pmrc2->ulAddress)
[238]488 return -1;
[91]489 }
490
[238]491 return 0;
[91]492}
493
[13]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]
[91]511 *@@changed V0.9.14 (2001-08-01) [umoeller]: added sort by address
[13]512 */
513
[164]514MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
[13]515{
516 MRESULT mrc = 0;
517
518 switch (msg)
519 {
520 case WM_CREATE:
521 {
[71]522 TRY_LOUD(excpt1)
[13]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
[142]614 CreateRecords(hwndCnr,
615 &ulTotalItems,
616 &ulAllocatedItems,
617 &ulFreedItems,
618 &ulTotalBytes,
619 &ulAllocatedBytes,
620 &ulFreedBytes);
[13]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",
[123]638 nlsThousandsDouble(szTotalItems,
[13]639 ulTotalItems,
640 '.'),
[123]641 nlsThousandsDouble(szTotalBytes,
[13]642 ulTotalBytes,
643 '.'),
[123]644 nlsThousandsDouble(szAllocatedItems,
[13]645 ulAllocatedItems,
646 '.'),
[123]647 nlsThousandsDouble(szAllocatedBytes,
[13]648 ulAllocatedBytes,
649 '.'),
[123]650 nlsThousandsDouble(szFreedItems,
[13]651 ulFreedItems,
652 '.'),
[123]653 nlsThousandsDouble(szFreedBytes,
[13]654 ulFreedBytes,
655 '.'),
[123]656 nlsThousandsDouble(szReleasedItems,
[13]657 G_ulItemsReleased,
658 '.'),
[123]659 nlsThousandsDouble(szReleasedBytes,
[13]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);
[91]691 winhInsertMenuItem(G_hwndMemDebugMenu,
692 MIT_END,
693 1004,
694 "Sort by address",
695 MIS_TEXT, 0);
[13]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;
[91]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;
[13]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
[167]787 return mrc;
[13]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;
[91]843 i++;
[13]844}
[297]845#endif // __XWPMEMDEBUG__
[13]846
Note: See TracBrowser for help on using the repository browser.