home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / CHAP5.ZIP / WINTASK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  14.5 KB  |  544 lines

  1. /*
  2.     WINTASK.C -- Windows task list browser
  3.  
  4.     From Chapter 5 of "Undocumented Windows" (Addison-Wesley 1992)
  5.     by Andrew Schulman, Dave Maxey and Matt Pietrek
  6.  
  7.     Build using: WINIOBC WINTASK (for Borland C++ v3.00)
  8.                  WINIOMS WINTASK (for Microsoft C/SDK)
  9. */
  10.  
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <dos.h>
  16. #include "winio.h"
  17.  
  18. #include "taskdb.h"
  19. #include "taskq.h"
  20. #include "psp.h"
  21.  
  22. #ifndef __BORLANDC__
  23. #define asm _asm
  24. #define MK_FP(a,b)  ((void far *)(((unsigned long)(a) << 16) | (b))) 
  25. #endif
  26.  
  27. #define NE_SIGNATURE            0x454E
  28. #define TDB_SIGNATURE           0x4454
  29. #define TDB_SIGNATURE_OFFSET    0x00FA
  30. #define TDB_MODULE_NAME_OFFSET  0x00F2
  31. #define PSP_LENGTH              0x0100
  32. #define PSP_SIGNATURE           0x20CD
  33.  
  34. #define WIDTH 25
  35.  
  36. WORD WinVersion;
  37.  
  38. //---------------------------------------------
  39. // Converts a global handle to a selector value.
  40. // The proper way would be to use GlobalLock, but
  41. // GlobalLock will RIP on certain selectors.
  42. // TOOLHELP does it like this, so...
  43. //---------------------------------------------
  44.  
  45. WORD HandleToSel(HANDLE h)
  46. {
  47.     // In 3.1, handles = (selectors-1)
  48.     // Valid selectors end in a 7 or a F
  49.     // Thus, we can simply make sure the
  50.     // lowest bit is turned on.
  51.     // 
  52.     // In 3.0, handles = (selectors+1)
  53.     // Valid selectors end in a 5 or a D
  54.     // Decrement the handle if it's an
  55.     // even value.
  56.  
  57.     if ( WinVersion == 0x030A )
  58.         h |= 0x0001;
  59.         
  60.     else if ( WinVersion < 0x030A )
  61.         if ( (h & 0x0002) == 0x0002 )
  62.             h--;
  63.         
  64.     return h;
  65. }
  66.  
  67.  
  68. //---------------------------------------------
  69. // Returns a BOOL indicating whether the passed
  70. // in handle is an HTASK.  In Windows 3.1, you
  71. // could call IsTask()
  72. //---------------------------------------------
  73.  
  74. BOOL IsATask(HANDLE hTask)
  75. {
  76.     WORD segLen;
  77.     BOOL segOK=FALSE;
  78.     WORD far *signature;
  79.  
  80.     // Make sure that it's ok to read from the passed in handle/selector
  81.  
  82.     asm {
  83.             mov     ax, [hTask]
  84.             cmp     ax, 0
  85.             je      mylabel
  86.             lsl     bx, ax
  87.             jnz     mylabel
  88.             mov     [segLen], bx
  89.             mov     [segOK], 1
  90.     }
  91.     
  92.     mylabel:
  93.     
  94.     // Make sure that the segment is long enough, and then
  95.     // look for the 'TD' signature
  96.         
  97.     if ( !segOK || (segLen < TDB_SIGNATURE_OFFSET+2) )
  98.         return FALSE;
  99.     
  100.     signature = MK_FP(hTask, TDB_SIGNATURE_OFFSET);
  101.     
  102.     return (*signature == TDB_SIGNATURE) ? TRUE : 0;
  103. }
  104.  
  105. BOOL IsAPSP(HANDLE hPSP)
  106. {
  107.     WORD segLen;
  108.     BOOL segOK=FALSE;
  109.     WORD far *signature;
  110.  
  111.     // Make sure that it's ok to read from the passed in handle/selector
  112.  
  113.     asm {
  114.             mov     ax, [hPSP]
  115.             cmp     ax, 0
  116.             je      mylabel
  117.             lsl     bx, ax
  118.             jnz     mylabel
  119.             mov     [segLen], bx
  120.             mov     [segOK], 1
  121.     }
  122.     
  123.     mylabel:
  124.     
  125.     // Make sure that the segment is long enough, and then
  126.     // look for the 'TD' signature
  127.         
  128.     if ( !segOK || (segLen < PSP_LENGTH) )
  129.         return FALSE;
  130.     
  131.     signature = MK_FP(hPSP, 0);
  132.     
  133.     return (*signature == PSP_SIGNATURE) ? TRUE : 0;
  134. }
  135.  
  136. //---------------------------------------------
  137. // Given a module handle, return back the
  138. // name of the module.
  139. //---------------------------------------------
  140.  
  141. char *GetModuleNameFromHandle(HANDLE handle)
  142. {
  143.     static char name[129];
  144.     char far *moduleTablePtr;
  145.     WORD residentNamesOffset;
  146.     BYTE cbModuleName;
  147.     
  148.     name[0] = 0;    // Null out the return string
  149.     
  150.     // create a pointer to the module table
  151.  
  152.     moduleTablePtr = GlobalLock(handle);
  153.     GlobalUnlock(handle);
  154.     if ( !moduleTablePtr )
  155.         return name;
  156.  
  157.     // Verify that we're really looking at a module table, by
  158.     // looking for the 'NE' signature.  If we are, get the
  159.     // module name out of the resident names table.
  160.         
  161.     if ( *(WORD far *)moduleTablePtr == NE_SIGNATURE )
  162.     {
  163.         // Obtain the resident names table offset, and point to it
  164.             
  165.         residentNamesOffset = *(WORD far *)(moduleTablePtr + 0x26);
  166.         moduleTablePtr += residentNamesOffset;
  167.         
  168.         // Get the length of the first entry, which is always
  169.         // the module name.
  170.             
  171.         cbModuleName = *(BYTE far *)moduleTablePtr;
  172.         moduleTablePtr++;
  173.         
  174.         // Use the far string copy to move the name to our local
  175.         // buffer.  Then null terminate the local buffer copy.
  176.             
  177.         _fstrncpy(name, moduleTablePtr, cbModuleName);
  178.         name[cbModuleName] = 0;
  179.     }
  180.     
  181.     return name;
  182. }
  183.  
  184. //---------------------------------------------
  185. // Given a task handle, return back the name
  186. // of the module that it's an instance of
  187. //---------------------------------------------
  188.  
  189. char *GetModuleNameFromTaskHandle(HANDLE hTask)
  190. {
  191.     static char buffer[10];
  192.     
  193.     buffer[0] = 0;
  194.     if ( IsATask(hTask) )
  195.     {
  196.         _fstrncpy(buffer, MK_FP(hTask, TDB_MODULE_NAME_OFFSET), 8);
  197.         buffer[8] = 0;
  198.     }
  199.     return buffer;
  200. }
  201.  
  202. void DisplayMessage(MSG far *msg)
  203. {
  204.     WORD offset;
  205.     
  206.     offset = FP_OFF(msg);
  207.     
  208.     // If Win 3.1, adjust the offset to display the true
  209.     // start of the message
  210.         
  211.     if (WinVersion == 0x030A)
  212.         offset -= 4;
  213.     
  214.     printf("%04X  %04X  %04X  %04X  %08lX  %08lX  %4d.%d\n",
  215.             offset,
  216.             msg->hwnd,
  217.             msg->message,
  218.             msg->wParam,
  219.             msg->lParam,
  220.             msg->time,
  221.             msg->pt.x,
  222.             msg->pt.y
  223.     );
  224. }
  225.  
  226.  
  227. void DoTaskQueue(HANDLE hQueue)
  228. {
  229.     MESSAGEQUEUE far *mq;
  230.     WORD    sel;
  231.     WORD    msgCount;
  232.     MSG     far *firstMsg;
  233.     char    far *currMsgOffset;
  234.     BOOL    win31=FALSE;
  235.     WORD    i;
  236.     
  237.     if ( WinVersion > 0x030A )
  238.     {
  239.         printf("Cannot dump task queue.  Windows version is too new\n");
  240.         return;
  241.     }
  242.     
  243.     win31 = ( WinVersion == 0x030A) ? TRUE : FALSE;
  244.         
  245.     sel = hQueue;
  246.     mq = MK_FP(sel, 0);
  247.  
  248.     if ( win31 )
  249.         firstMsg = MK_FP(sel, 0x6E);
  250.     else
  251.         firstMsg = MK_FP(sel, 0x5A);
  252.     
  253.     msgCount = (mq->endOfQueue - FP_OFF(firstMsg)) / mq->msgSize;
  254.     
  255.     printf("%-*s%04X messages\n", WIDTH, "Queue Size", msgCount);   
  256.     printf("%-*s%04X\n", WIDTH, "Message Size", mq->msgSize);
  257.     printf("%-*s%04X\n", WIDTH, "Waiting messages", mq->msgCount);
  258.     printf("%-*s%04X\n", WIDTH, "Next Message offset", mq->nextMessageOffset);
  259.     printf("%-*s%04X\n", WIDTH, "Next Free message offset", mq->nextFreeMessageOffset);
  260.  
  261.     printf("\n");
  262.     printf("Messages:\n");
  263.  
  264.     printf("OFFS  HWND   MSG  WPAR    LPARAM      TIME  POINT\n");
  265.     
  266.     currMsgOffset = (char far *)firstMsg;
  267.  
  268.     if ( win31 )
  269.         currMsgOffset += 4;
  270.     
  271.     for ( i=0; i < msgCount; i++ )
  272.     {
  273.         DisplayMessage( (MSG far *)currMsgOffset );     
  274.         currMsgOffset += mq->msgSize;
  275.     }
  276.         
  277.     printf("\n");
  278. }
  279.  
  280. void DisplayTask(HANDLE hTask)
  281. {
  282.     TASK_DB far *tdb;
  283.     WORD sel;
  284.     
  285.     sel = hTask;
  286.     tdb = MK_FP(sel, 0);
  287.     
  288.     printf("%-*s%04X\n", WIDTH, "hTask", tdb->hTask);   
  289.     printf("%-*s%04X\n", WIDTH, "hInstance", tdb->hInstance);
  290.     printf("%-*s%04X (%s)\n", WIDTH, "hModule",
  291.         tdb->hModule, GetModuleNameFromHandle(tdb->hModule));
  292.  
  293.     printf("%-*s%04X <- Double-click here for PSP display\n",
  294.         WIDTH, "PDB/PSP", tdb->pdb);
  295.     
  296.     printf("%-*s%04X (%s)\n", WIDTH, "hParent",
  297.         tdb->hParent,  GetModuleNameFromTaskHandle(tdb->hParent));
  298.     
  299.     printf("%-*s%c:%Fs\n", WIDTH, "Current directory",
  300.             (tdb->currDrive-0x80) + 'A', tdb->currDir );
  301.     printf("%-*s%Fp\n",  WIDTH, "SS:SP", tdb->sssp);
  302.     printf("%-*s%04X\n", WIDTH, "Waiting system events", tdb->nevents);
  303.     printf("%-*s%04X\n", WIDTH, "Priority", tdb->nevents);
  304.  
  305.     printf("%-*s%u.%02u\n", WIDTH, "Expected Win version",
  306.         HIBYTE(tdb->expWinVer), LOBYTE(tdb->expWinVer) );
  307.     
  308.     printf("%-*s%04X\n", WIDTH, "SetSigHandler flag", tdb->SetSigHandlerFlag);
  309.     printf("%-*s%Fp\n",  WIDTH, "SetSigHandler Proc", tdb->SetSigHandlerProc);
  310.     printf("%-*s%Fp\n",  WIDTH, "Signal Proc", tdb->signalProc);
  311.  
  312.     printf("%-*s%Fp\n",  WIDTH, "Int 00 handler", tdb->int0Proc);
  313.     printf("%-*s%Fp\n",  WIDTH, "Int 02 handler", tdb->int2Proc);
  314.     printf("%-*s%Fp\n",  WIDTH, "Int 04 handler", tdb->int4Proc);
  315.     printf("%-*s%Fp\n",  WIDTH, "Int 06 handler", tdb->int6Proc);
  316.     printf("%-*s%Fp\n",  WIDTH, "Int 07 handler", tdb->int7Proc);
  317.     printf("%-*s%Fp\n",  WIDTH, "Int 3E handler", tdb->int3EProc);
  318.     printf("%-*s%Fp\n",  WIDTH, "Int 75 handler", tdb->int75Proc);
  319.  
  320.     printf("\n");
  321.     printf("Message Queue:\n");
  322.         
  323.     if ( tdb->hQueue )
  324.     {
  325.         printf("%-*s%04X\n", WIDTH, "hQueue", tdb->hQueue);
  326.         DoTaskQueue(tdb->hQueue);
  327.     }
  328.     else
  329.         printf("No message queue for task\n");
  330. }
  331.  
  332. void DisplayPSP(HANDLE hPSP)
  333. {
  334.     PSP far *psp;
  335.     WORD sel;
  336.     WORD i;
  337.     char c;
  338.     
  339.     sel = hPSP;
  340.     psp = MK_FP(sel, 0);
  341.     
  342.     printf("%-*s%04X\n", WIDTH, "File handle count", psp->handleCount);
  343.     
  344.     printf("File handles:\n");
  345.     for ( i = 0; (i < psp->handleCount) && (i < 20 ); i++)
  346.         printf(" %02X", psp->handles[i]);
  347.     printf("\n");
  348.     
  349.     printf("%-*s", WIDTH, "Command line", psp->handleCount);
  350.     if ( psp->argLen == 0 )
  351.         printf("<none>");
  352.     else
  353.         for ( i = 0; i < psp->argLen; i++)
  354.         {
  355.             c = psp->args[i];
  356.             c = isascii(c) ? (isprint(c) ? c : '.') : '.';
  357.             printf("%c", c);
  358.         }
  359.     printf("\n");   
  360. }
  361.  
  362. void TaskWalk(void)
  363. {
  364.     HANDLE thisTask;
  365.     WORD far *signature;
  366.  
  367.     // Undocumented way to get the first task in the system.
  368.         
  369.     GetCurrentTask();
  370.     asm     mov     [thisTask], DX
  371.     
  372.     if ( !thisTask )
  373.         return;
  374.  
  375.     // Turn off repaints while we output the info
  376.         
  377.     winio_setbusy();
  378.     winio_setpaint(winio_current(), FALSE);
  379.  
  380.     printf("Double-Click on any line for detailed view\n\n");
  381.     printf("TASK      HNDL\n");
  382.  
  383.     while ( thisTask )
  384.     {
  385.         // Verify that we're looking at a valid TDB
  386.             
  387.         signature = MK_FP(thisTask, 0xFA);
  388.         if ( *signature != TDB_SIGNATURE )
  389.         {
  390.             printf("Error in following task chain\n");
  391.             break;
  392.         }
  393.                         
  394.         printf("%-8s  %04X\n",
  395.             GetModuleNameFromTaskHandle(thisTask), thisTask);
  396.  
  397.         // Extract the next task in the linked list
  398.         
  399.         thisTask = *(HANDLE far *)MK_FP(thisTask, 0);
  400.     }
  401.  
  402.     // Turn the repaints back on
  403.     winio_setpaint(winio_current(), TRUE);
  404.     winio_resetbusy();
  405.     winio_home(winio_current());
  406. }
  407.  
  408. void DumpPSP(HWND hwnd, LPSTR line, int i)
  409. {
  410.     char moduleName[80];
  411.     char buffer[80];
  412.     HANDLE hPSP;
  413.     int returnCode;
  414.     HWND newWindow;
  415.     
  416.     // Make a local copy of the line, and then extract the 
  417.     // relevant info from the line.
  418.         
  419.     _fstrcpy(buffer, line);    
  420.     returnCode = sscanf(buffer, "PDB/PSP %x", &hPSP);
  421.     
  422.     // Make sure that a valid line was pressed, and that the
  423.     // task still exists.  Get out if either is not true
  424.         
  425.     if ( returnCode != 1 )
  426.     {
  427.         MessageBox(NULL, "Not a valid line", "Error",
  428.                     MB_OK | MB_ICONEXCLAMATION);
  429.         return;
  430.     }
  431.     
  432.     if ( !IsAPSP(hPSP) )
  433.     {
  434.         MessageBox(NULL, "Task/PSP no longer exists", "Error",
  435.                     MB_OK | MB_ICONEXCLAMATION);
  436.         return;
  437.     }
  438.  
  439.     // Create the window for the PSP display.  Give it
  440.     // an appropriate title.
  441.  
  442.     GetWindowText(hwnd, buffer, sizeof(buffer));
  443.     sscanf(buffer, "WinTask: %s", moduleName);
  444.     sprintf(buffer, "WinTask PSP: %s", moduleName);     
  445.     newWindow = winio_window(buffer, 0x0400, WW_HASMENU);
  446.     winio_setcurrent(newWindow);
  447.  
  448.     // Turn off repaints
  449.         
  450.     winio_setbusy();
  451.     winio_setpaint(winio_current(), FALSE);
  452.     
  453.     DisplayPSP(hPSP);
  454.  
  455.     // Turn repaints back on, and position at the top of the info
  456.         
  457.     winio_setpaint(winio_current(), TRUE);
  458.     winio_resetbusy();
  459.     winio_home(newWindow);      
  460. }
  461.  
  462. void DumpTask(HWND hwnd, LPSTR line, int i)
  463. {
  464.     char moduleName[80];
  465.     char buffer[80];
  466.     HANDLE hTask;
  467.     int returnCode;
  468.     HWND newWindow;
  469.     
  470.     // Make a local copy of the line, and then extract the 
  471.     // relevant info from the line.
  472.         
  473.     _fstrcpy(buffer, line);    
  474.     returnCode = sscanf(buffer, "%s %x", moduleName, &hTask);
  475.     
  476.     // Make sure that a valid line was pressed, and that the
  477.     // task still exists.  Get out if either is not true
  478.         
  479.     if ( returnCode != 2 )
  480.     {
  481.         MessageBox(NULL, "Not a valid line", "Error",
  482.                     MB_OK | MB_ICONEXCLAMATION);
  483.         return;
  484.     }
  485.     
  486.     if ( !IsATask(hTask) )
  487.     {
  488.         MessageBox(NULL, "Task no longer exists", "Error",
  489.                     MB_OK | MB_ICONEXCLAMATION);
  490.         return;
  491.     }
  492.  
  493.  
  494.     // Create the window for the new task display.  Give it
  495.     // an appropriate title.
  496.         
  497.     sprintf(buffer, "WinTask: %s", moduleName);     
  498.     newWindow = winio_window(buffer, 0x1000, WW_HASMENU);
  499.     winio_setcurrent(newWindow);
  500.  
  501.     // Turn off repaints
  502.         
  503.     winio_setbusy();
  504.     winio_setpaint(winio_current(), FALSE);
  505.     
  506.     DisplayTask(hTask);
  507.  
  508.     // Turn repaints back on, and position at the top of the info
  509.         
  510.     winio_setpaint(winio_current(), TRUE);
  511.     winio_resetbusy();
  512.     winio_home(newWindow);  
  513.     
  514.     winio_setlinefn(winio_current(), DumpPSP);  
  515. }
  516.  
  517. int main(int argc, char *argv[])
  518. {
  519.     winio_about("WINTASK"
  520.         "\nWindows task list browser"
  521.         "\n\nFrom Chapter 5 of"
  522.         "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
  523.         "\nby Andrew Schulman, David Maxey and Matt Pietrek"
  524.         );
  525.     
  526.     // GetVersion returns in AX register.  Flip the byte registers to
  527.     // produce a sensible version, with the major revision in ah, and
  528.     // the minor revision in AL.  When done, store away in WinVersion.
  529.     GetVersion();
  530.     asm     xchg    ah, al
  531.     asm     mov     [WinVersion], ax
  532.  
  533.     // Create the list of tasks for the user
  534.     // to double click on.
  535.         
  536.     TaskWalk();
  537.  
  538.     // Install a double click handler
  539.         
  540.     winio_setlinefn(winio_current(), DumpTask);
  541.         
  542.     return 0;
  543. }
  544.