1 /*
2  *  ReactOS ps - process list console viewer
3  *
4  *  ps.c
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 /*
21     Thanks to Filip Navara patch for fixing the Xp crash problem.
22 */
23 
24 #define NTOS_MODE_USER
25 #define WIN32_NO_STATUS
26 #include <windows.h>
27 #include <ndk/ntndk.h>
28 
29 typedef struct _SYSTEM_THREADS
30  {
31     LARGE_INTEGER KernelTime;
32     LARGE_INTEGER UserTime;
33     LARGE_INTEGER CreateTime;
34     ULONG WaitTime;
35     PVOID StartAddress;
36     CLIENT_ID ClientId;
37     KPRIORITY Priority;
38     LONG BasePriority;
39     ULONG ContextSwitches;
40     ULONG ThreadState;
41     ULONG WaitReason;
42  } SYSTEM_THREADS, *PSYSTEM_THREADS;
43 
44  typedef struct _SYSTEM_PROCESSES
45  {
46     ULONG NextEntryOffset;
47     ULONG NumberOfThreads;
48     LARGE_INTEGER SpareLi1;
49     LARGE_INTEGER SpareLi2;
50     LARGE_INTEGER SpareLi3;
51     LARGE_INTEGER CreateTime;
52     LARGE_INTEGER UserTime;
53     LARGE_INTEGER KernelTime;
54     UNICODE_STRING ImageName;
55     KPRIORITY BasePriority;
56     HANDLE UniqueProcessId;
57     HANDLE InheritedFromUniqueProcessId;
58     ULONG HandleCount;
59     ULONG SessionId;
60     ULONG PageDirectoryFrame;
61 
62     /*
63      * This part corresponds to VM_COUNTERS_EX.
64      * NOTE: *NOT* THE SAME AS VM_COUNTERS!
65      */
66     ULONG PeakVirtualSize;
67     ULONG VirtualSize;
68     ULONG PageFaultCount;
69     ULONG PeakWorkingSetSize;
70     ULONG WorkingSetSize;
71     ULONG QuotaPeakPagedPoolUsage;
72     ULONG QuotaPagedPoolUsage;
73     ULONG QuotaPeakNonPagedPoolUsage;
74     ULONG QuotaNonPagedPoolUsage;
75     ULONG PagefileUsage;
76     ULONG PeakPagefileUsage;
77     ULONG PrivateUsage;
78 
79     /* This part corresponds to IO_COUNTERS */
80     LARGE_INTEGER ReadOperationCount;
81     LARGE_INTEGER WriteOperationCount;
82     LARGE_INTEGER OtherOperationCount;
83     LARGE_INTEGER ReadTransferCount;
84     LARGE_INTEGER WriteTransferCount;
85     LARGE_INTEGER OtherTransferCount;
86 
87          SYSTEM_THREADS       Threads [1];
88  } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;
89 
90 
91 //                     x00000000 00000000 000:00:00  000:00:00 ()
92 static char title[]  = "P     PID     PPID     KTime      UTime   NAME\n";
93 static char title1[] = "t              TID     KTime      UTime   State      WaitResson\n";
94 static char title2[] = "w     PID     Hwnd  WndStile        TID   WndName\n";
95 
96 
97 struct status {
98     DWORD state;
99     const char  desc[10];
100 }   thread_stat[8 + 1] = {
101     {0,	"Init      "},
102     {1,	"Ready     "},
103     {2,	"Running   "},
104     {3,	"Standby   "},
105     {4,	"Terminated"},
106     {5,	"Wait      "},
107     {6,	"Transition"},
108     {7, "Unknown   "},
109     {-1,"    ?     "}
110 };
111 
112 struct waitres {
113     DWORD state;
114     char  desc[17];
115 }   waitreason[35 + 1] = {
116    {0, "Executive        "},
117    {1, "FreePage         "},
118    {2, "PageIn           "},
119    {3, "PoolAllocation   "},
120    {4, "DelayExecution   "},
121    {5, "Suspended        "},
122    {6, "UserRequest      "},
123    {7, "WrExecutive      "},
124    {8, "WrFreePage       "},
125    {9, "WrPageIn         "},
126    {10,"WrPoolAllocation "},
127    {11,"WrDelayExecution "},
128    {12,"WrSuspended      "},
129    {13,"WrUserRequest    "},
130    {14,"WrEventPair      "},
131    {15,"WrQueue          "},
132    {16,"WrLpcReceive     "},
133    {17,"WrLpcReply       "},
134    {18,"WrVirtualMemory  "},
135    {19,"WrPageOut        "},
136    {20,"WrRendezvous     "},
137    {21,"Spare2           "},
138    {22,"WrGuardedMutex   "},
139    {23,"Spare4           "},
140    {24,"Spare5           "},
141    {25,"Spare6           "},
142    {26,"WrKernel         "},
143    {27,"WrResource       "},
144    {28,"WrPushLock       "},
145    {29,"WrMutex          "},
146    {30,"WrQuantumEnd     "},
147    {31,"WrDispatchInt    "},
148    {32,"WrPreempted      "},
149    {33,"WrYieldExecution "},
150    {34,"MaximumWaitReason"},
151    {-1,"       ?         "}
152 };
153 
154 static BOOL CALLBACK
EnumThreadProc(HWND hwnd,LPARAM lp)155 EnumThreadProc(HWND hwnd, LPARAM lp)
156 {
157 	DWORD r, pid, tid;
158 	LONG style;
159 	char buf[256];
160     HANDLE Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
161 
162 	GetWindowText(hwnd, (LPTSTR)lp, 30);
163 
164 	if(hwnd != 0)
165 	{
166 	style = GetWindowLong(hwnd, GWL_STYLE);
167 
168 	tid = GetWindowThreadProcessId(hwnd, &pid);
169 
170 	wsprintf (buf,"w%8d %8x  %08x   %8d   %s\n",pid, hwnd , style, tid, lp );
171        	WriteFile(Stdout, buf, lstrlen(buf), &r, NULL);
172        	}
173 	return (TRUE);
174 }
175 
main()176 int main()
177 {
178     DWORD r;
179     ANSI_STRING astring;
180     HANDLE Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
181     PSYSTEM_PROCESSES SystemProcesses = NULL;
182     PSYSTEM_PROCESSES CurrentProcess;
183     ULONG BufferSize, ReturnSize;
184     NTSTATUS Status;
185     char buf[256];
186     char buf1[256];
187 
188     WriteFile(Stdout, title, lstrlen(title), &r, NULL);
189     WriteFile(Stdout, title1, lstrlen(title1), &r, NULL);
190     WriteFile(Stdout, title2, lstrlen(title2), &r, NULL);
191 
192     /* Get process information. */
193     BufferSize = 0;
194     do
195     {
196         BufferSize += 0x10000;
197         SystemProcesses = HeapAlloc(GetProcessHeap(), 0, BufferSize);
198         Status = NtQuerySystemInformation(SystemProcessInformation,
199                                           SystemProcesses, BufferSize,
200                                           &ReturnSize);
201         if (Status == STATUS_INFO_LENGTH_MISMATCH)
202             HeapFree(GetProcessHeap(), 0, SystemProcesses);
203     } while (Status == STATUS_INFO_LENGTH_MISMATCH);
204 
205     /* If querying system information failed, bail out. */
206     if (!NT_SUCCESS(Status))
207         return 1;
208 
209     /* For every process print the information. */
210     CurrentProcess = SystemProcesses;
211     while (CurrentProcess->NextEntryOffset != 0)
212     {
213         int hour, hour1, thour, thour1;
214         unsigned char minute, minute1, tmin, tmin1;
215         unsigned char  seconds, seconds1, tsec, tsec1;
216 
217 	unsigned int ti;
218 	LARGE_INTEGER ptime;
219 
220 	ptime.QuadPart = CurrentProcess->KernelTime.QuadPart;
221 	hour    = (ptime.QuadPart / (10000000LL * 3600LL));
222 	minute  = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL;
223 	seconds = (ptime.QuadPart / 10000000LL) % 60LL;
224 
225 	ptime.QuadPart = CurrentProcess->UserTime.QuadPart;
226 	hour1    = (ptime.QuadPart / (10000000LL * 3600LL));
227 	minute1  = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL;
228 	seconds1 = (ptime.QuadPart / 10000000LL) % 60LL;
229 
230 	RtlUnicodeStringToAnsiString(&astring, &CurrentProcess->ImageName, TRUE);
231 
232         wsprintf(buf,"P%8d %8d %3d:%02d:%02d  %3d:%02d:%02d   ProcName: %s\n",
233                  CurrentProcess->UniqueProcessId, CurrentProcess->InheritedFromUniqueProcessId,
234                  hour, minute, seconds, hour1, minute1, seconds1,
235                  astring.Buffer);
236         WriteFile(stdout, buf, lstrlen(buf), &r, NULL);
237 
238         RtlFreeAnsiString(&astring);
239 
240 	for (ti = 0; ti < CurrentProcess->NumberOfThreads; ti++)
241 	   {
242 		struct status *statt;
243 		struct waitres *waitt;
244 		char szWindowName[30] = {" "};
245 
246 		ptime = CurrentProcess->Threads[ti].KernelTime;
247 		thour = (ptime.QuadPart / (10000000LL * 3600LL));
248 		tmin  = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL;
249 		tsec  = (ptime.QuadPart / 10000000LL) % 60LL;
250 
251 		ptime = CurrentProcess->Threads[ti].UserTime;
252 		thour1 = (ptime.QuadPart / (10000000LL * 3600LL));
253 		tmin1  = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL;
254 		tsec1  = (ptime.QuadPart / 10000000LL) % 60LL;
255 
256 		statt = thread_stat;
257                 while (statt->state != CurrentProcess->Threads[ti].ThreadState  && statt->state >= 0)
258                 	statt++;
259 
260 		waitt = waitreason;
261                 while (waitt->state != CurrentProcess->Threads[ti].WaitReason  && waitt->state >= 0)
262                         waitt++;
263 
264 		wsprintf (buf1,
265 		          "t%         %8d %3d:%02d:%02d  %3d:%02d:%02d   %s %s\n",
266 		          CurrentProcess->Threads[ti].ClientId.UniqueThread,
267 		          thour, tmin, tsec, thour1, tmin1, tsec1,
268 		          statt->desc , waitt->desc);
269         	WriteFile(stdout, buf1, lstrlen(buf1), &r, NULL);
270 
271 		EnumThreadWindows(PtrToUlong(CurrentProcess->Threads[ti].ClientId.UniqueThread),
272 		                  (WNDENUMPROC) EnumThreadProc,
273 		                  (LPARAM)(LPTSTR) szWindowName );
274 	   }
275 
276 	   CurrentProcess = (PSYSTEM_PROCESSES)((ULONG_PTR)CurrentProcess +
277 	                     (ULONG_PTR)CurrentProcess->NextEntryOffset);
278 	}
279   	return (0);
280 }
281