home *** CD-ROM | disk | FTP | other *** search
- /*
- WINTASK.C -- Windows task list browser
-
- From Chapter 5 of "Undocumented Windows" (Addison-Wesley 1992)
- by Andrew Schulman, Dave Maxey and Matt Pietrek
-
- Build using: WINIOBC WINTASK (for Borland C++ v3.00)
- WINIOMS WINTASK (for Microsoft C/SDK)
- */
-
- #include <windows.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <dos.h>
- #include "winio.h"
-
- #include "taskdb.h"
- #include "taskq.h"
- #include "psp.h"
-
- #ifndef __BORLANDC__
- #define asm _asm
- #define MK_FP(a,b) ((void far *)(((unsigned long)(a) << 16) | (b)))
- #endif
-
- #define NE_SIGNATURE 0x454E
- #define TDB_SIGNATURE 0x4454
- #define TDB_SIGNATURE_OFFSET 0x00FA
- #define TDB_MODULE_NAME_OFFSET 0x00F2
- #define PSP_LENGTH 0x0100
- #define PSP_SIGNATURE 0x20CD
-
- #define WIDTH 25
-
- WORD WinVersion;
-
- //---------------------------------------------
- // Converts a global handle to a selector value.
- // The proper way would be to use GlobalLock, but
- // GlobalLock will RIP on certain selectors.
- // TOOLHELP does it like this, so...
- //---------------------------------------------
-
- WORD HandleToSel(HANDLE h)
- {
- // In 3.1, handles = (selectors-1)
- // Valid selectors end in a 7 or a F
- // Thus, we can simply make sure the
- // lowest bit is turned on.
- //
- // In 3.0, handles = (selectors+1)
- // Valid selectors end in a 5 or a D
- // Decrement the handle if it's an
- // even value.
-
- if ( WinVersion == 0x030A )
- h |= 0x0001;
-
- else if ( WinVersion < 0x030A )
- if ( (h & 0x0002) == 0x0002 )
- h--;
-
- return h;
- }
-
-
- //---------------------------------------------
- // Returns a BOOL indicating whether the passed
- // in handle is an HTASK. In Windows 3.1, you
- // could call IsTask()
- //---------------------------------------------
-
- BOOL IsATask(HANDLE hTask)
- {
- WORD segLen;
- BOOL segOK=FALSE;
- WORD far *signature;
-
- // Make sure that it's ok to read from the passed in handle/selector
-
- asm {
- mov ax, [hTask]
- cmp ax, 0
- je mylabel
- lsl bx, ax
- jnz mylabel
- mov [segLen], bx
- mov [segOK], 1
- }
-
- mylabel:
-
- // Make sure that the segment is long enough, and then
- // look for the 'TD' signature
-
- if ( !segOK || (segLen < TDB_SIGNATURE_OFFSET+2) )
- return FALSE;
-
- signature = MK_FP(hTask, TDB_SIGNATURE_OFFSET);
-
- return (*signature == TDB_SIGNATURE) ? TRUE : 0;
- }
-
- BOOL IsAPSP(HANDLE hPSP)
- {
- WORD segLen;
- BOOL segOK=FALSE;
- WORD far *signature;
-
- // Make sure that it's ok to read from the passed in handle/selector
-
- asm {
- mov ax, [hPSP]
- cmp ax, 0
- je mylabel
- lsl bx, ax
- jnz mylabel
- mov [segLen], bx
- mov [segOK], 1
- }
-
- mylabel:
-
- // Make sure that the segment is long enough, and then
- // look for the 'TD' signature
-
- if ( !segOK || (segLen < PSP_LENGTH) )
- return FALSE;
-
- signature = MK_FP(hPSP, 0);
-
- return (*signature == PSP_SIGNATURE) ? TRUE : 0;
- }
-
- //---------------------------------------------
- // Given a module handle, return back the
- // name of the module.
- //---------------------------------------------
-
- char *GetModuleNameFromHandle(HANDLE handle)
- {
- static char name[129];
- char far *moduleTablePtr;
- WORD residentNamesOffset;
- BYTE cbModuleName;
-
- name[0] = 0; // Null out the return string
-
- // create a pointer to the module table
-
- moduleTablePtr = GlobalLock(handle);
- GlobalUnlock(handle);
- if ( !moduleTablePtr )
- return name;
-
- // Verify that we're really looking at a module table, by
- // looking for the 'NE' signature. If we are, get the
- // module name out of the resident names table.
-
- if ( *(WORD far *)moduleTablePtr == NE_SIGNATURE )
- {
- // Obtain the resident names table offset, and point to it
-
- residentNamesOffset = *(WORD far *)(moduleTablePtr + 0x26);
- moduleTablePtr += residentNamesOffset;
-
- // Get the length of the first entry, which is always
- // the module name.
-
- cbModuleName = *(BYTE far *)moduleTablePtr;
- moduleTablePtr++;
-
- // Use the far string copy to move the name to our local
- // buffer. Then null terminate the local buffer copy.
-
- _fstrncpy(name, moduleTablePtr, cbModuleName);
- name[cbModuleName] = 0;
- }
-
- return name;
- }
-
- //---------------------------------------------
- // Given a task handle, return back the name
- // of the module that it's an instance of
- //---------------------------------------------
-
- char *GetModuleNameFromTaskHandle(HANDLE hTask)
- {
- static char buffer[10];
-
- buffer[0] = 0;
- if ( IsATask(hTask) )
- {
- _fstrncpy(buffer, MK_FP(hTask, TDB_MODULE_NAME_OFFSET), 8);
- buffer[8] = 0;
- }
- return buffer;
- }
-
- void DisplayMessage(MSG far *msg)
- {
- WORD offset;
-
- offset = FP_OFF(msg);
-
- // If Win 3.1, adjust the offset to display the true
- // start of the message
-
- if (WinVersion == 0x030A)
- offset -= 4;
-
- printf("%04X %04X %04X %04X %08lX %08lX %4d.%d\n",
- offset,
- msg->hwnd,
- msg->message,
- msg->wParam,
- msg->lParam,
- msg->time,
- msg->pt.x,
- msg->pt.y
- );
- }
-
-
- void DoTaskQueue(HANDLE hQueue)
- {
- MESSAGEQUEUE far *mq;
- WORD sel;
- WORD msgCount;
- MSG far *firstMsg;
- char far *currMsgOffset;
- BOOL win31=FALSE;
- WORD i;
-
- if ( WinVersion > 0x030A )
- {
- printf("Cannot dump task queue. Windows version is too new\n");
- return;
- }
-
- win31 = ( WinVersion == 0x030A) ? TRUE : FALSE;
-
- sel = hQueue;
- mq = MK_FP(sel, 0);
-
- if ( win31 )
- firstMsg = MK_FP(sel, 0x6E);
- else
- firstMsg = MK_FP(sel, 0x5A);
-
- msgCount = (mq->endOfQueue - FP_OFF(firstMsg)) / mq->msgSize;
-
- printf("%-*s%04X messages\n", WIDTH, "Queue Size", msgCount);
- printf("%-*s%04X\n", WIDTH, "Message Size", mq->msgSize);
- printf("%-*s%04X\n", WIDTH, "Waiting messages", mq->msgCount);
- printf("%-*s%04X\n", WIDTH, "Next Message offset", mq->nextMessageOffset);
- printf("%-*s%04X\n", WIDTH, "Next Free message offset", mq->nextFreeMessageOffset);
-
- printf("\n");
- printf("Messages:\n");
-
- printf("OFFS HWND MSG WPAR LPARAM TIME POINT\n");
-
- currMsgOffset = (char far *)firstMsg;
-
- if ( win31 )
- currMsgOffset += 4;
-
- for ( i=0; i < msgCount; i++ )
- {
- DisplayMessage( (MSG far *)currMsgOffset );
- currMsgOffset += mq->msgSize;
- }
-
- printf("\n");
- }
-
- void DisplayTask(HANDLE hTask)
- {
- TASK_DB far *tdb;
- WORD sel;
-
- sel = hTask;
- tdb = MK_FP(sel, 0);
-
- printf("%-*s%04X\n", WIDTH, "hTask", tdb->hTask);
- printf("%-*s%04X\n", WIDTH, "hInstance", tdb->hInstance);
- printf("%-*s%04X (%s)\n", WIDTH, "hModule",
- tdb->hModule, GetModuleNameFromHandle(tdb->hModule));
-
- printf("%-*s%04X <- Double-click here for PSP display\n",
- WIDTH, "PDB/PSP", tdb->pdb);
-
- printf("%-*s%04X (%s)\n", WIDTH, "hParent",
- tdb->hParent, GetModuleNameFromTaskHandle(tdb->hParent));
-
- printf("%-*s%c:%Fs\n", WIDTH, "Current directory",
- (tdb->currDrive-0x80) + 'A', tdb->currDir );
- printf("%-*s%Fp\n", WIDTH, "SS:SP", tdb->sssp);
- printf("%-*s%04X\n", WIDTH, "Waiting system events", tdb->nevents);
- printf("%-*s%04X\n", WIDTH, "Priority", tdb->nevents);
-
- printf("%-*s%u.%02u\n", WIDTH, "Expected Win version",
- HIBYTE(tdb->expWinVer), LOBYTE(tdb->expWinVer) );
-
- printf("%-*s%04X\n", WIDTH, "SetSigHandler flag", tdb->SetSigHandlerFlag);
- printf("%-*s%Fp\n", WIDTH, "SetSigHandler Proc", tdb->SetSigHandlerProc);
- printf("%-*s%Fp\n", WIDTH, "Signal Proc", tdb->signalProc);
-
- printf("%-*s%Fp\n", WIDTH, "Int 00 handler", tdb->int0Proc);
- printf("%-*s%Fp\n", WIDTH, "Int 02 handler", tdb->int2Proc);
- printf("%-*s%Fp\n", WIDTH, "Int 04 handler", tdb->int4Proc);
- printf("%-*s%Fp\n", WIDTH, "Int 06 handler", tdb->int6Proc);
- printf("%-*s%Fp\n", WIDTH, "Int 07 handler", tdb->int7Proc);
- printf("%-*s%Fp\n", WIDTH, "Int 3E handler", tdb->int3EProc);
- printf("%-*s%Fp\n", WIDTH, "Int 75 handler", tdb->int75Proc);
-
- printf("\n");
- printf("Message Queue:\n");
-
- if ( tdb->hQueue )
- {
- printf("%-*s%04X\n", WIDTH, "hQueue", tdb->hQueue);
- DoTaskQueue(tdb->hQueue);
- }
- else
- printf("No message queue for task\n");
- }
-
- void DisplayPSP(HANDLE hPSP)
- {
- PSP far *psp;
- WORD sel;
- WORD i;
- char c;
-
- sel = hPSP;
- psp = MK_FP(sel, 0);
-
- printf("%-*s%04X\n", WIDTH, "File handle count", psp->handleCount);
-
- printf("File handles:\n");
- for ( i = 0; (i < psp->handleCount) && (i < 20 ); i++)
- printf(" %02X", psp->handles[i]);
- printf("\n");
-
- printf("%-*s", WIDTH, "Command line", psp->handleCount);
- if ( psp->argLen == 0 )
- printf("<none>");
- else
- for ( i = 0; i < psp->argLen; i++)
- {
- c = psp->args[i];
- c = isascii(c) ? (isprint(c) ? c : '.') : '.';
- printf("%c", c);
- }
- printf("\n");
- }
-
- void TaskWalk(void)
- {
- HANDLE thisTask;
- WORD far *signature;
-
- // Undocumented way to get the first task in the system.
-
- GetCurrentTask();
- asm mov [thisTask], DX
-
- if ( !thisTask )
- return;
-
- // Turn off repaints while we output the info
-
- winio_setbusy();
- winio_setpaint(winio_current(), FALSE);
-
- printf("Double-Click on any line for detailed view\n\n");
- printf("TASK HNDL\n");
-
- while ( thisTask )
- {
- // Verify that we're looking at a valid TDB
-
- signature = MK_FP(thisTask, 0xFA);
- if ( *signature != TDB_SIGNATURE )
- {
- printf("Error in following task chain\n");
- break;
- }
-
- printf("%-8s %04X\n",
- GetModuleNameFromTaskHandle(thisTask), thisTask);
-
- // Extract the next task in the linked list
-
- thisTask = *(HANDLE far *)MK_FP(thisTask, 0);
- }
-
- // Turn the repaints back on
- winio_setpaint(winio_current(), TRUE);
- winio_resetbusy();
- winio_home(winio_current());
- }
-
- void DumpPSP(HWND hwnd, LPSTR line, int i)
- {
- char moduleName[80];
- char buffer[80];
- HANDLE hPSP;
- int returnCode;
- HWND newWindow;
-
- // Make a local copy of the line, and then extract the
- // relevant info from the line.
-
- _fstrcpy(buffer, line);
- returnCode = sscanf(buffer, "PDB/PSP %x", &hPSP);
-
- // Make sure that a valid line was pressed, and that the
- // task still exists. Get out if either is not true
-
- if ( returnCode != 1 )
- {
- MessageBox(NULL, "Not a valid line", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- if ( !IsAPSP(hPSP) )
- {
- MessageBox(NULL, "Task/PSP no longer exists", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- // Create the window for the PSP display. Give it
- // an appropriate title.
-
- GetWindowText(hwnd, buffer, sizeof(buffer));
- sscanf(buffer, "WinTask: %s", moduleName);
- sprintf(buffer, "WinTask PSP: %s", moduleName);
- newWindow = winio_window(buffer, 0x0400, WW_HASMENU);
- winio_setcurrent(newWindow);
-
- // Turn off repaints
-
- winio_setbusy();
- winio_setpaint(winio_current(), FALSE);
-
- DisplayPSP(hPSP);
-
- // Turn repaints back on, and position at the top of the info
-
- winio_setpaint(winio_current(), TRUE);
- winio_resetbusy();
- winio_home(newWindow);
- }
-
- void DumpTask(HWND hwnd, LPSTR line, int i)
- {
- char moduleName[80];
- char buffer[80];
- HANDLE hTask;
- int returnCode;
- HWND newWindow;
-
- // Make a local copy of the line, and then extract the
- // relevant info from the line.
-
- _fstrcpy(buffer, line);
- returnCode = sscanf(buffer, "%s %x", moduleName, &hTask);
-
- // Make sure that a valid line was pressed, and that the
- // task still exists. Get out if either is not true
-
- if ( returnCode != 2 )
- {
- MessageBox(NULL, "Not a valid line", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
- if ( !IsATask(hTask) )
- {
- MessageBox(NULL, "Task no longer exists", "Error",
- MB_OK | MB_ICONEXCLAMATION);
- return;
- }
-
-
- // Create the window for the new task display. Give it
- // an appropriate title.
-
- sprintf(buffer, "WinTask: %s", moduleName);
- newWindow = winio_window(buffer, 0x1000, WW_HASMENU);
- winio_setcurrent(newWindow);
-
- // Turn off repaints
-
- winio_setbusy();
- winio_setpaint(winio_current(), FALSE);
-
- DisplayTask(hTask);
-
- // Turn repaints back on, and position at the top of the info
-
- winio_setpaint(winio_current(), TRUE);
- winio_resetbusy();
- winio_home(newWindow);
-
- winio_setlinefn(winio_current(), DumpPSP);
- }
-
- int main(int argc, char *argv[])
- {
- winio_about("WINTASK"
- "\nWindows task list browser"
- "\n\nFrom Chapter 5 of"
- "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
- "\nby Andrew Schulman, David Maxey and Matt Pietrek"
- );
-
- // GetVersion returns in AX register. Flip the byte registers to
- // produce a sensible version, with the major revision in ah, and
- // the minor revision in AL. When done, store away in WinVersion.
- GetVersion();
- asm xchg ah, al
- asm mov [WinVersion], ax
-
- // Create the list of tasks for the user
- // to double click on.
-
- TaskWalk();
-
- // Install a double click handler
-
- winio_setlinefn(winio_current(), DumpTask);
-
- return 0;
- }
-