home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / memdebug_win.c < prev    next >
C/C++ Source or Header  |  2002-06-02  |  31KB  |  847 lines

  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. #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.  
  74. PSZ             G_pszMemCnrTitle = NULL;
  75. HWND            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.  
  89. typedef 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;
  122. ULONG       ulTotalAllocated,
  123.             ulTotalFreed;
  124. PMEMRECORD  pMemRecordThis = NULL;
  125. PSZ         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.  
  274. static 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.     BOOL        fLocked = FALSE;
  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 occured 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.  
  413. static 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.  
  431. static 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.  
  460. static 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.  
  480. static 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.  
  514. MRESULT 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.  
  810. VOID 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
  840. void memdDummy2(void)
  841. {
  842.     int i = 0;
  843.     i++;
  844. }
  845. #endif
  846.  
  847.