home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwplascr.zip / XWPL0208.ZIP / tools / xpstat / xpstat.c < prev    next >
C/C++ Source or Header  |  2002-04-13  |  59KB  |  1,736 lines

  1.  
  2. /*
  3.  * xpstat.c:
  4.  *      this is the main (and only) .C file for xpstat.exe.
  5.  *
  6.  *      Copyright (C) 2000 Ulrich Möller.
  7.  *      This program is part of the XWorkplace package.
  8.  *      This program is free software; you can redistribute it and/or modify
  9.  *      it under the terms of the GNU General Public License as published by
  10.  *      the Free Software Foundation, in version 2 as it comes in the COPYING
  11.  *      file of the XWorkplace main distribution.
  12.  *      This program is distributed in the hope that it will be useful,
  13.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *      GNU General Public License for more details.
  16.  */
  17.  
  18. #define  INCL_WIN
  19. #define  INCL_WINWORKPLACE
  20. #define  INCL_DOS
  21. #define  INCL_DOSERRORS
  22. #include <os2.h>
  23. #include <stdio.h>
  24.  
  25. #include "setup.h"
  26. #include "helpers\pmprintf.h"
  27.  
  28. #include "helpers\comctl.h"
  29. #include "helpers\cnrh.h"
  30. #include "helpers\dosh.h"
  31. #include "helpers\exeh.h"
  32. #include "helpers\gpih.h"
  33. #include "helpers\linklist.h"
  34. #include "helpers\memdebug.h"
  35. #include "helpers\procstat.h"
  36. #include "helpers\dosh.h"
  37. #include "helpers\stringh.h"
  38. #include "helpers\textview.h"           // PM text view control
  39. #include "helpers\winh.h"
  40. #include "helpers\xstring.h"
  41.  
  42. #include "dlgids.h"
  43.  
  44. #include "xpstat.h"
  45.  
  46.                                 /*
  47.  
  48.                                 if (fl & PAG_COMMIT)
  49.                                     strcat(szInfo, "commit ");
  50.                                 if (fl & PAG_SHARED)
  51.                                     strcat(szInfo, "shared ");
  52.                                 if (fl & PAG_FREE)
  53.                                     strcat(szInfo, "free ");
  54.                                 if (fl & PAG_BASE)
  55.                                     strcat(szInfo, "base ");
  56.                                 if (fl & PAG_READ)
  57.                                     strcat(szInfo, "read ");
  58.                                 if (fl & PAG_WRITE)
  59.                                     strcat(szInfo, "write ");
  60.                                 if (fl & PAG_EXECUTE)
  61.                                     strcat(szInfo, "exec ");
  62.                                 if (fl & PAG_GUARD)
  63.                                     strcat(szInfo, "guard ");
  64. */
  65.  
  66. /* ******************************************************************
  67.  *
  68.  *   Global variables
  69.  *
  70.  ********************************************************************/
  71.  
  72. HAB         G_hab;
  73. HMQ         G_hmq;
  74.  
  75. HWND        G_hwndMain = NULLHANDLE;
  76.  
  77. HMODULE     G_hmodNLS = NULLHANDLE;
  78.  
  79. HWND        G_hwndProcListCnr = NULLHANDLE,
  80.             G_hwndProcView = NULLHANDLE,
  81.             G_hwndSplit = NULLHANDLE,
  82.             G_hMainMenu = NULLHANDLE;
  83.  
  84. const char  *pcszClientClass = "ProcInfoClient";
  85.  
  86. const char  *INIAPP                 = "XWorkplace";
  87. const char  *INIKEY_MAINWINPOS      = "WndPosXpstat";
  88.  
  89. ULONG       G_ulCurrentView = ID_XPSMI_PIDTREE;
  90.  
  91. PQTOPLEVEL32 G_pInfo = NULL;
  92.  
  93. PRECORDCORE G_precSelected = NULL;
  94.  
  95. BOOL        G_fWordWrap = FALSE;
  96.  
  97. QPROCESS32  SysInitProcess =
  98.                 {
  99.                     1,      // rectype
  100.                     NULL,   // pThreads
  101.                     1,      // PID
  102.                     0,      // PPID
  103.                     0,      // FS
  104.                     0,      // state
  105.                     0,      // SID
  106.                     NULLHANDLE, // hmod
  107.                     0,      // thread count
  108.                     0,      // ulPrivSem32Count;
  109.                     0,      // _reserved2_;    // 0 always
  110.                     0,      // usSem16Count;   // count of 16-bit semaphores in pausSem16 array
  111.                     0,      // usModuleCount;  // count of DLLs owned by this process
  112.                     0,      // usShrMemCount;  // count of shared memory items
  113.                     0,      // usFdsCount;     // count of open files; this is mostly way too large
  114.                     0,      // pausSem16;      // ptr to array of 16-bit semaphore handles;
  115.                     0,      // pausModules;    // ptr to array of modules;
  116.                     0,      // pausShrMems;    // ptr to array of shared mem items;
  117.                     0,      // pausFds;        // ptr to array of file handles;
  118.                 };
  119.  
  120. /* ******************************************************************
  121.  *
  122.  *   Miscellaneous
  123.  *
  124.  ********************************************************************/
  125.  
  126. /*
  127.  *@@ fnComparePID:
  128.  *      compare process IDs. Works with PROCRECORD's only.
  129.  */
  130.  
  131. SHORT EXPENTRY fnComparePID(PPROCRECORD p1, PPROCRECORD p2, PVOID pStorage)
  132. {
  133.     if (p1->pProcess && p2->pProcess)
  134.     {
  135.         if (p1->pProcess->usPID < p2->pProcess->usPID)
  136.             return (-1);
  137.         else if (p1->pProcess->usPID > p2->pProcess->usPID)
  138.             return (1);
  139.     }
  140.  
  141.     return (0);
  142. }
  143.  
  144. /*
  145.  *@@ fnCompareSID:
  146.  *      compare session IDs. Works with PROCRECORD's only.
  147.  */
  148.  
  149. SHORT EXPENTRY fnCompareSID(PPROCRECORD p1, PPROCRECORD p2, PVOID pStorage)
  150. {
  151.     if (p1->pProcess && p2->pProcess)
  152.     {
  153.         if (p1->pProcess->ulScreenGroupID < p2->pProcess->ulScreenGroupID)
  154.             return (-1);
  155.         else if (p1->pProcess->ulScreenGroupID > p2->pProcess->ulScreenGroupID)
  156.             return (1);
  157.     }
  158.  
  159.     return (0);
  160. }
  161.  
  162. /*
  163.  *@@ fnComparePSZ:
  164.  *      compare record titles. Works with all RECORDCORE's.
  165.  */
  166.  
  167. SHORT EXPENTRY fnComparePSZ(PRECORDCORE p1, PRECORDCORE p2, PVOID pStorage)
  168. {
  169.     if (p1->pszIcon && p2->pszIcon)
  170.     {
  171.         switch (WinCompareStrings(G_hab,
  172.                                   0, 0,
  173.                                   p1->pszIcon,
  174.                                   p2->pszIcon,
  175.                                   0))
  176.         {
  177.             case WCS_LT: return (-1);
  178.             case WCS_GT: return (1);
  179.         }
  180.     }
  181.  
  182.     return (0);
  183. }
  184.  
  185. /*
  186.  *@@ SetupWindows:
  187.  *
  188.  */
  189.  
  190. VOID SetupWindows(HWND hwndClient)
  191. {
  192.     SPLITBARCDATA sbcd;
  193.     XTEXTVIEWCDATA xtxvCData;
  194.     XFMTPARAGRAPH fmtp;
  195.     G_hwndProcListCnr = WinCreateWindow(hwndClient,
  196.                                         WC_CONTAINER,
  197.                                         "",
  198.                                         WS_VISIBLE,
  199.                                         0, 0, 100, 100,
  200.                                         hwndClient,
  201.                                         HWND_TOP,
  202.                                         ID_PROCLISTCNR,
  203.                                         0,
  204.                                         0);
  205.  
  206.     memset(&xtxvCData, 0, sizeof(xtxvCData));
  207.     xtxvCData.cbData = sizeof(xtxvCData);
  208.     xtxvCData.flStyle = XTXF_HSCROLL | XTXF_VSCROLL
  209.                           | XTXF_AUTOHHIDE | XTXF_AUTOVHIDE;
  210.     xtxvCData.ulXBorder = 20;
  211.     xtxvCData.ulYBorder = 20;
  212.     G_hwndProcView = WinCreateWindow(hwndClient,
  213.                                      WC_XTEXTVIEW,
  214.                                      "",
  215.                                      WS_VISIBLE,
  216.                                      0, 0, 100, 100,
  217.                                      hwndClient,
  218.                                      HWND_TOP,
  219.                                      ID_PROCINFO,
  220.                                      &xtxvCData,
  221.                                      0);
  222.  
  223.     winhSetWindowFont(G_hwndProcView, "10.System VIO");
  224.  
  225.     // change default format
  226.     WinSendMsg(G_hwndProcView,
  227.                TXM_QUERYPARFORMAT,
  228.                (MPARAM)0,       // default format
  229.                (MPARAM)&fmtp);
  230.     fmtp.fWordWrap = FALSE;
  231.     fmtp.lLeftMargin = 0;
  232.     fmtp.lFirstLineMargin = 5;
  233.     WinSendMsg(G_hwndProcView,
  234.                TXM_SETPARFORMAT,
  235.                (MPARAM)0,       // default format
  236.                (MPARAM)&fmtp);
  237.  
  238.     winhSetWindowFont(G_hwndProcListCnr, "9.WarpSans");
  239.  
  240.     sbcd.ulSplitWindowID = ID_PROCSPLIT;
  241.     sbcd.ulCreateFlags = SBCF_VERTICAL | SBCF_PERCENTAGE | SBCF_3DSUNK | SBCF_MOVEABLE;
  242.     sbcd.lPos = 50;
  243.     sbcd.ulLeftOrBottomLimit = 100;
  244.     sbcd.ulRightOrTopLimit = 100;
  245.     sbcd.hwndParentAndOwner = hwndClient;
  246.     G_hwndSplit = ctlCreateSplitWindow(G_hab,
  247.                                        &sbcd);
  248.  
  249.                      // fnwpProcInfoClient,
  250.     WinSendMsg(G_hwndSplit,
  251.                SPLM_SETLINKS,
  252.                (MPARAM)G_hwndProcListCnr,
  253.                (MPARAM)G_hwndProcView);
  254.  
  255.     WinSetFocus(HWND_DESKTOP, G_hwndProcListCnr);
  256. }
  257.  
  258. /*
  259.  *@@ SetupMenu:
  260.  *
  261.  */
  262.  
  263. VOID SetupMenu(VOID)
  264. {
  265.     WinCheckMenuItem(G_hMainMenu,
  266.                      G_ulCurrentView,
  267.                      TRUE);
  268.     WinCheckMenuItem(G_hMainMenu,
  269.                      ID_XPSMI_WORDWRAP,
  270.                      G_fWordWrap);
  271. }
  272.  
  273. /*
  274.  *@@ AppendModuleInfo:
  275.  *
  276.  */
  277.  
  278. VOID AppendModuleInfo(PXSTRING ppszCurrentInfo,
  279.                       PSZ pszModuleName)
  280. {
  281.     CHAR            szTemp[2000];
  282.     PSZ             pszTemp = szTemp;
  283.     PEXECUTABLE     pExec = NULL;
  284.     PSZ             pszExeFormat = "unknown",
  285.                     psz32Bits = "unknown",
  286.                     pszVersion = "not available",
  287.                     pszVendor = "not available",
  288.                     pszDescr = "not available";
  289.     // get module info
  290.     if (exehOpen(pszModuleName,
  291.                      &pExec)
  292.             == NO_ERROR)
  293.     {
  294.         switch (pExec->ulExeFormat)
  295.         {
  296.             case EXEFORMAT_OLDDOS:
  297.                 pszExeFormat = "Old DOS";
  298.             break;
  299.             case EXEFORMAT_NE:
  300.                 pszExeFormat = "New Executable (NE)";
  301.             break;
  302.             case EXEFORMAT_PE:
  303.                 pszExeFormat = "Portable Executable (PE)";
  304.             break;
  305.             case EXEFORMAT_LX:
  306.                 pszExeFormat = "Linear Executable (LX)";
  307.             break;
  308.             case EXEFORMAT_TEXT_BATCH:
  309.                 pszExeFormat = "Text batch file";
  310.             break;
  311.             case EXEFORMAT_TEXT_CMD:
  312.                 pszExeFormat = "Text command file";
  313.             break;
  314.         }
  315.  
  316.         if (pExec->f32Bits)
  317.             psz32Bits = "yes";
  318.         else
  319.             psz32Bits = "no";
  320.  
  321.         if (exehQueryBldLevel(pExec) == NO_ERROR)
  322.         {
  323.             if (pExec->pszVendor)
  324.                 pszVendor = pExec->pszVendor;
  325.             if (pExec->pszVersion)
  326.                 pszVersion = pExec->pszVersion;
  327.             if (pExec->pszInfo)
  328.                 pszDescr = pExec->pszInfo;
  329.         }
  330.     }
  331.  
  332.     pszTemp = szTemp;
  333.     pszTemp += sprintf(pszTemp, "Module format: %s\n", pszExeFormat);
  334.     pszTemp += sprintf(pszTemp, "32-bit module: %s\n", psz32Bits);
  335.     pszTemp += sprintf(pszTemp, "Vendor: %s\n", pszVendor);
  336.     pszTemp += sprintf(pszTemp, "Version: %s\n", pszVersion);
  337.     xstrcat(ppszCurrentInfo, szTemp, 0);
  338.     pszTemp = szTemp;
  339.     pszTemp += sprintf(pszTemp, "Description: %s\n", pszDescr);
  340.     xstrcat(ppszCurrentInfo, szTemp, 0);
  341.  
  342.     if (pExec)
  343.         exehClose(&pExec);
  344. }
  345.  
  346. /* ******************************************************************
  347.  *
  348.  *   "Process list" mode
  349.  *
  350.  ********************************************************************/
  351.  
  352. /*
  353.  *@@ InsertProcessList:
  354.  *      clears the container and inserts all processes by PID.
  355.  *      Gets called by RefreshView().
  356.  */
  357.  
  358. VOID InsertProcessList(HWND hwndCnr,
  359.                        BOOL fSortBySID)     // in: else PID
  360. {
  361.     APIRET arc = NO_ERROR;
  362.     XFIELDINFO    axfi[2];
  363.     ULONG         i = 0;
  364.  
  365.     WinSendMsg(hwndCnr,
  366.                CM_REMOVERECORD,
  367.                (MPARAM)NULL,
  368.                MPFROM2SHORT(0,  // all records
  369.                             CMA_FREE | CMA_INVALIDATE));
  370.  
  371.     BEGIN_CNRINFO()
  372.     {
  373.         cnrhSetView(CV_DETAIL | CA_DETAILSVIEWTITLES);
  374.  
  375.         if (fSortBySID)
  376.         {
  377.             cnrhSetSortFunc(fnCompareSID);
  378.         }
  379.         else
  380.             cnrhSetSortFunc(fnComparePID);
  381.     } END_CNRINFO(G_hwndProcListCnr);
  382.  
  383.     // set up cnr details view
  384.     i = 0;
  385.     axfi[i].ulFieldOffset = FIELDOFFSET(PROCRECORD, pszPID);
  386.     if (fSortBySID)
  387.         axfi[i].pszColumnTitle = "SID";
  388.     else
  389.         axfi[i].pszColumnTitle = "PID";
  390.     axfi[i].ulDataType = CFA_STRING;
  391.     axfi[i++].ulOrientation = CFA_LEFT;
  392.  
  393.     axfi[i].ulFieldOffset = FIELDOFFSET(PROCRECORD, pszModuleName);
  394.     axfi[i].pszColumnTitle = "Process";
  395.     axfi[i].ulDataType = CFA_STRING;
  396.     axfi[i++].ulOrientation = CFA_LEFT;
  397.  
  398.     cnrhClearFieldInfos(G_hwndProcListCnr, FALSE);  // no invalidate
  399.     cnrhSetFieldInfos(G_hwndProcListCnr,
  400.                       axfi,
  401.                       i,
  402.                       TRUE,
  403.                       0);
  404.  
  405.     if (G_pInfo)
  406.     {
  407.         prc32FreeInfo(G_pInfo);
  408.         G_pInfo = NULL;
  409.     }
  410.     G_pInfo = prc32GetInfo(&arc);
  411.  
  412.     if (G_pInfo)
  413.     {
  414.         PQPROCESS32 pProcess = G_pInfo->pProcessData;
  415.         PPROCRECORD precFirst,
  416.                     precThis;
  417.         ULONG cProcesses = 0;
  418.  
  419.         pProcess = G_pInfo->pProcessData;
  420.         while ((pProcess) && (pProcess->ulRecType == 1))
  421.         {
  422.             PQTHREAD32 pThread = pProcess->pThreads;
  423.             for (i = 0;
  424.                  i < pProcess->usThreadCount;
  425.                  i++, pThread++)
  426.                 ;
  427.             pProcess = (PQPROCESS32)pThread;
  428.             cProcesses++;
  429.         }
  430.  
  431.         // insert records
  432.         precFirst = (PPROCRECORD)cnrhAllocRecords(hwndCnr,
  433.                                                   sizeof(PROCRECORD),
  434.                                                   cProcesses);
  435.  
  436.         pProcess = G_pInfo->pProcessData;
  437.         precThis = precFirst;
  438.         while ((pProcess) && (pProcess->ulRecType == 1))
  439.         {
  440.             PQTHREAD32 pThread = pProcess->pThreads;
  441.             for (i = 0;
  442.                  i < pProcess->usThreadCount;
  443.                  i++, pThread++)
  444.                 ;
  445.  
  446.             DosQueryModuleName(pProcess->usHModule,
  447.                                sizeof(precThis->szModuleName),
  448.                                precThis->szModuleName);
  449.  
  450.             if (fSortBySID)
  451.                 sprintf(precThis->szPID, "0x%04lX", pProcess->ulScreenGroupID);
  452.             else
  453.                 sprintf(precThis->szPID, "0x%04lX", pProcess->usPID);
  454.             precThis->pszPID = precThis->szPID;
  455.             sprintf(precThis->szTitle, "%s: %s",
  456.                     precThis->szPID,
  457.                     precThis->szModuleName);
  458.             precThis->pszModuleName = precThis->szModuleName;
  459.  
  460.             precThis->recc.pszIcon
  461.                 = precThis->recc.pszTree
  462.                 = precThis->recc.pszName
  463.                 = precThis->recc.pszText
  464.                 = precThis->szTitle;
  465.             precThis->pProcess = pProcess;
  466.  
  467.  
  468.             pProcess = (PQPROCESS32)pThread;
  469.             precThis = (PPROCRECORD)precThis->recc.preccNextRecord;
  470.         }
  471.  
  472.         cnrhInsertRecords(hwndCnr,
  473.                           NULL,         // parent recc
  474.                           (PRECORDCORE)precFirst,
  475.                           TRUE,
  476.                           NULL,
  477.                           CRA_RECORDREADONLY,
  478.                           cProcesses);
  479.  
  480.     }
  481. }
  482.  
  483. /*
  484.  *@@ DescribeSem32:
  485.  *
  486.  *@@added V0.9.10 (2001-04-08) [umoeller]
  487.  */
  488.  
  489. VOID DescribeSem32(PSZ pszTemp,
  490.                    PQS32SEM32 pSem32)
  491. {
  492.     pszTemp += sprintf(pszTemp,
  493.                        "  %06lX  %8lX %04d",
  494.                        pSem32->ulHandle,
  495.                        pSem32->ulBlockID,
  496.                        pSem32->fl);
  497.     if (pSem32->fl & QS32_DC_SEM_SHARED)
  498.         pszTemp += sprintf(pszTemp, " shared");
  499.     /* if (pSem32->fl & QS32_DC_SEM_PM)
  500.         pszTemp += sprintf(pszTemp, " PM"); */
  501.  
  502.     if (pSem32->fl & QS32_DCM_MUTEX_SEM)
  503.         pszTemp += sprintf(pszTemp, " mutex");
  504.     if (pSem32->fl & QS32_DCE_EVENT_SEM)
  505.         pszTemp += sprintf(pszTemp, " event");
  506.     if (pSem32->fl & QS32_DCMW_MUX_SEM)
  507.         pszTemp += sprintf(pszTemp, " muxwait");
  508.  
  509.     if (pSem32->fl & QS32_DCE_POSTONE)
  510.         pszTemp += sprintf(pszTemp, ", post-one");
  511.     if (pSem32->fl & QS32_DCE_AUTORESET)
  512.         pszTemp += sprintf(pszTemp, ", auto-reset");
  513.  
  514.     if (pSem32->fl & QS32_DCMW_WAIT_ANY)
  515.         pszTemp += sprintf(pszTemp, ", waitAny");
  516.     if (pSem32->fl & QS32_DCMW_WAIT_ALL)
  517.         pszTemp += sprintf(pszTemp, ", waitAll");
  518.     if (pSem32->fl & QS32_DE_POSTED)
  519.         pszTemp += sprintf(pszTemp, ", %dx posted ", pSem32->usPostCount);
  520.     if (pSem32->fl & QS32_DM_OWNER_DIED)
  521.         pszTemp += sprintf(pszTemp, ", owner died");
  522.     if (pSem32->fl & QS32_DMW_MTX_MUX)
  523.         pszTemp += sprintf(pszTemp, ", contains mutexes");
  524.     if (pSem32->fl & QS32_DE_16BIT_MW)
  525.         pszTemp += sprintf(pszTemp, ", part of 16-bit muxwait");
  526.  
  527.     if (pSem32->fl & QS32_DHO_SEM_OPEN)
  528.         pszTemp += sprintf(pszTemp, ", opened by device driver");
  529.  
  530.     if (pSem32->pszName)
  531.         pszTemp += sprintf(pszTemp,
  532.                            "\n                        name: \"%s\"",
  533.                            pSem32->pszName);
  534.     if (pSem32->pvDeviceDriver)
  535.         pszTemp += sprintf(pszTemp,
  536.                            "\n                        ptr: %08lX",
  537.                            pSem32->pvDeviceDriver);
  538.  
  539.     /* if (pSem32->us_)
  540.         pszTemp += sprintf(pszTemp,
  541.                            "\n                        strange us_: %04lX",
  542.                            pSem32->us_);
  543.     if (pSem32->ulElse)
  544.         pszTemp += sprintf(pszTemp,
  545.                            "\n                        else: %08lX",
  546.                            pSem32->ulElse);
  547.     if (pSem32->ulElse2)
  548.         pszTemp += sprintf(pszTemp,
  549.                            "\n                        else2: %08lX",
  550.                            pSem32->ulElse2); */
  551.     strcpy(pszTemp, "\n");
  552. }
  553.  
  554. /*
  555.  *@@ ProcessSelected:
  556.  *      gets called when a new process gets selected
  557.  *      to compose the process information string
  558.  *      displayed on the right.
  559.  */
  560.  
  561. VOID ProcessSelected(VOID)
  562. {
  563.     XSTRING strCurrentInfo;
  564.     xstrInit(&strCurrentInfo, 1000);
  565.  
  566.     strCurrentInfo.ulDelta = 1000;
  567.  
  568.     if (G_precSelected)
  569.     {
  570.         PQPROCESS32 pProcess = ((PPROCRECORD)G_precSelected)->pProcess;
  571.         PQTHREAD32  pThread;
  572.         PSZ         pszSessionType = "unknown";
  573.         CHAR        szTemp[2000],
  574.                     szTemp2[200] = "";
  575.         PSZ         pszTemp = szTemp;
  576.         ULONG       i,
  577.                     cMsgQueues = 0;
  578.  
  579.         pszTemp += sprintf(pszTemp, "PID: 0x%04lX\n", pProcess->usPID);
  580.         pszTemp += sprintf(pszTemp, "Parent PID: 0x%04lX\n", pProcess->usPPID);
  581.         pszTemp += sprintf(pszTemp, "Screen Group ID: 0x%04lX\n", pProcess->ulScreenGroupID);
  582.  
  583.         pszTemp += sprintf(pszTemp, "\nModule: %s\n", ((PPROCRECORD)G_precSelected)->szModuleName);
  584.         xstrcpy(&strCurrentInfo, szTemp, 0);
  585.  
  586.         if (pProcess->usPID == 1)
  587.         {
  588.             // sysinit:
  589.             xstrcat(&strCurrentInfo, "\nKernel pseudo-process.\n", 0);
  590.         }
  591.         else
  592.         {
  593.             // regular process:
  594.             AppendModuleInfo(&strCurrentInfo,
  595.                              ((PPROCRECORD)G_precSelected)->szModuleName);
  596.             // get process type
  597.             switch (pProcess->ulProgType)
  598.             {
  599.                 case 0:
  600.                     pszSessionType = "Full screen protected mode";
  601.                 break;
  602.                 case 1:
  603.                     pszSessionType = "Real mode (probably VDM)";
  604.                 break;
  605.                 case 2:
  606.                     pszSessionType = "VIO windowable protected mode";
  607.                 break;
  608.                 case 3:
  609.                     pszSessionType = "Presentation manager protected mode";
  610.                 break;
  611.                 case 4:
  612.                     pszSessionType = "Detached protected mode";
  613.                 break;
  614.             }
  615.  
  616.             pszTemp = szTemp;
  617.             pszTemp += sprintf(pszTemp, "\nProcess type: %d (%s)\n",
  618.                                pProcess->ulProgType,
  619.                                pszSessionType);
  620.  
  621.             if (pProcess->ulState & STAT_EXITLIST)
  622.                 strcpy(szTemp2, "[processing exit list] ");
  623.             if (pProcess->ulState & STAT_EXIT1)
  624.                 strcat(szTemp2, "[exiting thread 1] ");
  625.             if (pProcess->ulState & STAT_EXITALL)
  626.                 strcat(szTemp2, "[exiting all] ");
  627.             if (pProcess->ulState & STAT_PARSTAT)
  628.                 strcat(szTemp2, "[notify parent on exit] ");
  629.             if (pProcess->ulState & STAT_SYNCH)
  630.                 strcat(szTemp2, "[parent waiting on exit] ");
  631.             if (pProcess->ulState & STAT_DYING)
  632.                 strcat(szTemp2, "[dying] ");
  633.             if (pProcess->ulState & STAT_EMBRYO)
  634.                 strcat(szTemp2, "[embryo] ");
  635.  
  636.             pszTemp += sprintf(pszTemp, "\nulState: 0x%lX %s\n",
  637.                                pProcess->ulState,
  638.                                szTemp2);
  639.  
  640.             // threads
  641.  
  642.             pszTemp += sprintf(pszTemp, "\nThreads: %d\n", pProcess->usThreadCount);
  643.             // header for the following
  644.             pszTemp += sprintf(pszTemp, "  TID Slot SleepID  Prty State HMQ==PMQ\n");
  645.             xstrcat(&strCurrentInfo, szTemp, 0);
  646.  
  647.             // dump threads
  648.             pThread = pProcess->pThreads;
  649.             for (i = 0;
  650.                  i < pProcess->usThreadCount;
  651.                  i++, pThread++)
  652.             {
  653.                 CHAR    szState[30] = "block";
  654.                 HAB     habhmq = 0;
  655.                 HMQ     hmq = 0;
  656.  
  657.                 switch(pThread->ucState)
  658.                 {
  659.                     case 1: strcpy(szState, "ready"); break;
  660.                     case 5: strcpy(szState, "runng"); break;
  661.                     case 9: strcpy(szState, "loadd"); break;
  662.                 }
  663.  
  664.                 pszTemp = szTemp;
  665.                 pszTemp += sprintf(pszTemp,
  666.                                    "  %02d  %04lX %08lX %04lX %s ",
  667.                                    pThread->usTID,
  668.                                    pThread->usSlotID,
  669.                                    pThread->ulSleepID,
  670.                                    pThread->ulPriority,
  671.                                    szState);
  672.                 if (hmq = winhFindMsgQueue(pProcess->usPID,
  673.                                            pThread->usTID,
  674.                                            &habhmq))
  675.                 {
  676.                     pszTemp += sprintf(pszTemp, "0x%lX", hmq);
  677.                     cMsgQueues++;
  678.                 }
  679.  
  680.                 pszTemp += sprintf(pszTemp, "\n");
  681.                 xstrcat(&strCurrentInfo, szTemp, 0);
  682.             }
  683.  
  684.             // dump message queues
  685.             if (cMsgQueues)
  686.             {
  687.                 HENUM   henum = WinBeginEnumWindows(HWND_OBJECT);
  688.                 HWND    hwndThis;
  689.                 pszTemp = szTemp;
  690.                 pszTemp += sprintf(pszTemp, "\nMessage queues: %d\n", cMsgQueues);
  691.                 // header for the following
  692.                 pszTemp += sprintf(pszTemp, "  PMQ        HWND       TID size\n");
  693.                 xstrcat(&strCurrentInfo, szTemp, 0);
  694.  
  695.                 while (hwndThis = WinGetNextWindow(henum))
  696.                 {
  697.                     CHAR    szClass[200];
  698.                     if (WinQueryClassName(hwndThis, sizeof(szClass), szClass))
  699.                     {
  700.                         if (strcmp(szClass, "#32767") == 0)
  701.                         {
  702.                             // is message queue:
  703.                             PID pidWin = 0;
  704.                             TID tidWin = 0;
  705.                             WinQueryWindowProcess(hwndThis,
  706.                                                   &pidWin,
  707.                                                   &tidWin);
  708.                             if (pidWin == pProcess->usPID)
  709.                             {
  710.                                 // is our process:
  711.                                 // get message queue for this
  712.                                 HMQ     hmq = WinQueryWindowULong(hwndThis, QWL_HMQ);
  713.                                 MQINFO  mqi = {0};
  714.                                 ULONG   cb, fl;
  715.  
  716.                                 WinQueryQueueInfo(hmq, &mqi, sizeof(mqi));
  717.  
  718.                                 pszTemp = szTemp;
  719.                                 pszTemp += sprintf(pszTemp, "  0x%08lX 0x%lX %02d  %d",
  720.                                                    hmq, hwndThis, tidWin, mqi.cmsgs);
  721.  
  722.                                 pszTemp += sprintf(pszTemp, "\n");
  723.                                 xstrcat(&strCurrentInfo, szTemp, 0);
  724.                             }
  725.                         }
  726.                     }
  727.                 }
  728.                 WinEndEnumWindows(henum);
  729.             }
  730.  
  731.             // dump public 32-bit semaphores
  732.             sprintf(szTemp, "\nPublic 32-bit semaphores:\n");
  733.             xstrcat(&strCurrentInfo, szTemp, 0);
  734.             if (!G_pInfo->pSem32Data)
  735.                 xstrcat(&strCurrentInfo, "  cannot get data\n", 0);
  736.             else
  737.             {
  738.                 // semaphore data available:
  739.                 PQS32SEM32 pFirst = G_pInfo->pSem32Data,
  740.                            pSem32 = pFirst;
  741.                 ULONG ul;
  742.  
  743.                 xstrcat(&strCurrentInfo,
  744.                         "  handle  blockid  flags           name\n", 0);
  745.  
  746.                 while (pSem32)
  747.                 {
  748.                     DescribeSem32(szTemp, pSem32);
  749.                     xstrcat(&strCurrentInfo, szTemp, 0);
  750.  
  751.                     pSem32 = pSem32->pNext;
  752.                 }
  753.             }
  754.  
  755.             // dump private 32-bit semaphores
  756.             sprintf(szTemp, "\nPrivate 32-bit semaphores: %d\n", pProcess->ulPrivSem32Count);
  757.             xstrcat(&strCurrentInfo, szTemp, 0);
  758.             if (!pProcess->pvPrivSem32s)
  759.                 xstrcat(&strCurrentInfo, "  cannot get data\n", 0);
  760.             else
  761.             {
  762.                 // semaphore data available:
  763.                 PQS32SEM32 pFirst = (PQS32SEM32)pProcess->pvPrivSem32s,
  764.                            pSem32 = pFirst;
  765.                 ULONG ul;
  766.  
  767.                 xstrcat(&strCurrentInfo,
  768.                         "  handle  blockid  flags           name\n", 0);
  769.  
  770.                 for (ul = 0;
  771.                      ul < pProcess->ulPrivSem32Count;
  772.                      ul++)
  773.                 {
  774.                     DescribeSem32(szTemp, pSem32);
  775.                     xstrcat(&strCurrentInfo, szTemp, 0);
  776.  
  777.                     pSem32 = pSem32->pNext;
  778.                 }
  779.             }
  780.  
  781.             // dump 16-bit semaphores
  782.             sprintf(szTemp, "\n16-bit semaphores: %d\n", pProcess->usSem16Count);
  783.             xstrcat(&strCurrentInfo, szTemp, 0);
  784.             if (pProcess->usSem16Count)
  785.             {
  786.                 sprintf(szTemp, "  indx ownr flag cUse cReq \n", pProcess->usSem16Count);
  787.                 xstrcat(&strCurrentInfo, szTemp, 0);
  788.                 for (i = 0;
  789.                      i < pProcess->usSem16Count;
  790.                      i++)
  791.                 {
  792.                     USHORT usSemThis = pProcess->pausSem16[i];
  793.                     PQS32SEM16 pSem16 = prc32FindSem16(G_pInfo, usSemThis);
  794.                     pszTemp = szTemp;
  795.                     pszTemp += sprintf(pszTemp, "  %4d", usSemThis);
  796.                     if (pSem16)
  797.                         pszTemp += sprintf(pszTemp,
  798.                                            " %04lX %04lX %04lX %04lX S%s",
  799.                                            pSem16->usSysSemOwner,
  800.                                            pSem16->fsSysSemFlags,
  801.                                            pSem16->usSysSemRefCnt,
  802.                                            pSem16->usSysSemProcCnt,
  803.                                            pSem16->szName);
  804.  
  805.  
  806.                     strcat(pszTemp, "\n");
  807.                     xstrcat(&strCurrentInfo, szTemp, 0);
  808.                 }
  809.             }
  810.  
  811.             // dump shared memory
  812.             sprintf(szTemp, "\nShared mem: %d references\n", pProcess->usShrMemCount);
  813.             xstrcat(&strCurrentInfo, szTemp, 0);
  814.             if (pProcess->usShrMemCount)
  815.             {
  816.                 sprintf(szTemp, "  shrmID selector cRef\n");
  817.                 xstrcat(&strCurrentInfo, szTemp, 0);
  818.                 for (i = 0;
  819.                      i < pProcess->usShrMemCount;
  820.                      i++)
  821.                 {
  822.                     USHORT  usShrThis = pProcess->pausShrMems[i];
  823.                     PQSHRMEM32 pShrThis = prc32FindShrMem(G_pInfo, usShrThis);
  824.                     pszTemp = szTemp;
  825.                     pszTemp += sprintf(pszTemp, "  0x%04lX", usShrThis);
  826.                     if (pShrThis)
  827.                         pszTemp += sprintf(pszTemp, " 0x%04lX %6d %s",
  828.                                            pShrThis->usSelector,
  829.                                            pShrThis->usRefCount,
  830.                                            pShrThis->acName);
  831.                     strcat(pszTemp, "\n");
  832.                     xstrcat(&strCurrentInfo, szTemp, 0);
  833.                 }
  834.             }
  835.  
  836.             // dump modules
  837.             sprintf(szTemp, "\nModule references (imports): %d\n", pProcess->usModuleCount);
  838.             xstrcat(&strCurrentInfo, szTemp, 0);
  839.             if (pProcess->usModuleCount)
  840.             {
  841.                 for (i = 0;
  842.                      i < pProcess->usModuleCount;
  843.                      i++)
  844.                 {
  845.                     pszTemp = szTemp;
  846.                     pszTemp += sprintf(pszTemp, "  0x%04lX ", pProcess->pausModules[i]);
  847.                     DosQueryModuleName(pProcess->pausModules[i],
  848.                                        sizeof(szTemp),
  849.                                        pszTemp);
  850.                     strcat(pszTemp, "\n");
  851.                     xstrcat(&strCurrentInfo, szTemp, 0);
  852.                 }
  853.             }
  854.  
  855.             // dump open files
  856.             sprintf(szTemp, "\nOpen files: %d\n", pProcess->usFdsCount);
  857.             xstrcat(&strCurrentInfo, szTemp, 0);
  858.             if (pProcess->usFdsCount)
  859.             {
  860.                 xstrcat(&strCurrentInfo,
  861.                          "  sfn  cOpn Flags    Accs  Size hVol attribs\n", 0);
  862.                 for (i = 0;
  863.                      i < pProcess->usFdsCount;
  864.                      i++)
  865.                 {
  866.                     USHORT usFileID = pProcess->pausFds[i];
  867.  
  868.                     szTemp[0] = 0;
  869.                     pszTemp = szTemp;
  870.  
  871.                     pszTemp += sprintf(pszTemp,
  872.                                        "  %04lX",
  873.                                        usFileID);
  874.  
  875.                     if (usFileID)       // rule out "0" file handles
  876.                     {
  877.                         PQFILEDATA32 pFile = prc32FindFileData(G_pInfo, usFileID);
  878.  
  879.                         if (pFile)      // rule out pseudo-file handles
  880.                         {
  881.                             CHAR    szAttribs[] = "......";
  882.                             PSZ     pszAccess = szAttribs;
  883.                             CHAR    szSize[20];
  884.                             PQFDS32 pFileData = pFile->paFiles;
  885.                             USHORT  fsAttribs = pFileData->fsAttribs;
  886.                             *pszAccess++ = (fsAttribs & 0x20) ? 'A' : '-';
  887.                             *pszAccess++ = (fsAttribs & 0x10) ? 'D' : '-';
  888.                             *pszAccess++ = (fsAttribs & 0x08) ? 'L' : '-';
  889.                             *pszAccess++ = (fsAttribs & 0x04) ? 'S' : '-';
  890.                             *pszAccess++ = (fsAttribs & 0x02) ? 'H' : '-';
  891.                             *pszAccess++ = (fsAttribs & 0x01) ? 'R' : '-';
  892.  
  893.                             if (pFileData->ulFileSize > (8*1024*1024))
  894.                                 sprintf(szSize, "%4dM", pFileData->ulFileSize / (8*1024*1024));
  895.                             else if (pFileData->ulFileSize > 1024)
  896.                                 sprintf(szSize, "%4dK", pFileData->ulFileSize / 1024);
  897.                             else
  898.                                 sprintf(szSize, "%4db", pFileData->ulFileSize);
  899.  
  900.                             pszTemp += sprintf(pszTemp,
  901.                                                " %04d %08lx %04x %s %04lX %s ",
  902.                                                pFile->ulCFiles,
  903.                                                pFileData->flFlags,
  904.                                                pFileData->flAccess,
  905.                                                szSize,
  906.                                                pFileData->usHVolume,
  907.                                                szAttribs);
  908.  
  909.                             if ((pFileData->flFlags & FSF_NO_SFT_HANDLE_ALLOCTD) == 0)
  910.                                 // we do have a file handle:
  911.                                 pszTemp += sprintf(pszTemp,
  912.                                                    "%s",
  913.                                                    pFile->szFilename);
  914.                             else
  915.                                 // no SFT file handle allocated:
  916.                                 strcat(szTemp, " [no SFT handle allocated]");
  917.  
  918.                         } // end if (pFile)      // rule out pseudo-file handles
  919.                         else
  920.                             strcat(szTemp, " [cannot find SFT entry]");
  921.  
  922.                     } // end if (usFileID)       // rule out "0" file handles
  923.  
  924.                     strcat(szTemp, "\n");
  925.                     xstrcat(&strCurrentInfo, szTemp, 0);
  926.                 }
  927.             }
  928.         }
  929.     } // end if (G_precSelected)
  930.  
  931.     xstrcat(&strCurrentInfo, "End of dump\n", 0);
  932.  
  933.     WinSetWindowText(G_hwndProcView, strCurrentInfo.psz);
  934.     xstrClear(&strCurrentInfo);
  935. }
  936.  
  937. /* ******************************************************************
  938.  *
  939.  *   "Process tree" mode
  940.  *
  941.  ********************************************************************/
  942.  
  943. /*
  944.  *@@ InsertProcTreeRecord:
  945.  *
  946.  */
  947.  
  948. PPROCRECORD InsertProcTreeRecord(HWND hwndCnr,
  949.                                  PPROCRECORD precParent,
  950.                                  PQPROCESS32 pProcess)
  951. {
  952.     PPROCRECORD prec = (PPROCRECORD)cnrhAllocRecords(hwndCnr,
  953.                                                      sizeof(PROCRECORD),
  954.                                                      1);
  955.     if (pProcess->usPID != 1)
  956.         DosQueryModuleName(pProcess->usHModule,
  957.                            sizeof(prec->szModuleName),
  958.                            prec->szModuleName);
  959.     else
  960.         strcpy(prec->szModuleName, "[sysinit]");
  961.     prec->pszModuleName = prec->szModuleName;
  962.  
  963.     sprintf(prec->szPID, "0x%04lX",
  964.                 pProcess->usPID);
  965.  
  966.     prec->pszPID = prec->szPID;
  967.     sprintf(prec->szTitle, "%s: %s",
  968.             prec->szPID,
  969.             prec->szModuleName);
  970.  
  971.     prec->recc.pszIcon
  972.         = prec->recc.pszTree
  973.         = prec->recc.pszName
  974.         = prec->recc.pszText
  975.         = prec->szTitle;
  976.     prec->pProcess = pProcess;
  977.  
  978.     // insert records
  979.     cnrhInsertRecords(hwndCnr,
  980.                       (PRECORDCORE)precParent,  // parent recc
  981.                       (PRECORDCORE)prec,
  982.                       FALSE,
  983.                       NULL,
  984.                       CRA_RECORDREADONLY | CRA_EXPANDED,
  985.                       1);
  986.     return (prec);
  987. }
  988.  
  989. /*
  990.  *@@ InsertProcessesWithParent:
  991.  *
  992.  */
  993.  
  994. VOID InsertProcessesWithParent(HWND hwndCnr,
  995.                                ULONG ulParentPID,           // initially 0
  996.                                PPROCRECORD precParent)
  997. {
  998.     PQPROCESS32 pProcess = G_pInfo->pProcessData;
  999.     ULONG       i;
  1000.  
  1001.     /* if (ulParentPID == 0)
  1002.     {
  1003.         PPROCRECORD prec = InsertProcTreeRecord(hwndCnr,
  1004.                                                 NULL,
  1005.                                                 &SysInitProcess);        // "sysinit" process
  1006.         InsertProcessesWithParent(hwndCnr,
  1007.                                   1,    // pid of sysinit
  1008.                                   prec);     // preccParent
  1009.     } */
  1010.  
  1011.     while ( (pProcess) && (pProcess->ulRecType == 1) )
  1012.     {
  1013.         PQTHREAD32 pThread = pProcess->pThreads;
  1014.         for (i = 0;
  1015.              i < pProcess->usThreadCount;
  1016.              i++, pThread++)
  1017.             ;
  1018.  
  1019.         if (pProcess->usPPID == ulParentPID)
  1020.         {
  1021.             PPROCRECORD prec = InsertProcTreeRecord(hwndCnr,
  1022.                                                     precParent,
  1023.                                                     pProcess);
  1024.             // recurse for processes which have this proc as parent
  1025.             InsertProcessesWithParent(hwndCnr,
  1026.                                       pProcess->usPID,
  1027.                                       prec);     // preccParent
  1028.         }
  1029.  
  1030.         // next process
  1031.         pProcess = (PQPROCESS32)pThread;
  1032.     }
  1033. }
  1034.  
  1035. /*
  1036.  *@@ InsertProcessTree:
  1037.  *
  1038.  */
  1039.  
  1040. VOID InsertProcessTree(HWND hwndCnr)
  1041. {
  1042.     APIRET arc = NO_ERROR;
  1043.     XFIELDINFO    axfi[2];
  1044.     ULONG         i = 0;
  1045.  
  1046.     WinSendMsg(hwndCnr,
  1047.                CM_REMOVERECORD,
  1048.                (MPARAM)NULL,
  1049.                MPFROM2SHORT(0,  // all records
  1050.                             CMA_FREE | CMA_INVALIDATE));
  1051.  
  1052.     // clear cnr details view
  1053.     cnrhClearFieldInfos(G_hwndProcListCnr, FALSE);  // no invalidate
  1054.  
  1055.     BEGIN_CNRINFO()
  1056.     {
  1057.         cnrhSetView(CV_TREE | CV_TEXT | CA_TREELINE);
  1058.         cnrhSetSortFunc(fnComparePID);
  1059.         cnrhSetTreeIndent(20);
  1060.     } END_CNRINFO(G_hwndProcListCnr);
  1061.  
  1062.     if (G_pInfo)
  1063.     {
  1064.         prc32FreeInfo(G_pInfo);
  1065.         G_pInfo = NULL;
  1066.     }
  1067.     G_pInfo = prc32GetInfo(&arc);
  1068.  
  1069.     if (G_pInfo)
  1070.     {
  1071.         PQPROCESS32 pProcess = G_pInfo->pProcessData;
  1072.         PPROCRECORD precFirst,
  1073.                     precThis;
  1074.         ULONG cProcesses = 0;
  1075.  
  1076.         pProcess = G_pInfo->pProcessData;
  1077.         while ((pProcess) && (pProcess->ulRecType == 1))
  1078.         {
  1079.             PQTHREAD32 pThread = pProcess->pThreads;
  1080.             for (i = 0;
  1081.                  i < pProcess->usThreadCount;
  1082.                  i++, pThread++)
  1083.                 ;
  1084.             pProcess = (PQPROCESS32)pThread;
  1085.             cProcesses++;
  1086.         }
  1087.  
  1088.         // insert records
  1089.         InsertProcessesWithParent(hwndCnr,
  1090.                                   0,
  1091.                                   NULL);     // preccParent
  1092.  
  1093.         cnrhInvalidateAll(hwndCnr);
  1094.     }
  1095. }
  1096.  
  1097. /* ******************************************************************
  1098.  *
  1099.  *   "Module tree" mode
  1100.  *
  1101.  ********************************************************************/
  1102.  
  1103. /*
  1104.  *@@ InsertModule2Parent:
  1105.  *
  1106.  */
  1107.  
  1108. PMODRECORD InsertModule2Parent(HWND hwndCnr,
  1109.                                PQMODULE32 pModule,
  1110.                                PMODRECORD precParent)
  1111. {
  1112.     PSZ     p;
  1113.     PMODRECORD prec = (PMODRECORD)cnrhAllocRecords(hwndCnr,
  1114.                                                    sizeof(MODRECORD),
  1115.                                                    1);
  1116.     DosQueryModuleName(pModule->usHModule,
  1117.                        sizeof(prec->szModuleName),
  1118.                        prec->szModuleName);
  1119.     prec->pszModuleName = prec->szModuleName;
  1120.  
  1121.     p = strrchr(prec->szModuleName, '\\');
  1122.     if (p)
  1123.         p++;
  1124.     else
  1125.         p = prec->szModuleName;
  1126.  
  1127.     prec->recc.pszIcon
  1128.         = prec->recc.pszTree
  1129.         = prec->recc.pszName
  1130.         = prec->recc.pszText
  1131.         = p;
  1132.  
  1133.     prec->pModule = pModule;
  1134.  
  1135.     // insert records
  1136.     cnrhInsertRecords(hwndCnr,
  1137.                       (PRECORDCORE)precParent,  // parent recc
  1138.                       (PRECORDCORE)prec,
  1139.                       FALSE,
  1140.                       NULL,
  1141.                       CRA_RECORDREADONLY | CRA_COLLAPSED,
  1142.                       1);
  1143.  
  1144.     return (prec);
  1145. }
  1146.  
  1147. /*
  1148.  *@@ InsertModulesTree:
  1149.  *
  1150.  */
  1151.  
  1152. VOID InsertModulesTree(HWND hwndCnr)
  1153. {
  1154.     APIRET arc = NO_ERROR;
  1155.     XFIELDINFO    axfi[2];
  1156.     ULONG         i = 0;
  1157.  
  1158.     WinSendMsg(hwndCnr,
  1159.                CM_REMOVERECORD,
  1160.                (MPARAM)NULL,
  1161.                MPFROM2SHORT(0,  // all records
  1162.                             CMA_FREE | CMA_INVALIDATE));
  1163.  
  1164.     // clear cnr details view
  1165.     cnrhClearFieldInfos(G_hwndProcListCnr, FALSE);  // no invalidate
  1166.  
  1167.     BEGIN_CNRINFO()
  1168.     {
  1169.         cnrhSetView(CV_TREE | CV_TEXT | CA_TREELINE);
  1170.         cnrhSetSortFunc(fnComparePSZ);
  1171.         cnrhSetTreeIndent(20);
  1172.     } END_CNRINFO(G_hwndProcListCnr);
  1173.  
  1174.     if (G_pInfo)
  1175.     {
  1176.         prc32FreeInfo(G_pInfo);
  1177.         G_pInfo = NULL;
  1178.     }
  1179.     G_pInfo = prc32GetInfo(&arc);
  1180.  
  1181.     if (G_pInfo)
  1182.     {
  1183.         PQMODULE32 pModule = G_pInfo->pModuleData;
  1184.  
  1185.         while (pModule)
  1186.         {
  1187.             // insert records; this recurses
  1188.             InsertModule2Parent(hwndCnr,
  1189.                                 pModule,
  1190.                                 NULL);     // preccParent
  1191.             pModule = pModule->pNext;
  1192.         }
  1193.     }
  1194. }
  1195.  
  1196. /*
  1197.  *@@ ModuleSelected:
  1198.  *
  1199.  */
  1200.  
  1201. VOID ModuleSelected(VOID)
  1202. {
  1203.     XSTRING strCurrentInfo;
  1204.     xstrInit(&strCurrentInfo, 40);
  1205.  
  1206.     if (G_precSelected)
  1207.     {
  1208.         PMODRECORD  precSelected = (PMODRECORD)G_precSelected;
  1209.         PQMODULE32  pModule = precSelected->pModule,
  1210.                     pModule2;
  1211.         PQPROCESS32 pProcess = G_pInfo->pProcessData;
  1212.  
  1213.         CHAR        szTemp[2000],
  1214.                     szTemp2[200] = "";
  1215.         PSZ         pszTemp = szTemp;
  1216.  
  1217.         ULONG   i,
  1218.                 cProcCount = 0;
  1219.  
  1220.         pszTemp += sprintf(pszTemp, "Module name: %s\n", precSelected->szModuleName);
  1221.         pszTemp += sprintf(pszTemp, "Module handle: 0x%04lX\n", pModule->usHModule);
  1222.         xstrcpy(&strCurrentInfo, szTemp, 0);
  1223.  
  1224.         // module flags
  1225.         pszTemp = szTemp;
  1226.         pszTemp += sprintf(pszTemp, "Module flags: 0x%04lX\n", pModule->fFlat);
  1227.         pszTemp += sprintf(pszTemp, "Segments: %d\n\n", pModule->cObjects);
  1228.         xstrcat(&strCurrentInfo, szTemp, 0);
  1229.  
  1230.         // module info
  1231.         AppendModuleInfo(&strCurrentInfo,
  1232.                          precSelected->szModuleName);
  1233.  
  1234.         // find processes using this module
  1235.         pszTemp = szTemp;
  1236.         pszTemp += sprintf(pszTemp, "\nProcesses using this module directly:\n");
  1237.         xstrcat(&strCurrentInfo, szTemp, 0);
  1238.  
  1239.         pProcess = G_pInfo->pProcessData;
  1240.         while ((pProcess) && (pProcess->ulRecType == 1))
  1241.         {
  1242.             PQTHREAD32 pThread = pProcess->pThreads;
  1243.             if (pProcess->usModuleCount)
  1244.             {
  1245.                 for (i = 0;
  1246.                      i < pProcess->usModuleCount;
  1247.                      i++)
  1248.                 {
  1249.                     if (pProcess->pausModules[i] == pModule->usHModule)
  1250.                     {
  1251.                         // this proc uses this module:
  1252.                         // store process name
  1253.                         strcpy(szTemp, "    ");
  1254.                         DosQueryModuleName(pProcess->usHModule,
  1255.                                            sizeof(szTemp) - 4,
  1256.                                            szTemp + 4);
  1257.                         strcat(szTemp, "\n");
  1258.                         xstrcat(&strCurrentInfo, szTemp, 0);
  1259.                         cProcCount++;
  1260.                     }
  1261.                 }
  1262.             }
  1263.  
  1264.             // next process
  1265.             for (i = 0;
  1266.                  i < pProcess->usThreadCount;
  1267.                  i++, pThread++)
  1268.                 ;
  1269.             pProcess = (PQPROCESS32)pThread;
  1270.         }
  1271.  
  1272.         pszTemp = szTemp;
  1273.         if (cProcCount == 0)
  1274.             pszTemp += sprintf(pszTemp, "    none\n");
  1275.         else
  1276.             pszTemp += sprintf(pszTemp, "Total: %d processes\n", cProcCount);
  1277.         xstrcat(&strCurrentInfo, szTemp, 0);
  1278.  
  1279.         // other modules using this module
  1280.         pszTemp = szTemp;
  1281.         pszTemp += sprintf(pszTemp, "\nOther modules using this module:\n");
  1282.         xstrcat(&strCurrentInfo, szTemp, 0);
  1283.  
  1284.         cProcCount = 0;
  1285.         pModule2 = G_pInfo->pModuleData;
  1286.         while (pModule2)
  1287.         {
  1288.             if (pModule2->ulRefCount)
  1289.             {
  1290.                 for (i = 0;
  1291.                      i < pModule2->ulRefCount;
  1292.                      i++)
  1293.                 {
  1294.                     if (pModule2->ausModRef[i] == pModule->usHModule)
  1295.                     {
  1296.                         pszTemp = szTemp;
  1297.                         DosQueryModuleName(pModule2->usHModule,
  1298.                                            sizeof(szTemp2),
  1299.                                            szTemp2);
  1300.                         pszTemp += sprintf(pszTemp, "    0x%04lX: %s\n",
  1301.                                            pModule2->usHModule,
  1302.                                            szTemp2);
  1303.                         xstrcat(&strCurrentInfo, szTemp, 0);
  1304.                         cProcCount++;
  1305.                     }
  1306.                 }
  1307.             }
  1308.  
  1309.             pModule2 = pModule2->pNext;
  1310.         }
  1311.  
  1312.         pszTemp = szTemp;
  1313.         if (cProcCount == 0)
  1314.             pszTemp += sprintf(pszTemp, "    none\n");
  1315.         else
  1316.             pszTemp += sprintf(pszTemp, "Total: %d modules\n", cProcCount);
  1317.         xstrcat(&strCurrentInfo, szTemp, 0);
  1318.  
  1319.         // references
  1320.         pszTemp = szTemp;
  1321.         pszTemp += sprintf(pszTemp, "\nModule references (imports, inserted into tree): %d\n", pModule->ulRefCount);
  1322.         xstrcat(&strCurrentInfo, szTemp, 0);
  1323.  
  1324.         if (pModule->ulRefCount)
  1325.         {
  1326.             BOOL        fMarkSelected = FALSE;
  1327.             for (i = 0;
  1328.                  i < pModule->ulRefCount;
  1329.                  i++)
  1330.             {
  1331.                 pszTemp = szTemp;
  1332.                 DosQueryModuleName(pModule->ausModRef[i],
  1333.                                    sizeof(szTemp2),
  1334.                                    szTemp2);
  1335.                 pszTemp += sprintf(pszTemp, "    0x%04lX: %s\n",
  1336.                                    pModule->ausModRef[i],
  1337.                                    szTemp2);
  1338.                 xstrcat(&strCurrentInfo, szTemp, 0);
  1339.  
  1340.                 if (    (!precSelected->fSubModulesInserted)
  1341.                      && (pModule->ausModRef[i] != pModule->usHModule)
  1342.                    )
  1343.                 {
  1344.                     PQMODULE32 pSubModule = prc32FindModule(G_pInfo,
  1345.                                                             pModule->ausModRef[i]);
  1346.                     if (pSubModule)
  1347.                         InsertModule2Parent(G_hwndProcListCnr,
  1348.                                             pSubModule,
  1349.                                             precSelected);
  1350.                     fMarkSelected = TRUE;
  1351.                 }
  1352.             }
  1353.  
  1354.             if (fMarkSelected)
  1355.                 precSelected->fSubModulesInserted = TRUE;
  1356.         }
  1357.     } // end if (G_precSelected)
  1358.  
  1359.     xstrcat(&strCurrentInfo, "End of dump\n", 0);
  1360.  
  1361.     WinSetWindowText(G_hwndProcView, strCurrentInfo.psz);
  1362.     xstrClear(&strCurrentInfo);
  1363. }
  1364.  
  1365. /* ******************************************************************
  1366.  *
  1367.  *   General view stuff
  1368.  *
  1369.  ********************************************************************/
  1370.  
  1371. /*
  1372.  *@@ RefreshView:
  1373.  *
  1374.  */
  1375.  
  1376. VOID RefreshView(VOID)
  1377. {
  1378.     switch (G_ulCurrentView)
  1379.     {
  1380.         case ID_XPSMI_PIDLIST:
  1381.             InsertProcessList(G_hwndProcListCnr, FALSE);
  1382.         break;
  1383.  
  1384.         case ID_XPSMI_SIDLIST:
  1385.             InsertProcessList(G_hwndProcListCnr, TRUE);
  1386.         break;
  1387.  
  1388.         case ID_XPSMI_PIDTREE:
  1389.             InsertProcessTree(G_hwndProcListCnr);
  1390.         break;
  1391.  
  1392.         case ID_XPSMI_MODTREE:
  1393.             InsertModulesTree(G_hwndProcListCnr);
  1394.         break;
  1395.     }
  1396. }
  1397.  
  1398. BOOL APIENTRY PrintCallback(ULONG ulPage,
  1399.                             ULONG ulUser)
  1400. {
  1401.     CHAR    szMsg[1000];
  1402.     sprintf(szMsg, "Page %d. Continue?", ulPage);
  1403.  
  1404.     if (winhYesNoBox("Printing", szMsg) == MBID_YES)
  1405.         return (TRUE);
  1406.     else
  1407.         return (FALSE);
  1408. }
  1409.  
  1410. /*
  1411.  *@@ fnwpProcInfoClient:
  1412.  *
  1413.  */
  1414.  
  1415. MRESULT EXPENTRY fnwpProcInfoClient(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)
  1416. {
  1417.     MRESULT mrc = 0;
  1418.  
  1419.     switch (msg)
  1420.     {
  1421.         case WM_CREATE:
  1422.             SetupWindows(hwndClient);
  1423.             RefreshView();
  1424.             mrc = (MPARAM)FALSE;        // continue;
  1425.         break;
  1426.  
  1427.         /*
  1428.          * WM_WINDOWPOSCHANGED:
  1429.          *
  1430.          */
  1431.  
  1432.         case WM_WINDOWPOSCHANGED:
  1433.         {
  1434.             // this msg is passed two SWP structs:                    WM_SIZE
  1435.             // one for the old, one for the new data
  1436.             // (from PM docs)
  1437.             PSWP pswpNew = PVOIDFROMMP(mp1);
  1438.             // PSWP pswpOld = pswpNew + 1;
  1439.  
  1440.             // resizing?
  1441.             if (pswpNew->fl & SWP_SIZE)
  1442.             {
  1443.                 WinSetWindowPos(G_hwndSplit, HWND_TOP,
  1444.                                 0, 0,
  1445.                                 pswpNew->cx, pswpNew->cy, // sCXNew, sCYNew,
  1446.                                 SWP_SIZE);
  1447.             }
  1448.  
  1449.             // return default NULL
  1450.         break; }
  1451.  
  1452.         case WM_CONTROL:
  1453.         {
  1454.             USHORT  usID = SHORT1FROMMP(mp1);
  1455.             USHORT  usNotifyCode = SHORT2FROMMP(mp1);
  1456.  
  1457.             if (usID == ID_PROCLISTCNR)
  1458.                 switch (usNotifyCode)
  1459.                 {
  1460.                     case CN_EMPHASIS:
  1461.                     {
  1462.                         PNOTIFYRECORDEMPHASIS pnre = (PNOTIFYRECORDEMPHASIS)mp2;
  1463.  
  1464.                         if (pnre->pRecord)
  1465.                             if (pnre->pRecord->flRecordAttr & CRA_SELECTED)
  1466.                             {
  1467.                                 G_precSelected = pnre->pRecord;
  1468.  
  1469.                                 switch (G_ulCurrentView)
  1470.                                 {
  1471.                                     case ID_XPSMI_PIDLIST:
  1472.                                     case ID_XPSMI_SIDLIST:
  1473.                                     case ID_XPSMI_PIDTREE:
  1474.                                         ProcessSelected();
  1475.                                     break;
  1476.  
  1477.                                     case ID_XPSMI_MODTREE:
  1478.                                         ModuleSelected();
  1479.                                     break;
  1480.                                 }
  1481.                             }
  1482.                     break; }
  1483.                 }
  1484.  
  1485.         break; }
  1486.  
  1487.         case WM_COMMAND:
  1488.         {
  1489.             SHORT sCommand = SHORT1FROMMP(mp1);
  1490.             switch (sCommand)
  1491.             {
  1492.                 case ID_XPSMI_EXIT:
  1493.                     WinPostMsg(WinQueryWindow(hwndClient, QW_PARENT),
  1494.                                WM_CLOSE,
  1495.                                0, 0);
  1496.                 break;
  1497.  
  1498.                 case ID_XPSMI_PIDLIST:
  1499.                 case ID_XPSMI_SIDLIST:
  1500.                 case ID_XPSMI_PIDTREE:
  1501.                 case ID_XPSMI_MODTREE:
  1502.                     if (G_ulCurrentView != sCommand)
  1503.                     {
  1504.                         WinCheckMenuItem(G_hMainMenu,
  1505.                                          G_ulCurrentView,
  1506.                                          FALSE);
  1507.                         G_ulCurrentView = sCommand;
  1508.                         RefreshView();
  1509.                         SetupMenu();
  1510.                     }
  1511.                 break;
  1512.  
  1513.                 case ID_XPSMI_REFRESH:
  1514.                     RefreshView(); // InsertProcessList(G_hwndProcListCnr);
  1515.                 break;
  1516.  
  1517.                 case ID_XPSMI_WORDWRAP:
  1518.                     G_fWordWrap = !G_fWordWrap;
  1519.                     SetupMenu();
  1520.                     WinSendMsg(G_hwndProcView,
  1521.                                TXM_SETWORDWRAP,
  1522.                                (MPARAM)G_fWordWrap,
  1523.                                0);
  1524.                 break;
  1525.             }
  1526.         break; }
  1527.  
  1528.         case WM_CHAR:
  1529.         {
  1530.             USHORT usFlags    = SHORT1FROMMP(mp1);
  1531.             USHORT usch       = SHORT1FROMMP(mp2);
  1532.             USHORT usvk       = SHORT2FROMMP(mp2);
  1533.  
  1534.             if (    (usFlags & KC_VIRTUALKEY)
  1535.                  && (usvk == VK_TAB)
  1536.                )
  1537.             {
  1538.                 if ((usFlags & KC_KEYUP) == 0)
  1539.                     if (WinQueryFocus(HWND_DESKTOP) == G_hwndProcListCnr)
  1540.                         WinSetFocus(HWND_DESKTOP, G_hwndProcView);
  1541.                     else
  1542.                         WinSetFocus(HWND_DESKTOP, G_hwndProcListCnr);
  1543.             }
  1544.             else
  1545.             {
  1546.                 if (    (usch == 'p')
  1547.                      && (usFlags & KC_CTRL)
  1548.                    )
  1549.                 {
  1550.                     CHAR szRet[100];
  1551.                     DosBeep(1000, 100);
  1552.                     sprintf(szRet, "return code: %d",
  1553.                             txvPrintWindow(G_hwndProcView,
  1554.                                            "Process dump",
  1555.                                            PrintCallback));
  1556.  
  1557.                     winhDebugBox(0, "print", szRet);
  1558.                 }
  1559.             }
  1560.             mrc = (MPARAM)TRUE;
  1561.         break; }
  1562.  
  1563.         case WM_CLOSE:
  1564.             winhSaveWindowPos(G_hwndMain,
  1565.                               HINI_USER,
  1566.                               INIAPP,
  1567.                               INIKEY_MAINWINPOS);
  1568.             mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
  1569.         break;
  1570.  
  1571.         default:
  1572.             mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);
  1573.     }
  1574.  
  1575.     return (mrc);
  1576. }
  1577.  
  1578. /*
  1579.  *@@ LoadNLS:
  1580.  *      load NLS interface.
  1581.  *
  1582.  */
  1583.  
  1584. BOOL LoadNLS(VOID)
  1585. {
  1586.     CHAR        szNLSDLL[2*CCHMAXPATH];
  1587.     BOOL Proceed = TRUE;
  1588.  
  1589.     if (PrfQueryProfileString(HINI_USER,
  1590.                               "XWorkplace",
  1591.                               "XFolderPath",
  1592.                               "",
  1593.                               szNLSDLL, sizeof(szNLSDLL)) < 3)
  1594.  
  1595.     {
  1596.         WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1597.                       "xpstat was unable to determine the location of the "
  1598.                       "XWorkplace National Language Support DLL, which is "
  1599.                       "required for operation. The OS2.INI file does not contain "
  1600.                       "this information. "
  1601.                       "xpstat cannot proceed. Please re-install XWorkplace.",
  1602.                       "xpstat: Fatal Error",
  1603.                       0, MB_OK | MB_MOVEABLE);
  1604.         Proceed = FALSE;
  1605.     }
  1606.     else
  1607.     {
  1608.         CHAR    szLanguageCode[50] = "";
  1609.  
  1610.         // now compose module name from language code
  1611.         PrfQueryProfileString(HINI_USERPROFILE,
  1612.                               "XWorkplace", "Language",
  1613.                               "001",
  1614.                               (PVOID)szLanguageCode,
  1615.                               sizeof(szLanguageCode));
  1616.         strcat(szNLSDLL, "\\bin\\xfldr");
  1617.         strcat(szNLSDLL, szLanguageCode);
  1618.         strcat(szNLSDLL, ".dll");
  1619.  
  1620.         // try to load the module
  1621.         if (DosLoadModule(NULL,
  1622.                           0,
  1623.                           szNLSDLL,
  1624.                           &G_hmodNLS))
  1625.         {
  1626.             CHAR    szMessage[2000];
  1627.             sprintf(szMessage,
  1628.                     "xpstat was unable to load \"%s\", "
  1629.                     "the National Language DLL which "
  1630.                     "is specified for XWorkplace in OS2.INI.",
  1631.                     szNLSDLL);
  1632.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1633.                           szMessage,
  1634.                           "xpstat: Fatal Error",
  1635.                           0, MB_OK | MB_MOVEABLE);
  1636.             Proceed = FALSE;
  1637.         }
  1638.     }
  1639.     return (Proceed);
  1640. }
  1641.  
  1642. /*
  1643.  * main:
  1644.  *      program entry point.
  1645.  */
  1646.  
  1647. int main(int argc, char *argv[])
  1648. {
  1649.     QMSG        qmsg;
  1650.  
  1651.     if (!(G_hab = WinInitialize(0)))
  1652.         return FALSE;
  1653.  
  1654.     if (!(G_hmq = WinCreateMsgQueue(G_hab, 0)))
  1655.         return FALSE;
  1656.  
  1657.     // now attempt to find the XWorkplace NLS resource DLL,
  1658.     // which we need for all resources (new with XWP 0.9.0)
  1659.     if (LoadNLS())
  1660.     {
  1661.         SWP swpFrame;
  1662.  
  1663.         swpFrame.x = 100;
  1664.         swpFrame.y = 100;
  1665.         swpFrame.cx = 500;
  1666.         swpFrame.cy = 500;
  1667.         swpFrame.hwndInsertBehind = HWND_TOP;
  1668.         swpFrame.fl = SWP_MOVE | SWP_SIZE;
  1669.  
  1670.         if (    WinRegisterClass(G_hab,
  1671.                                  (PSZ)pcszClientClass,
  1672.                                  fnwpProcInfoClient,
  1673.                                  CS_SIZEREDRAW | CS_SYNCPAINT,
  1674.                                  sizeof(PVOID))
  1675.              && txvRegisterTextView(G_hab)
  1676.             )
  1677.         {
  1678.             HPOINTER hptrMain = WinLoadPointer(HWND_DESKTOP,
  1679.                                                NULLHANDLE,
  1680.                                                1);
  1681.             HWND hwndClient;
  1682.             G_hwndMain = winhCreateStdWindow(HWND_DESKTOP,
  1683.                                              &swpFrame,
  1684.                                              FCF_SYSMENU
  1685.                                              | FCF_SIZEBORDER
  1686.                                              | FCF_TITLEBAR
  1687.                                              | FCF_MINMAX
  1688.                                              | FCF_NOBYTEALIGN,
  1689.                                              WS_CLIPCHILDREN,
  1690.                                              "xpstat",
  1691.                                              0,
  1692.                                              (PSZ)pcszClientClass,
  1693.                                              WS_VISIBLE,
  1694.                                              0,
  1695.                                              NULL,
  1696.                                              &hwndClient);
  1697.             G_hMainMenu = WinLoadMenu(G_hwndMain,
  1698.                                       NULLHANDLE,
  1699.                                       ID_XPSM_MAIN);
  1700.  
  1701.             // now position the frame and the client:
  1702.             // 1) frame
  1703.             if (!winhRestoreWindowPos(G_hwndMain,
  1704.                                       HINI_USER,
  1705.                                       INIAPP,
  1706.                                       INIKEY_MAINWINPOS,
  1707.                                       SWP_MOVE | SWP_SIZE))
  1708.                 // INI data not found:
  1709.                 WinSetWindowPos(G_hwndMain,
  1710.                                 HWND_TOP,
  1711.                                 100, 100,
  1712.                                 500, 500,
  1713.                                 SWP_MOVE | SWP_SIZE);
  1714.  
  1715.             SetupMenu();
  1716.  
  1717.             // add to task list
  1718.             winhAddToTasklist(G_hwndMain,
  1719.                               hptrMain);
  1720.             // finally, show window
  1721.             WinShowWindow(G_hwndMain, TRUE);
  1722.  
  1723.             while (WinGetMsg(G_hab, &qmsg, 0, 0, 0))
  1724.                 WinDispatchMsg(G_hab, &qmsg);
  1725.         }
  1726.     } // end if (proceed)
  1727.  
  1728.     // clean up on the way out
  1729.     WinDestroyMsgQueue(G_hmq);
  1730.     WinTerminate(G_hab);
  1731.  
  1732.     return TRUE;
  1733. }
  1734.  
  1735.  
  1736.