1 |
|
---|
2 | /*
|
---|
3 | * memdebug.c:
|
---|
4 | * memory debugging helpers. Memory debugging is enabled
|
---|
5 | * if the __XWPMEMDEBUG__ #define is set in setup.h.
|
---|
6 | *
|
---|
7 | * Several things are in here which might turn out to
|
---|
8 | * be useful:
|
---|
9 | *
|
---|
10 | * -- Memory block dumping (memdDumpMemoryBlock).
|
---|
11 | *
|
---|
12 | * -- Sophisticated heap debugging functions, which
|
---|
13 | * automatically replace malloc() and free() etc.
|
---|
14 | * when XWorkplace is compiled with debug code.
|
---|
15 | * These log every memory allocation made and log
|
---|
16 | * much more data compared to the VAC++ memory
|
---|
17 | * debugging functions. See HEAPITEM for details.
|
---|
18 | * Automatic heap checking is also included, using
|
---|
19 | * special "magic string" which are checked to
|
---|
20 | * detect overwrites.
|
---|
21 | *
|
---|
22 | * To be able to trace memory errors, set the global
|
---|
23 | * variable G_pMemdLogFunc to a function which can
|
---|
24 | * write an error string to a meaningful place (the
|
---|
25 | * screen or a file). WARNING: While that error function
|
---|
26 | * is executed, the system might be in a global memory
|
---|
27 | * lock, so DON'T display a message box while in that
|
---|
28 | * function.
|
---|
29 | *
|
---|
30 | * At present, malloc(), calloc(), strdup() and free()
|
---|
31 | * are supported. If you invoke free() on a memory block
|
---|
32 | * allocated by a function other than the above, you'll
|
---|
33 | * get a runtime error.
|
---|
34 | *
|
---|
35 | * These debug functions have been added with V0.9.3
|
---|
36 | * and should now be compiler-independent.
|
---|
37 | *
|
---|
38 | * -- A PM heap debugging window which shows the statuzs
|
---|
39 | * of the heap logging list. See memdCreateMemDebugWindow
|
---|
40 | * for details.
|
---|
41 | *
|
---|
42 | * To enable memory debugging, do the following:
|
---|
43 | *
|
---|
44 | * 1) Include at least <stdlib.h> and <string.h>.
|
---|
45 | *
|
---|
46 | * 2) Include memdebug.h AFTER those two. This will remap
|
---|
47 | * the malloc() etc. calls.
|
---|
48 | *
|
---|
49 | * If you don't want those replaced, add
|
---|
50 | + #define DONT_REPLACE_MALLOC
|
---|
51 | * before including memdebug.h.
|
---|
52 | *
|
---|
53 | * That's all. XWorkplace's setup.h does this automatically
|
---|
54 | * if XWorkplace is compiled with debug code.
|
---|
55 | *
|
---|
56 | *@@added V0.9.1 (2000-02-12) [umoeller]
|
---|
57 | */
|
---|
58 |
|
---|
59 | /*
|
---|
60 | * Copyright (C) 2000 Ulrich Mller.
|
---|
61 | * This program is part of the XWorkplace package.
|
---|
62 | * This program is free software; you can redistribute it and/or modify
|
---|
63 | * it under the terms of the GNU General Public License as published by
|
---|
64 | * the Free Software Foundation, in version 2 as it comes in the COPYING
|
---|
65 | * file of the XWorkplace main distribution.
|
---|
66 | * This program is distributed in the hope that it will be useful,
|
---|
67 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
68 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
69 | * GNU General Public License for more details.
|
---|
70 | */
|
---|
71 |
|
---|
72 | #define OS2EMX_PLAIN_CHAR
|
---|
73 | // this is needed for "os2emx.h"; if this is defined,
|
---|
74 | // emx will define PSZ as _signed_ char, otherwise
|
---|
75 | // as unsigned char
|
---|
76 |
|
---|
77 | #define INCL_DOSSEMAPHORES
|
---|
78 | #define INCL_DOSEXCEPTIONS
|
---|
79 | #define INCL_DOSPROCESS
|
---|
80 | #define INCL_DOSERRORS
|
---|
81 |
|
---|
82 | #define INCL_WINWINDOWMGR
|
---|
83 | #define INCL_WINFRAMEMGR
|
---|
84 | #define INCL_WINCOUNTRY
|
---|
85 | #define INCL_WINSYS
|
---|
86 | #define INCL_WINMENUS
|
---|
87 | #define INCL_WINSTDCNR
|
---|
88 | #include <os2.h>
|
---|
89 |
|
---|
90 | #include <stdio.h>
|
---|
91 | #include <string.h>
|
---|
92 | // #include <malloc.h>
|
---|
93 | #include <setjmp.h>
|
---|
94 |
|
---|
95 | #define DONT_REPLACE_MALLOC // we need the "real" malloc in this file
|
---|
96 | #include "setup.h"
|
---|
97 |
|
---|
98 | #ifdef __XWPMEMDEBUG__
|
---|
99 |
|
---|
100 | #include "helpers\cnrh.h"
|
---|
101 | #include "helpers\except.h"
|
---|
102 | // #include "helpers\memdebug.h" // included by setup.h already
|
---|
103 | #include "helpers\stringh.h"
|
---|
104 | #include "helpers\winh.h"
|
---|
105 |
|
---|
106 | /*
|
---|
107 | *@@category: Helpers\C helpers\Heap debugging
|
---|
108 | */
|
---|
109 |
|
---|
110 | /* ******************************************************************
|
---|
111 | * *
|
---|
112 | * Global variables *
|
---|
113 | * *
|
---|
114 | ********************************************************************/
|
---|
115 |
|
---|
116 | #define MEMBLOCKMAGIC_HEAD "\210\203`H&cx$&%\254"
|
---|
117 | // size must be a multiple of 4 or dword-alignment will fail;
|
---|
118 | // there's an extra 0 byte at the end, so we have a size of 12
|
---|
119 | // V0.9.3 (2000-04-17) [umoeller]
|
---|
120 | #define MEMBLOCKMAGIC_TAIL "\250\210&%/dfjsk%#,dlhf\223"
|
---|
121 |
|
---|
122 | /*
|
---|
123 | *@@ HEAPITEM:
|
---|
124 | * informational structure created for each
|
---|
125 | * malloc() call by memdMalloc. These are stored
|
---|
126 | * in a global linked list (G_pHeapItemsRoot).
|
---|
127 | *
|
---|
128 | * We cannot use the linklist.c functions for
|
---|
129 | * managing the linked list because these use
|
---|
130 | * malloc in turn, which would lead to infinite
|
---|
131 | * loops.
|
---|
132 | *
|
---|
133 | *@@added V0.9.3 (2000-04-11) [umoeller]
|
---|
134 | */
|
---|
135 |
|
---|
136 | typedef struct _HEAPITEM
|
---|
137 | {
|
---|
138 | struct _HEAPITEM *pNext; // next item in linked list or NULL if last
|
---|
139 |
|
---|
140 | void *pAfterMagic; // memory pointer returned by memdMalloc;
|
---|
141 | // this points to after the magic string
|
---|
142 | unsigned long ulSize; // size of *pData
|
---|
143 |
|
---|
144 | const char *pcszSourceFile; // as passed to memdMalloc
|
---|
145 | unsigned long ulLine; // as passed to memdMalloc
|
---|
146 | const char *pcszFunction; // as passed to memdMalloc
|
---|
147 |
|
---|
148 | DATETIME dtAllocated; // system date/time at time of memdMalloc call
|
---|
149 |
|
---|
150 | ULONG ulTID; // thread ID that memdMalloc was running on
|
---|
151 |
|
---|
152 | BOOL fFreed; // TRUE only after item has been freed by memdFree
|
---|
153 | } HEAPITEM, *PHEAPITEM;
|
---|
154 |
|
---|
155 | HMTX G_hmtxMallocList = NULLHANDLE;
|
---|
156 |
|
---|
157 | PHEAPITEM G_pHeapItemsRoot = NULL,
|
---|
158 | G_pHeapItemsLast = NULL;
|
---|
159 |
|
---|
160 | PSZ G_pszMemCnrTitle = NULL;
|
---|
161 |
|
---|
162 | PFNCBMEMDLOG G_pMemdLogFunc = NULL;
|
---|
163 |
|
---|
164 | ULONG G_ulItemsReleased = 0,
|
---|
165 | G_ulBytesReleased = 0;
|
---|
166 |
|
---|
167 | /* ******************************************************************
|
---|
168 | * *
|
---|
169 | * Debug heap management *
|
---|
170 | * *
|
---|
171 | ********************************************************************/
|
---|
172 |
|
---|
173 | /*
|
---|
174 | *@@ memdLock:
|
---|
175 | * enables the global memory lock to protect
|
---|
176 | * the global variables here. Use memdUnlock
|
---|
177 | * to unlock again, and lock only for the shortest
|
---|
178 | * possible time. This is only used by the memdebug.c
|
---|
179 | * functions.
|
---|
180 | *
|
---|
181 | *@@added V0.9.3 (2000-04-10) [umoeller]
|
---|
182 | */
|
---|
183 |
|
---|
184 | BOOL memdLock(VOID)
|
---|
185 | {
|
---|
186 | APIRET arc = NO_ERROR;
|
---|
187 | if (G_hmtxMallocList == NULLHANDLE)
|
---|
188 | // first call:
|
---|
189 | arc = DosCreateMutexSem(NULL,
|
---|
190 | &G_hmtxMallocList,
|
---|
191 | 0,
|
---|
192 | FALSE);
|
---|
193 |
|
---|
194 | arc = DosRequestMutexSem(G_hmtxMallocList,
|
---|
195 | SEM_INDEFINITE_WAIT);
|
---|
196 |
|
---|
197 | return (arc == NO_ERROR);
|
---|
198 | }
|
---|
199 |
|
---|
200 | /*
|
---|
201 | *@@ memdUnlock:
|
---|
202 | * the reverse to memdLock.
|
---|
203 | *
|
---|
204 | *@@added V0.9.3 (2000-04-10) [umoeller]
|
---|
205 | */
|
---|
206 |
|
---|
207 | VOID memdUnlock(VOID)
|
---|
208 | {
|
---|
209 | DosReleaseMutexSem(G_hmtxMallocList);
|
---|
210 | }
|
---|
211 |
|
---|
212 | /*
|
---|
213 | *@@ memdMalloc:
|
---|
214 | * wrapper function for malloc() to trace malloc()
|
---|
215 | * calls more precisely.
|
---|
216 | *
|
---|
217 | * If XWorkplace is compiled with debug code, setup.h
|
---|
218 | * automatically #includes memdebug.h, which maps
|
---|
219 | * malloc to this function so that the source file
|
---|
220 | * etc. parameters automatically get passed.
|
---|
221 | *
|
---|
222 | * For each call, we call the default malloc(), whose
|
---|
223 | * return value is returned, and create a HEAPITEM
|
---|
224 | * for remembering the call, which is stored in a global
|
---|
225 | * linked list.
|
---|
226 | *
|
---|
227 | *@@added V0.9.3 (2000-04-11) [umoeller]
|
---|
228 | */
|
---|
229 |
|
---|
230 | void* memdMalloc(size_t stSize,
|
---|
231 | const char *pcszSourceFile, // in: source file name
|
---|
232 | unsigned long ulLine, // in: source line
|
---|
233 | const char *pcszFunction) // in: function name
|
---|
234 | {
|
---|
235 | void *prc = NULL;
|
---|
236 |
|
---|
237 | if (stSize == 0)
|
---|
238 | // malloc(0) called: report error
|
---|
239 | if (G_pMemdLogFunc)
|
---|
240 | {
|
---|
241 | CHAR szMsg[1000];
|
---|
242 | sprintf(szMsg,
|
---|
243 | "Function %s (%s, line %d) called malloc(0).",
|
---|
244 | pcszFunction,
|
---|
245 | pcszSourceFile,
|
---|
246 | ulLine);
|
---|
247 | G_pMemdLogFunc(szMsg);
|
---|
248 | }
|
---|
249 |
|
---|
250 | if (memdLock())
|
---|
251 | {
|
---|
252 | // call default malloc(), but with the additional
|
---|
253 | // size of our MEMBLOCKMAGIC strings; we'll return
|
---|
254 | // the first byte after the "front" string so we can
|
---|
255 | // check for string overwrites
|
---|
256 | void *pObj = malloc(stSize
|
---|
257 | + sizeof(MEMBLOCKMAGIC_HEAD)
|
---|
258 | + sizeof(MEMBLOCKMAGIC_TAIL));
|
---|
259 | if (pObj)
|
---|
260 | {
|
---|
261 | PHEAPITEM pHeapItem = (PHEAPITEM)malloc(sizeof(HEAPITEM));
|
---|
262 |
|
---|
263 | // store "front" magic string
|
---|
264 | memcpy(pObj,
|
---|
265 | MEMBLOCKMAGIC_HEAD,
|
---|
266 | sizeof(MEMBLOCKMAGIC_HEAD));
|
---|
267 | // return address: first byte after "front" magic string
|
---|
268 | prc = ((PBYTE)pObj) + sizeof(MEMBLOCKMAGIC_HEAD);
|
---|
269 | // store "tail" magic string to block which
|
---|
270 | // will be returned plus the size which was requested
|
---|
271 | memcpy(((PBYTE)prc) + stSize,
|
---|
272 | MEMBLOCKMAGIC_TAIL,
|
---|
273 | sizeof(MEMBLOCKMAGIC_TAIL));
|
---|
274 |
|
---|
275 | if (pHeapItem)
|
---|
276 | {
|
---|
277 | PTIB ptib;
|
---|
278 | PPIB ppib;
|
---|
279 |
|
---|
280 | pHeapItem->pNext = 0;
|
---|
281 |
|
---|
282 | pHeapItem->pAfterMagic = prc;
|
---|
283 | pHeapItem->ulSize = stSize;
|
---|
284 | pHeapItem->pcszSourceFile = pcszSourceFile;
|
---|
285 | pHeapItem->ulLine = ulLine;
|
---|
286 | pHeapItem->pcszFunction = pcszFunction;
|
---|
287 |
|
---|
288 | DosGetDateTime(&pHeapItem->dtAllocated);
|
---|
289 |
|
---|
290 | pHeapItem->ulTID = 0;
|
---|
291 |
|
---|
292 | if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR)
|
---|
293 | if (ptib)
|
---|
294 | if (ptib->tib_ptib2)
|
---|
295 | pHeapItem->ulTID = ptib->tib_ptib2->tib2_ultid;
|
---|
296 |
|
---|
297 | pHeapItem->fFreed = FALSE;
|
---|
298 |
|
---|
299 | // append heap item to linked list
|
---|
300 | if (G_pHeapItemsRoot == NULL)
|
---|
301 | // first item:
|
---|
302 | G_pHeapItemsRoot = pHeapItem;
|
---|
303 | else
|
---|
304 | // we have items already:
|
---|
305 | if (G_pHeapItemsLast)
|
---|
306 | {
|
---|
307 | // last item cached:
|
---|
308 | G_pHeapItemsLast->pNext = pHeapItem;
|
---|
309 | G_pHeapItemsLast = pHeapItem;
|
---|
310 | }
|
---|
311 | else
|
---|
312 | {
|
---|
313 | // not cached: find end of list
|
---|
314 | PHEAPITEM phi = G_pHeapItemsRoot;
|
---|
315 | while (phi->pNext)
|
---|
316 | phi = phi->pNext;
|
---|
317 |
|
---|
318 | phi->pNext = pHeapItem;
|
---|
319 | G_pHeapItemsLast = pHeapItem;
|
---|
320 | }
|
---|
321 | }
|
---|
322 | }
|
---|
323 |
|
---|
324 | memdUnlock();
|
---|
325 | }
|
---|
326 |
|
---|
327 | return (prc);
|
---|
328 | }
|
---|
329 |
|
---|
330 | /*
|
---|
331 | *@@ memdCalloc:
|
---|
332 | * similar to memdMalloc; this is the wrapper for
|
---|
333 | * the calloc() call. This is automatically
|
---|
334 | * remapped also.
|
---|
335 | *
|
---|
336 | *@@added V0.9.3 (2000-04-11) [umoeller]
|
---|
337 | */
|
---|
338 |
|
---|
339 | void* memdCalloc(size_t num,
|
---|
340 | size_t stSize,
|
---|
341 | const char *pcszSourceFile,
|
---|
342 | unsigned long ulLine,
|
---|
343 | const char *pcszFunction)
|
---|
344 | {
|
---|
345 | void *p = memdMalloc(num * stSize,
|
---|
346 | pcszSourceFile,
|
---|
347 | ulLine,
|
---|
348 | pcszFunction);
|
---|
349 | memset(p, 0, num * stSize);
|
---|
350 | return (p);
|
---|
351 | }
|
---|
352 |
|
---|
353 | /*
|
---|
354 | *@@ memdFree:
|
---|
355 | * wrapper for the free() call, which is remapped
|
---|
356 | * by setup.h and memdebug.h like memdMalloc
|
---|
357 | * and memdCalloc. This searches the memory object
|
---|
358 | * (p) which was previously allocated on the linked
|
---|
359 | * list of HEAPITEM's and frees it then by calling
|
---|
360 | * the default free().
|
---|
361 | *
|
---|
362 | * The HEAPITEM itself is not freed, but only marked
|
---|
363 | * as freed. As a result, the linked list can grow
|
---|
364 | * REALLY large. While memdMalloc does not become
|
---|
365 | * slower with large HEAPITEM lists because it only
|
---|
366 | * appends to the end of the list, which is remembered,
|
---|
367 | * memdFree can become extremely slow because the entire
|
---|
368 | * list needs to be searched with each call.
|
---|
369 | * So call memdReleaseFreed from time to time.
|
---|
370 | *
|
---|
371 | *@@added V0.9.3 (2000-04-10) [umoeller]
|
---|
372 | */
|
---|
373 |
|
---|
374 | void memdFree(void *p,
|
---|
375 | const char *pcszSourceFile,
|
---|
376 | unsigned long ulLine,
|
---|
377 | const char *pcszFunction)
|
---|
378 | {
|
---|
379 | BOOL fFound = FALSE;
|
---|
380 | if (memdLock())
|
---|
381 | {
|
---|
382 | // PLISTNODE pNode = lstQueryFirstNode(&G_llHeapItems);
|
---|
383 | PHEAPITEM pHeapItem = G_pHeapItemsRoot;
|
---|
384 |
|
---|
385 | // search the list with the pointer which was
|
---|
386 | // really returned by the original malloc(),
|
---|
387 | // that is, the byte before the magic string
|
---|
388 | void *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
|
---|
389 |
|
---|
390 | while (pHeapItem)
|
---|
391 | {
|
---|
392 | if (pHeapItem->pAfterMagic == p)
|
---|
393 | // the same address may be allocated and freed
|
---|
394 | // several times, so if this address has been
|
---|
395 | // freed, search on
|
---|
396 | if (!pHeapItem->fFreed)
|
---|
397 | {
|
---|
398 | // found:
|
---|
399 | ULONG ulError = 0;
|
---|
400 | // check magic string
|
---|
401 | if (memcmp(pBeforeMagic,
|
---|
402 | MEMBLOCKMAGIC_HEAD,
|
---|
403 | sizeof(MEMBLOCKMAGIC_HEAD))
|
---|
404 | != 0)
|
---|
405 | ulError = 1;
|
---|
406 | else if (memcmp(((PBYTE)pHeapItem->pAfterMagic) + pHeapItem->ulSize,
|
---|
407 | MEMBLOCKMAGIC_TAIL,
|
---|
408 | sizeof(MEMBLOCKMAGIC_TAIL))
|
---|
409 | != 0)
|
---|
410 | ulError = 2;
|
---|
411 |
|
---|
412 | if (ulError)
|
---|
413 | {
|
---|
414 | // magic block has been overwritten:
|
---|
415 | if (G_pMemdLogFunc)
|
---|
416 | {
|
---|
417 | CHAR szMsg[1000];
|
---|
418 | sprintf(szMsg,
|
---|
419 | "Magic string %s memory block at 0x%lX has been overwritten.\n"
|
---|
420 | "This was detected by the free() call at %s (%s, line %d).\n"
|
---|
421 | "The block was allocated by %s (%s, line %d).",
|
---|
422 | (ulError == 1) ? "before" : "after",
|
---|
423 | p,
|
---|
424 | pcszFunction,
|
---|
425 | pcszSourceFile,
|
---|
426 | ulLine, // free
|
---|
427 | pHeapItem->pcszFunction,
|
---|
428 | pHeapItem->pcszSourceFile,
|
---|
429 | pHeapItem->ulLine);
|
---|
430 | G_pMemdLogFunc(szMsg);
|
---|
431 | }
|
---|
432 | }
|
---|
433 |
|
---|
434 | free(pBeforeMagic);
|
---|
435 | pHeapItem->fFreed = TRUE;
|
---|
436 |
|
---|
437 | /* lstRemoveNode(&G_llHeapItems,
|
---|
438 | pNode); */
|
---|
439 | fFound = TRUE;
|
---|
440 | break;
|
---|
441 | }
|
---|
442 |
|
---|
443 | pHeapItem = pHeapItem->pNext;
|
---|
444 | }
|
---|
445 |
|
---|
446 | memdUnlock();
|
---|
447 | }
|
---|
448 |
|
---|
449 | if (!fFound)
|
---|
450 | if (G_pMemdLogFunc)
|
---|
451 | {
|
---|
452 | CHAR szMsg[1000];
|
---|
453 | sprintf(szMsg,
|
---|
454 | "free() failed. Called from %s (%s, line %d) for object 0x%lX.",
|
---|
455 | pcszFunction,
|
---|
456 | pcszSourceFile,
|
---|
457 | ulLine,
|
---|
458 | p);
|
---|
459 | G_pMemdLogFunc(szMsg);
|
---|
460 | }
|
---|
461 | }
|
---|
462 |
|
---|
463 | /*
|
---|
464 | *@@ memdReleaseFreed:
|
---|
465 | * goes thru the entire global HEAPITEM's list
|
---|
466 | * and throws out all items which have been freed.
|
---|
467 | * Call this from time to time in order to keep
|
---|
468 | * the system usable. See memdFree() for details.
|
---|
469 | *
|
---|
470 | * Returns the no. of HEAPITEM's that have been
|
---|
471 | * released.
|
---|
472 | *
|
---|
473 | *@@added V0.9.3 (2000-04-11) [umoeller]
|
---|
474 | */
|
---|
475 |
|
---|
476 | unsigned long memdReleaseFreed(void)
|
---|
477 | {
|
---|
478 | BOOL ulItemsReleased = 0,
|
---|
479 | ulBytesReleased = 0;
|
---|
480 | if (memdLock())
|
---|
481 | {
|
---|
482 | PHEAPITEM pHeapItem = G_pHeapItemsRoot,
|
---|
483 | pPrevious = NULL;
|
---|
484 |
|
---|
485 | while (pHeapItem)
|
---|
486 | {
|
---|
487 | PHEAPITEM pNext = pHeapItem->pNext; // can be NULL
|
---|
488 | if (pHeapItem->fFreed)
|
---|
489 | {
|
---|
490 | // item freed:
|
---|
491 | if (pPrevious == NULL)
|
---|
492 | // head of list:
|
---|
493 | G_pHeapItemsRoot = pNext; // can be NULL
|
---|
494 | else
|
---|
495 | // somewhere later:
|
---|
496 | // link next to previous to skip current
|
---|
497 | pPrevious->pNext = pNext; // can be NULL
|
---|
498 |
|
---|
499 | ulItemsReleased++;
|
---|
500 | ulBytesReleased += pHeapItem->ulSize;
|
---|
501 |
|
---|
502 | free(pHeapItem);
|
---|
503 | }
|
---|
504 | else
|
---|
505 | // item still valid:
|
---|
506 | pPrevious = pHeapItem;
|
---|
507 |
|
---|
508 | pHeapItem = pNext;
|
---|
509 | }
|
---|
510 |
|
---|
511 | G_ulItemsReleased += ulItemsReleased;
|
---|
512 | G_ulBytesReleased += ulBytesReleased;
|
---|
513 |
|
---|
514 | memdUnlock();
|
---|
515 | }
|
---|
516 |
|
---|
517 | return (ulItemsReleased);
|
---|
518 | }
|
---|
519 |
|
---|
520 | /* ******************************************************************
|
---|
521 | * *
|
---|
522 | * XFolder debugging helpers *
|
---|
523 | * *
|
---|
524 | ********************************************************************/
|
---|
525 |
|
---|
526 | #ifdef _PMPRINTF_
|
---|
527 | /*
|
---|
528 | *@@ memdDumpMemoryBlock:
|
---|
529 | * if _PMPRINTF_ has been #define'd before including
|
---|
530 | * memdebug.h,
|
---|
531 | * this will dump a block of memory to the PMPRINTF
|
---|
532 | * output window. Useful for debugging internal
|
---|
533 | * structures.
|
---|
534 | * If _PMPRINTF_ has been NOT #define'd,
|
---|
535 | * no code will be produced at all. :-)
|
---|
536 | */
|
---|
537 |
|
---|
538 | void memdDumpMemoryBlock(PBYTE pb, // in: start address
|
---|
539 | ULONG ulSize, // in: size of block
|
---|
540 | ULONG ulIndent) // in: how many spaces to put
|
---|
541 | // before each output line
|
---|
542 | {
|
---|
543 | PSZ psz = strhCreateDump(pb, ulSize, ulIndent);
|
---|
544 | if (psz)
|
---|
545 | {
|
---|
546 | _Pmpf(("\n%s", psz));
|
---|
547 | free(psz);
|
---|
548 | }
|
---|
549 | }
|
---|
550 | #endif
|
---|
551 |
|
---|
552 | /* ******************************************************************
|
---|
553 | * *
|
---|
554 | * Heap debugging window *
|
---|
555 | * *
|
---|
556 | ********************************************************************/
|
---|
557 |
|
---|
558 | /*
|
---|
559 | *@@ MEMRECORD:
|
---|
560 | *
|
---|
561 | *@@added V0.9.1 (99-12-04) [umoeller]
|
---|
562 | */
|
---|
563 |
|
---|
564 | typedef struct _MEMRECORD
|
---|
565 | {
|
---|
566 | RECORDCORE recc;
|
---|
567 |
|
---|
568 | ULONG ulIndex;
|
---|
569 |
|
---|
570 | CDATE cdateAllocated;
|
---|
571 | CTIME ctimeAllocated;
|
---|
572 |
|
---|
573 | PSZ pszFreed;
|
---|
574 |
|
---|
575 | ULONG ulTID;
|
---|
576 |
|
---|
577 | PSZ pszFunction; // points to szFunction
|
---|
578 | CHAR szFunction[400];
|
---|
579 |
|
---|
580 | PSZ pszSource; // points to szSource
|
---|
581 | CHAR szSource[CCHMAXPATH];
|
---|
582 |
|
---|
583 | ULONG ulLine;
|
---|
584 |
|
---|
585 | PSZ pszAddress; // points to szAddress
|
---|
586 | CHAR szAddress[20];
|
---|
587 |
|
---|
588 | ULONG ulSize;
|
---|
589 |
|
---|
590 | } MEMRECORD, *PMEMRECORD;
|
---|
591 |
|
---|
592 | /* ULONG ulHeapItemsCount1,
|
---|
593 | ulHeapItemsCount2;
|
---|
594 | ULONG ulTotalAllocated,
|
---|
595 | ulTotalFreed;
|
---|
596 | PMEMRECORD pMemRecordThis = NULL;
|
---|
597 | PSZ pszMemCnrTitle = NULL; */
|
---|
598 |
|
---|
599 | #if 0
|
---|
600 | /*
|
---|
601 | *@@ fncbMemHeapWalkCount:
|
---|
602 | * callback func for _heap_walk function used for
|
---|
603 | * fnwpMemDebug.
|
---|
604 | *
|
---|
605 | *@@added V0.9.1 (99-12-04) [umoeller]
|
---|
606 | */
|
---|
607 |
|
---|
608 | int fncbMemHeapWalkCount(const void *pObject,
|
---|
609 | size_t Size,
|
---|
610 | int useflag,
|
---|
611 | int status,
|
---|
612 | const char *filename,
|
---|
613 | size_t line)
|
---|
614 | {
|
---|
615 | // skip all the items which seem to be
|
---|
616 | // internal to the runtime
|
---|
617 | if ((filename) || (useflag == _FREEENTRY))
|
---|
618 | {
|
---|
619 | ulHeapItemsCount1++;
|
---|
620 | if (useflag == _FREEENTRY)
|
---|
621 | ulTotalFreed += Size;
|
---|
622 | else
|
---|
623 | ulTotalAllocated += Size;
|
---|
624 | }
|
---|
625 | return (0);
|
---|
626 | }
|
---|
627 |
|
---|
628 | /*
|
---|
629 | *@@ fncbMemHeapWalkFill:
|
---|
630 | * callback func for _heap_walk function used for
|
---|
631 | * fnwpMemDebug.
|
---|
632 | *
|
---|
633 | *@@added V0.9.1 (99-12-04) [umoeller]
|
---|
634 | */
|
---|
635 |
|
---|
636 | int fncbMemHeapWalkFill(const void *pObject,
|
---|
637 | size_t Size,
|
---|
638 | int useflag,
|
---|
639 | int status,
|
---|
640 | const char *filename,
|
---|
641 | size_t line)
|
---|
642 | {
|
---|
643 | // skip all the items which seem to be
|
---|
644 | // internal to the runtime
|
---|
645 | if ((filename) || (useflag == _FREEENTRY))
|
---|
646 | {
|
---|
647 | ulHeapItemsCount2++;
|
---|
648 | if ((pMemRecordThis) && (ulHeapItemsCount2 < ulHeapItemsCount1))
|
---|
649 | {
|
---|
650 | pMemRecordThis->ulIndex = ulHeapItemsCount2 - 1;
|
---|
651 |
|
---|
652 | pMemRecordThis->pObject = pObject;
|
---|
653 | pMemRecordThis->useflag = useflag;
|
---|
654 | pMemRecordThis->status = status;
|
---|
655 | pMemRecordThis->filename = filename;
|
---|
656 |
|
---|
657 | pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
|
---|
658 |
|
---|
659 | pMemRecordThis->ulSize = Size;
|
---|
660 |
|
---|
661 | pMemRecordThis->pszSource = pMemRecordThis->szSource;
|
---|
662 |
|
---|
663 | pMemRecordThis->ulLine = line;
|
---|
664 |
|
---|
665 | pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
|
---|
666 | }
|
---|
667 | else
|
---|
668 | return (1); // stop
|
---|
669 | }
|
---|
670 |
|
---|
671 | return (0);
|
---|
672 | }
|
---|
673 |
|
---|
674 | /*
|
---|
675 | *@@ memdCreateRecordsVAC:
|
---|
676 | *
|
---|
677 | *@@added V0.9.3 (2000-04-10) [umoeller]
|
---|
678 | */
|
---|
679 |
|
---|
680 | VOID memdCreateRecordsVAC(HWND hwndCnr)
|
---|
681 | {
|
---|
682 | // count heap items
|
---|
683 | ulHeapItemsCount1 = 0;
|
---|
684 | ulTotalFreed = 0;
|
---|
685 | ulTotalAllocated = 0;
|
---|
686 | _heap_walk(fncbMemHeapWalkCount);
|
---|
687 |
|
---|
688 | pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
|
---|
689 | sizeof(MEMRECORD),
|
---|
690 | ulHeapItemsCount1);
|
---|
691 | if (pMemRecordFirst)
|
---|
692 | {
|
---|
693 | ulHeapItemsCount2 = 0;
|
---|
694 | pMemRecordThis = pMemRecordFirst;
|
---|
695 | _heap_walk(fncbMemHeapWalkFill);
|
---|
696 |
|
---|
697 | // the following doesn't work while _heap_walk is running
|
---|
698 | pMemRecordThis = pMemRecordFirst;
|
---|
699 | while (pMemRecordThis)
|
---|
700 | {
|
---|
701 | switch (pMemRecordThis->useflag)
|
---|
702 | {
|
---|
703 | case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
|
---|
704 | case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
|
---|
705 | }
|
---|
706 |
|
---|
707 | switch (pMemRecordThis->status)
|
---|
708 | {
|
---|
709 | case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
|
---|
710 | case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
|
---|
711 | case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
|
---|
712 | case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
|
---|
713 | }
|
---|
714 |
|
---|
715 | sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
|
---|
716 | strcpy(pMemRecordThis->szSource,
|
---|
717 | (pMemRecordThis->filename)
|
---|
718 | ? pMemRecordThis->filename
|
---|
719 | : "?");
|
---|
720 |
|
---|
721 | pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
|
---|
722 | }
|
---|
723 |
|
---|
724 | cnrhInsertRecords(hwndCnr,
|
---|
725 | NULL, // parent
|
---|
726 | (PRECORDCORE)pMemRecordFirst,
|
---|
727 | TRUE,
|
---|
728 | NULL,
|
---|
729 | CRA_RECORDREADONLY,
|
---|
730 | ulHeapItemsCount2);
|
---|
731 | }
|
---|
732 | }
|
---|
733 |
|
---|
734 | #endif
|
---|
735 |
|
---|
736 | /*
|
---|
737 | *@@ memdCreateRecords:
|
---|
738 | *
|
---|
739 | *@@added V0.9.3 (2000-04-10) [umoeller]
|
---|
740 | */
|
---|
741 |
|
---|
742 | VOID memdCreateRecords(HWND hwndCnr,
|
---|
743 | PULONG pulTotalItems,
|
---|
744 | PULONG pulAllocatedItems,
|
---|
745 | PULONG pulFreedItems,
|
---|
746 | PULONG pulTotalBytes,
|
---|
747 | PULONG pulAllocatedBytes,
|
---|
748 | PULONG pulFreedBytes)
|
---|
749 | {
|
---|
750 | // count heap items
|
---|
751 | ULONG ulHeapItemsCount1 = 0;
|
---|
752 | PMEMRECORD pMemRecordFirst;
|
---|
753 |
|
---|
754 | if (memdLock())
|
---|
755 | {
|
---|
756 | // PLISTNODE pNode = lstQueryFirstNode(&G_llHeapItems);
|
---|
757 | PHEAPITEM pHeapItem = G_pHeapItemsRoot;
|
---|
758 |
|
---|
759 | *pulTotalItems = 0;
|
---|
760 | *pulAllocatedItems = 0;
|
---|
761 | *pulFreedItems = 0;
|
---|
762 |
|
---|
763 | *pulTotalBytes = 0;
|
---|
764 | *pulAllocatedBytes = 0;
|
---|
765 | *pulFreedBytes = 0;
|
---|
766 |
|
---|
767 | while (pHeapItem)
|
---|
768 | {
|
---|
769 | ulHeapItemsCount1++;
|
---|
770 | if (pHeapItem->fFreed)
|
---|
771 | {
|
---|
772 | (*pulFreedItems)++;
|
---|
773 | (*pulFreedBytes) += pHeapItem->ulSize;
|
---|
774 | }
|
---|
775 | else
|
---|
776 | {
|
---|
777 | (*pulAllocatedItems)++;
|
---|
778 | (*pulAllocatedBytes) += pHeapItem->ulSize;
|
---|
779 | }
|
---|
780 |
|
---|
781 | (*pulTotalBytes) += pHeapItem->ulSize;
|
---|
782 |
|
---|
783 | pHeapItem = pHeapItem->pNext;
|
---|
784 | }
|
---|
785 |
|
---|
786 | *pulTotalItems = ulHeapItemsCount1;
|
---|
787 |
|
---|
788 | pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
|
---|
789 | sizeof(MEMRECORD),
|
---|
790 | ulHeapItemsCount1);
|
---|
791 | if (pMemRecordFirst)
|
---|
792 | {
|
---|
793 | ULONG ulHeapItemsCount2 = 0;
|
---|
794 | PMEMRECORD pMemRecordThis = pMemRecordFirst;
|
---|
795 | pHeapItem = G_pHeapItemsRoot;
|
---|
796 | // PLISTNODE pMemNode = lstQueryFirstNode(&G_llHeapItems);
|
---|
797 |
|
---|
798 | while ((pMemRecordThis) && (pHeapItem))
|
---|
799 | {
|
---|
800 | // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;
|
---|
801 |
|
---|
802 | pMemRecordThis->ulIndex = ulHeapItemsCount2++;
|
---|
803 |
|
---|
804 | cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
|
---|
805 | &pMemRecordThis->cdateAllocated,
|
---|
806 | &pMemRecordThis->ctimeAllocated);
|
---|
807 |
|
---|
808 | if (pHeapItem->fFreed)
|
---|
809 | pMemRecordThis->pszFreed = "yes";
|
---|
810 |
|
---|
811 | pMemRecordThis->ulTID = pHeapItem->ulTID;
|
---|
812 |
|
---|
813 | strcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
|
---|
814 | pMemRecordThis->pszSource = pMemRecordThis->szSource;
|
---|
815 |
|
---|
816 | pMemRecordThis->ulLine = pHeapItem->ulLine;
|
---|
817 |
|
---|
818 | strcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
|
---|
819 | pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
|
---|
820 |
|
---|
821 | sprintf(pMemRecordThis->szAddress, "0x%lX", pHeapItem->pAfterMagic);
|
---|
822 | pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
|
---|
823 |
|
---|
824 | pMemRecordThis->ulSize = pHeapItem->ulSize;
|
---|
825 |
|
---|
826 |
|
---|
827 | /* switch (pMemRecordThis->useflag)
|
---|
828 | {
|
---|
829 | case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
|
---|
830 | case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
|
---|
831 | }
|
---|
832 |
|
---|
833 | switch (pMemRecordThis->status)
|
---|
834 | {
|
---|
835 | case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
|
---|
836 | case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
|
---|
837 | case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
|
---|
838 | case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
|
---|
839 | }
|
---|
840 |
|
---|
841 | sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
|
---|
842 | strcpy(pMemRecordThis->szSource,
|
---|
843 | (pMemRecordThis->filename)
|
---|
844 | ? pMemRecordThis->filename
|
---|
845 | : "?"); */
|
---|
846 |
|
---|
847 | pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
|
---|
848 | pHeapItem = pHeapItem->pNext;
|
---|
849 | }
|
---|
850 |
|
---|
851 | cnrhInsertRecords(hwndCnr,
|
---|
852 | NULL, // parent
|
---|
853 | (PRECORDCORE)pMemRecordFirst,
|
---|
854 | TRUE,
|
---|
855 | NULL,
|
---|
856 | CRA_RECORDREADONLY,
|
---|
857 | ulHeapItemsCount2);
|
---|
858 | }
|
---|
859 |
|
---|
860 | memdUnlock();
|
---|
861 | }
|
---|
862 | }
|
---|
863 |
|
---|
864 | /*
|
---|
865 | *@@ mnu_fnCompareIndex:
|
---|
866 | *
|
---|
867 | *@@added V0.9.1 (99-12-03) [umoeller]
|
---|
868 | */
|
---|
869 |
|
---|
870 | SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
|
---|
871 | {
|
---|
872 | // HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
|
---|
873 | pStorage = pStorage; // to keep the compiler happy
|
---|
874 | if ((pmrc1) && (pmrc2))
|
---|
875 | if (pmrc1->ulIndex < pmrc2->ulIndex)
|
---|
876 | return (-1);
|
---|
877 | else if (pmrc1->ulIndex > pmrc2->ulIndex)
|
---|
878 | return (1);
|
---|
879 |
|
---|
880 | return (0);
|
---|
881 | }
|
---|
882 |
|
---|
883 | /*
|
---|
884 | *@@ mnu_fnCompareSourceFile:
|
---|
885 | *
|
---|
886 | *@@added V0.9.1 (99-12-03) [umoeller]
|
---|
887 | */
|
---|
888 |
|
---|
889 | SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)
|
---|
890 | {
|
---|
891 | HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
|
---|
892 | pStorage = pStorage; // to keep the compiler happy
|
---|
893 | if ((pmrc1) && (pmrc2))
|
---|
894 | switch (WinCompareStrings(habDesktop, 0, 0,
|
---|
895 | pmrc1->szSource,
|
---|
896 | pmrc2->szSource,
|
---|
897 | 0))
|
---|
898 | {
|
---|
899 | case WCS_LT: return (-1);
|
---|
900 | case WCS_GT: return (1);
|
---|
901 | default: // equal
|
---|
902 | if (pmrc1->ulLine < pmrc2->ulLine)
|
---|
903 | return (-1);
|
---|
904 | else if (pmrc1->ulLine > pmrc2->ulLine)
|
---|
905 | return (1);
|
---|
906 |
|
---|
907 | }
|
---|
908 |
|
---|
909 | return (0);
|
---|
910 | }
|
---|
911 |
|
---|
912 | #define ID_MEMCNR 1000
|
---|
913 |
|
---|
914 | /*
|
---|
915 | *@@ memd_fnwpMemDebug:
|
---|
916 | * client window proc for the heap debugger window
|
---|
917 | * accessible from the Desktop context menu if
|
---|
918 | * __XWPMEMDEBUG__ is defined. Otherwise, this is not
|
---|
919 | * compiled.
|
---|
920 | *
|
---|
921 | * Usage: this is a regular PM client window procedure
|
---|
922 | * to be used with WinRegisterClass and WinCreateStdWindow.
|
---|
923 | * See dtpMenuItemSelected, which uses this.
|
---|
924 | *
|
---|
925 | * This creates a container with all the memory objects
|
---|
926 | * with the size of the client area in turn.
|
---|
927 | *
|
---|
928 | *@@added V0.9.1 (99-12-04) [umoeller]
|
---|
929 | */
|
---|
930 |
|
---|
931 |
|
---|
932 | MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
|
---|
933 | {
|
---|
934 | MRESULT mrc = 0;
|
---|
935 |
|
---|
936 | switch (msg)
|
---|
937 | {
|
---|
938 | case WM_CREATE:
|
---|
939 | {
|
---|
940 | TRY_LOUD(excpt1, NULL)
|
---|
941 | {
|
---|
942 | // PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
|
---|
943 | HWND hwndCnr;
|
---|
944 | hwndCnr = WinCreateWindow(hwndClient, // parent
|
---|
945 | WC_CONTAINER,
|
---|
946 | "",
|
---|
947 | WS_VISIBLE | CCS_MINIICONS | CCS_READONLY | CCS_SINGLESEL,
|
---|
948 | 0, 0, 0, 0,
|
---|
949 | hwndClient, // owner
|
---|
950 | HWND_TOP,
|
---|
951 | ID_MEMCNR,
|
---|
952 | NULL, NULL);
|
---|
953 | if (hwndCnr)
|
---|
954 | {
|
---|
955 | XFIELDINFO xfi[11];
|
---|
956 | PFIELDINFO pfi = NULL;
|
---|
957 | PMEMRECORD pMemRecordFirst;
|
---|
958 | int i = 0;
|
---|
959 |
|
---|
960 | ULONG ulTotalItems = 0,
|
---|
961 | ulAllocatedItems = 0,
|
---|
962 | ulFreedItems = 0;
|
---|
963 | ULONG ulTotalBytes = 0,
|
---|
964 | ulAllocatedBytes = 0,
|
---|
965 | ulFreedBytes = 0;
|
---|
966 |
|
---|
967 | // set up cnr details view
|
---|
968 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulIndex);
|
---|
969 | xfi[i].pszColumnTitle = "No.";
|
---|
970 | xfi[i].ulDataType = CFA_ULONG;
|
---|
971 | xfi[i++].ulOrientation = CFA_RIGHT;
|
---|
972 |
|
---|
973 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, cdateAllocated);
|
---|
974 | xfi[i].pszColumnTitle = "Date";
|
---|
975 | xfi[i].ulDataType = CFA_DATE;
|
---|
976 | xfi[i++].ulOrientation = CFA_LEFT;
|
---|
977 |
|
---|
978 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ctimeAllocated);
|
---|
979 | xfi[i].pszColumnTitle = "Time";
|
---|
980 | xfi[i].ulDataType = CFA_TIME;
|
---|
981 | xfi[i++].ulOrientation = CFA_LEFT;
|
---|
982 |
|
---|
983 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFreed);
|
---|
984 | xfi[i].pszColumnTitle = "Freed";
|
---|
985 | xfi[i].ulDataType = CFA_STRING;
|
---|
986 | xfi[i++].ulOrientation = CFA_CENTER;
|
---|
987 |
|
---|
988 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulTID);
|
---|
989 | xfi[i].pszColumnTitle = "TID";
|
---|
990 | xfi[i].ulDataType = CFA_ULONG;
|
---|
991 | xfi[i++].ulOrientation = CFA_RIGHT;
|
---|
992 |
|
---|
993 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFunction);
|
---|
994 | xfi[i].pszColumnTitle = "Function";
|
---|
995 | xfi[i].ulDataType = CFA_STRING;
|
---|
996 | xfi[i++].ulOrientation = CFA_LEFT;
|
---|
997 |
|
---|
998 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszSource);
|
---|
999 | xfi[i].pszColumnTitle = "Source";
|
---|
1000 | xfi[i].ulDataType = CFA_STRING;
|
---|
1001 | xfi[i++].ulOrientation = CFA_LEFT;
|
---|
1002 |
|
---|
1003 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulLine);
|
---|
1004 | xfi[i].pszColumnTitle = "Line";
|
---|
1005 | xfi[i].ulDataType = CFA_ULONG;
|
---|
1006 | xfi[i++].ulOrientation = CFA_RIGHT;
|
---|
1007 |
|
---|
1008 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulSize);
|
---|
1009 | xfi[i].pszColumnTitle = "Size";
|
---|
1010 | xfi[i].ulDataType = CFA_ULONG;
|
---|
1011 | xfi[i++].ulOrientation = CFA_RIGHT;
|
---|
1012 |
|
---|
1013 | xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszAddress);
|
---|
1014 | xfi[i].pszColumnTitle = "Address";
|
---|
1015 | xfi[i].ulDataType = CFA_STRING;
|
---|
1016 | xfi[i++].ulOrientation = CFA_LEFT;
|
---|
1017 |
|
---|
1018 | pfi = cnrhSetFieldInfos(hwndCnr,
|
---|
1019 | &xfi[0],
|
---|
1020 | i, // array item count
|
---|
1021 | TRUE, // no draw lines
|
---|
1022 | 3); // return column
|
---|
1023 |
|
---|
1024 | {
|
---|
1025 | PSZ pszFont = "9.WarpSans";
|
---|
1026 | WinSetPresParam(hwndCnr,
|
---|
1027 | PP_FONTNAMESIZE,
|
---|
1028 | strlen(pszFont),
|
---|
1029 | pszFont);
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | memdCreateRecords(hwndCnr,
|
---|
1033 | &ulTotalItems,
|
---|
1034 | &ulAllocatedItems,
|
---|
1035 | &ulFreedItems,
|
---|
1036 | &ulTotalBytes,
|
---|
1037 | &ulAllocatedBytes,
|
---|
1038 | &ulFreedBytes);
|
---|
1039 |
|
---|
1040 | BEGIN_CNRINFO()
|
---|
1041 | {
|
---|
1042 | CHAR szCnrTitle[1000];
|
---|
1043 | CHAR szTotalItems[100],
|
---|
1044 | szAllocatedItems[100],
|
---|
1045 | szFreedItems[100],
|
---|
1046 | szReleasedItems[100];
|
---|
1047 | CHAR szTotalBytes[100],
|
---|
1048 | szAllocatedBytes[100],
|
---|
1049 | szFreedBytes[100],
|
---|
1050 | szReleasedBytes[100];
|
---|
1051 | sprintf(szCnrTitle,
|
---|
1052 | "Total logs in use: %s items = %s bytes\n"
|
---|
1053 | " Total in use: %s items = %s bytes\n"
|
---|
1054 | " Total freed: %s items = %s bytes\n"
|
---|
1055 | "Total logs released: %s items = %s bytes",
|
---|
1056 | strhThousandsDouble(szTotalItems,
|
---|
1057 | ulTotalItems,
|
---|
1058 | '.'),
|
---|
1059 | strhThousandsDouble(szTotalBytes,
|
---|
1060 | ulTotalBytes,
|
---|
1061 | '.'),
|
---|
1062 | strhThousandsDouble(szAllocatedItems,
|
---|
1063 | ulAllocatedItems,
|
---|
1064 | '.'),
|
---|
1065 | strhThousandsDouble(szAllocatedBytes,
|
---|
1066 | ulAllocatedBytes,
|
---|
1067 | '.'),
|
---|
1068 | strhThousandsDouble(szFreedItems,
|
---|
1069 | ulFreedItems,
|
---|
1070 | '.'),
|
---|
1071 | strhThousandsDouble(szFreedBytes,
|
---|
1072 | ulFreedBytes,
|
---|
1073 | '.'),
|
---|
1074 | strhThousandsDouble(szReleasedItems,
|
---|
1075 | G_ulItemsReleased,
|
---|
1076 | '.'),
|
---|
1077 | strhThousandsDouble(szReleasedBytes,
|
---|
1078 | G_ulBytesReleased,
|
---|
1079 | '.'));
|
---|
1080 | G_pszMemCnrTitle = strdup(szCnrTitle);
|
---|
1081 | cnrhSetTitle(G_pszMemCnrTitle);
|
---|
1082 | cnrhSetView(CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES
|
---|
1083 | | CA_DRAWICON
|
---|
1084 | | CA_CONTAINERTITLE | CA_TITLEREADONLY
|
---|
1085 | | CA_TITLESEPARATOR | CA_TITLELEFT);
|
---|
1086 | cnrhSetSplitBarAfter(pfi);
|
---|
1087 | cnrhSetSplitBarPos(250);
|
---|
1088 | } END_CNRINFO(hwndCnr);
|
---|
1089 |
|
---|
1090 | WinSetFocus(HWND_DESKTOP, hwndCnr);
|
---|
1091 | }
|
---|
1092 | }
|
---|
1093 | CATCH(excpt1) {} END_CATCH();
|
---|
1094 |
|
---|
1095 | mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
|
---|
1096 | break; }
|
---|
1097 |
|
---|
1098 | case WM_WINDOWPOSCHANGED:
|
---|
1099 | {
|
---|
1100 | PSWP pswp = (PSWP)mp1;
|
---|
1101 | mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
|
---|
1102 | if (pswp->fl & SWP_SIZE)
|
---|
1103 | {
|
---|
1104 | WinSetWindowPos(WinWindowFromID(hwndClient, ID_MEMCNR), // cnr
|
---|
1105 | HWND_TOP,
|
---|
1106 | 0, 0, pswp->cx, pswp->cy,
|
---|
1107 | SWP_SIZE | SWP_MOVE | SWP_SHOW);
|
---|
1108 | }
|
---|
1109 | break; }
|
---|
1110 |
|
---|
1111 | case WM_CONTROL:
|
---|
1112 | {
|
---|
1113 | USHORT usItemID = SHORT1FROMMP(mp1),
|
---|
1114 | usNotifyCode = SHORT2FROMMP(mp1);
|
---|
1115 | if (usItemID == ID_MEMCNR) // cnr
|
---|
1116 | {
|
---|
1117 | switch (usNotifyCode)
|
---|
1118 | {
|
---|
1119 | case CN_CONTEXTMENU:
|
---|
1120 | {
|
---|
1121 | PMEMRECORD precc = (PMEMRECORD)mp2;
|
---|
1122 | if (precc == NULL)
|
---|
1123 | {
|
---|
1124 | // whitespace
|
---|
1125 | HWND hwndMenu = WinCreateMenu(HWND_DESKTOP,
|
---|
1126 | NULL); // no menu template
|
---|
1127 | winhInsertMenuItem(hwndMenu,
|
---|
1128 | MIT_END,
|
---|
1129 | 1001,
|
---|
1130 | "Sort by index",
|
---|
1131 | MIS_TEXT, 0);
|
---|
1132 | winhInsertMenuItem(hwndMenu,
|
---|
1133 | MIT_END,
|
---|
1134 | 1002,
|
---|
1135 | "Sort by source file",
|
---|
1136 | MIS_TEXT, 0);
|
---|
1137 | cnrhShowContextMenu(WinWindowFromID(hwndClient, ID_MEMCNR),
|
---|
1138 | NULL, // record
|
---|
1139 | hwndMenu,
|
---|
1140 | hwndClient);
|
---|
1141 | }
|
---|
1142 | }
|
---|
1143 | }
|
---|
1144 | }
|
---|
1145 | break; }
|
---|
1146 |
|
---|
1147 | case WM_COMMAND:
|
---|
1148 | switch (SHORT1FROMMP(mp1))
|
---|
1149 | {
|
---|
1150 | case 1001: // sort by index
|
---|
1151 | WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
|
---|
1152 | CM_SORTRECORD,
|
---|
1153 | (MPARAM)mnu_fnCompareIndex,
|
---|
1154 | 0);
|
---|
1155 | break;
|
---|
1156 |
|
---|
1157 | case 1002: // sort by source file
|
---|
1158 | WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),
|
---|
1159 | CM_SORTRECORD,
|
---|
1160 | (MPARAM)mnu_fnCompareSourceFile,
|
---|
1161 | 0);
|
---|
1162 | break;
|
---|
1163 | }
|
---|
1164 | break;
|
---|
1165 |
|
---|
1166 | case WM_CLOSE:
|
---|
1167 | WinDestroyWindow(WinWindowFromID(hwndClient, ID_MEMCNR));
|
---|
1168 | WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT));
|
---|
1169 | free(G_pszMemCnrTitle);
|
---|
1170 | G_pszMemCnrTitle = NULL;
|
---|
1171 | break;
|
---|
1172 |
|
---|
1173 | default:
|
---|
1174 | mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
|
---|
1175 | }
|
---|
1176 |
|
---|
1177 | return (mrc);
|
---|
1178 | }
|
---|
1179 |
|
---|
1180 | /*
|
---|
1181 | *@@ memdCreateMemDebugWindow:
|
---|
1182 | * creates a heap debugging window which
|
---|
1183 | * is a standard frame with a container,
|
---|
1184 | * listing all heap objects ever allocated.
|
---|
1185 | *
|
---|
1186 | * The client of this standard frame is in
|
---|
1187 | * memd_fnwpMemDebug.
|
---|
1188 | *
|
---|
1189 | * This thing lists all calls to malloc()
|
---|
1190 | * which were ever made, including the
|
---|
1191 | * source file and source line number which
|
---|
1192 | * made the call. Extreeeemely useful for
|
---|
1193 | * detecting memory leaks.
|
---|
1194 | *
|
---|
1195 | * This only works if the memory functions
|
---|
1196 | * have been replaced with the debug versions
|
---|
1197 | * in this file.
|
---|
1198 | */
|
---|
1199 |
|
---|
1200 | VOID memdCreateMemDebugWindow(VOID)
|
---|
1201 | {
|
---|
1202 | ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_HIDEMAX
|
---|
1203 | | FCF_SIZEBORDER | FCF_SHELLPOSITION
|
---|
1204 | | FCF_NOBYTEALIGN | FCF_TASKLIST;
|
---|
1205 | if (WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),
|
---|
1206 | "XWPMemDebug",
|
---|
1207 | memd_fnwpMemDebug, 0L, 0))
|
---|
1208 | {
|
---|
1209 | HWND hwndClient;
|
---|
1210 | HWND hwndMemFrame = WinCreateStdWindow(HWND_DESKTOP,
|
---|
1211 | 0L,
|
---|
1212 | &flStyle,
|
---|
1213 | "XWPMemDebug",
|
---|
1214 | "Allocated XWorkplace Memory Objects",
|
---|
1215 | 0L,
|
---|
1216 | NULLHANDLE, // resource
|
---|
1217 | 0,
|
---|
1218 | &hwndClient);
|
---|
1219 | if (hwndMemFrame)
|
---|
1220 | {
|
---|
1221 | WinSetWindowPos(hwndMemFrame,
|
---|
1222 | HWND_TOP,
|
---|
1223 | 0, 0, 0, 0,
|
---|
1224 | SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);
|
---|
1225 | }
|
---|
1226 | }
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | #else
|
---|
1230 | void memdDummy(void)
|
---|
1231 | {
|
---|
1232 | int i = 0;
|
---|
1233 | }
|
---|
1234 | #endif
|
---|
1235 |
|
---|