[SHELL32_APITEST] Follow-up to #6796 (25e2f5f)
[reactos.git] / base / applications / taskmgr / perfdata.c
1 /*
2 * ReactOS Task Manager
3 *
4 * perfdata.c
5 *
6 * Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
7 * Copyright (C) 2014 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "precomp.h"
25
26 #define WIN32_LEAN_AND_MEAN
27 #include <aclapi.h>
28
29 #define NTOS_MODE_USER
30 #include <ndk/psfuncs.h>
31 #include <ndk/exfuncs.h>
32
33 CRITICAL_SECTION PerfDataCriticalSection;
34 PPERFDATA pPerfDataOld = NULL; /* Older perf data (saved to establish delta values) */
35 PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */
36 ULONG ProcessCountOld = 0;
37 ULONG ProcessCount = 0;
38 double dbIdleTime;
39 double dbKernelTime;
40 double dbSystemTime;
41 LARGE_INTEGER liOldIdleTime = {{0,0}};
42 double OldKernelTime = 0;
43 LARGE_INTEGER liOldSystemTime = {{0,0}};
44 SYSTEM_PERFORMANCE_INFORMATION SystemPerfInfo;
45 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
46 SYSTEM_FILECACHE_INFORMATION SystemCacheInfo;
47 ULONG SystemNumberOfHandles;
48 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemProcessorTimeInfo = NULL;
49 PSID SystemUserSid = NULL;
50
51 PCMD_LINE_CACHE global_cache = NULL;
52
53 #define CMD_LINE_MIN(a, b) (a < b ? a - sizeof(WCHAR) : b)
54
55 typedef struct _SIDTOUSERNAME
56 {
57 LIST_ENTRY List;
58 LPWSTR pszName;
59 BYTE Data[0];
60 } SIDTOUSERNAME, *PSIDTOUSERNAME;
61
62 static LIST_ENTRY SidToUserNameHead = {&SidToUserNameHead, &SidToUserNameHead};
63
64 BOOL PerfDataInitialize(void)
65 {
66 SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
67 NTSTATUS status;
68
69 InitializeCriticalSection(&PerfDataCriticalSection);
70
71 /*
72 * Get number of processors in the system
73 */
74 status = NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), NULL);
75 if (!NT_SUCCESS(status))
76 return FALSE;
77
78 /*
79 * Create the SYSTEM Sid
80 */
81 AllocateAndInitializeSid(&NtSidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &SystemUserSid);
82 return TRUE;
83 }
84
85 void PerfDataUninitialize(void)
86 {
87 PLIST_ENTRY pCur;
88 PSIDTOUSERNAME pEntry;
89
90 if (pPerfData != NULL)
91 HeapFree(GetProcessHeap(), 0, pPerfData);
92
93 DeleteCriticalSection(&PerfDataCriticalSection);
94
95 if (SystemUserSid != NULL)
96 {
97 FreeSid(SystemUserSid);
98 SystemUserSid = NULL;
99 }
100
101 /* Free user names cache list */
102 pCur = SidToUserNameHead.Flink;
103 while (pCur != &SidToUserNameHead)
104 {
105 pEntry = CONTAINING_RECORD(pCur, SIDTOUSERNAME, List);
106 pCur = pCur->Flink;
107 HeapFree(GetProcessHeap(), 0, pEntry);
108 }
109
110 if (SystemProcessorTimeInfo) {
111 HeapFree(GetProcessHeap(), 0, SystemProcessorTimeInfo);
112 }
113 }
114
115 static void SidToUserName(PSID Sid, LPWSTR szBuffer, DWORD BufferSize)
116 {
117 static WCHAR szDomainNameUnused[255];
118 DWORD DomainNameLen = sizeof(szDomainNameUnused) / sizeof(szDomainNameUnused[0]);
119 SID_NAME_USE Use;
120
121 if (Sid != NULL)
122 LookupAccountSidW(NULL, Sid, szBuffer, &BufferSize, szDomainNameUnused, &DomainNameLen, &Use);
123 }
124
125 VOID
126 WINAPI
127 CachedGetUserFromSid(
128 PSID pSid,
129 LPWSTR pUserName,
130 PULONG pcwcUserName)
131 {
132 PLIST_ENTRY pCur;
133 PSIDTOUSERNAME pEntry;
134 ULONG cbSid, cwcUserName;
135
136 cwcUserName = *pcwcUserName;
137
138 /* Walk through the list */
139 for(pCur = SidToUserNameHead.Flink;
140 pCur != &SidToUserNameHead;
141 pCur = pCur->Flink)
142 {
143 pEntry = CONTAINING_RECORD(pCur, SIDTOUSERNAME, List);
144 if (EqualSid((PSID)&pEntry->Data, pSid))
145 {
146 wcsncpy(pUserName, pEntry->pszName, cwcUserName);
147 *pcwcUserName = wcslen(pUserName);
148 return;
149 }
150 }
151
152 /* We didn't find the SID in the list, get the name conventional */
153 SidToUserName(pSid, pUserName, cwcUserName);
154 *pcwcUserName = wcslen(pUserName);
155
156 /* Allocate a new entry */
157 cwcUserName = *pcwcUserName + 1;
158 cbSid = GetLengthSid(pSid);
159 pEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(SIDTOUSERNAME) + cbSid + cwcUserName * sizeof(WCHAR));
160
161 /* Copy the Sid and name to our entry */
162 CopySid(cbSid, (PSID)&pEntry->Data, pSid);
163 pEntry->pszName = (LPWSTR)(pEntry->Data + cbSid);
164 wcsncpy(pEntry->pszName, pUserName, cwcUserName);
165
166 /* Insert the new entry */
167 pEntry->List.Flink = &SidToUserNameHead;
168 pEntry->List.Blink = SidToUserNameHead.Blink;
169 SidToUserNameHead.Blink->Flink = &pEntry->List;
170 SidToUserNameHead.Blink = &pEntry->List;
171
172 return;
173 }
174
175 void PerfDataRefresh(void)
176 {
177 ULONG ulSize;
178 NTSTATUS status;
179 LPBYTE pBuffer;
180 ULONG BufferSize;
181 PSYSTEM_PROCESS_INFORMATION pSPI;
182 PPERFDATA pPDOld;
183 ULONG Idx, Idx2;
184 HANDLE hProcess;
185 HANDLE hProcessToken;
186 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
187 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
188 SYSTEM_FILECACHE_INFORMATION SysCacheInfo;
189 SYSTEM_HANDLE_INFORMATION SysHandleInfoData;
190 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo;
191 double CurrentKernelTime;
192 PSECURITY_DESCRIPTOR ProcessSD;
193 PSID ProcessUser;
194 ULONG Buffer[64]; /* must be 4 bytes aligned! */
195 ULONG cwcUserName;
196
197 /* Get new system time */
198 status = NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), NULL);
199 if (!NT_SUCCESS(status))
200 return;
201
202 /* Get new CPU's idle time */
203 status = NtQuerySystemInformation(SystemPerformanceInformation, &SysPerfInfo, sizeof(SysPerfInfo), NULL);
204 if (!NT_SUCCESS(status))
205 return;
206
207 /* Get system cache information */
208 status = NtQuerySystemInformation(SystemFileCacheInformation, &SysCacheInfo, sizeof(SysCacheInfo), NULL);
209 if (!NT_SUCCESS(status))
210 return;
211
212 /* Get processor time information */
213 SysProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)HeapAlloc(GetProcessHeap(), 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors);
214 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors, &ulSize);
215
216 if (!NT_SUCCESS(status))
217 {
218 if (SysProcessorTimeInfo != NULL)
219 HeapFree(GetProcessHeap(), 0, SysProcessorTimeInfo);
220 return;
221 }
222
223 /* Get handle information
224 * Number of handles is enough, no need for data array.
225 */
226 status = NtQuerySystemInformation(SystemHandleInformation, &SysHandleInfoData, sizeof(SysHandleInfoData), NULL);
227 /* On unexpected error, reuse previous value.
228 * STATUS_SUCCESS (0-1 handle) should never happen.
229 */
230 if (status != STATUS_INFO_LENGTH_MISMATCH)
231 SysHandleInfoData.NumberOfHandles = SystemNumberOfHandles;
232
233 /* Get process information
234 * We don't know how much data there is so just keep
235 * increasing the buffer size until the call succeeds
236 */
237 BufferSize = 0;
238 do
239 {
240 BufferSize += 0x10000;
241 pBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, BufferSize);
242
243 status = NtQuerySystemInformation(SystemProcessInformation, pBuffer, BufferSize, &ulSize);
244
245 if (status == STATUS_INFO_LENGTH_MISMATCH) {
246 HeapFree(GetProcessHeap(), 0, pBuffer);
247 }
248
249 } while (status == STATUS_INFO_LENGTH_MISMATCH);
250
251 EnterCriticalSection(&PerfDataCriticalSection);
252
253 /*
254 * Save system performance info
255 */
256 memcpy(&SystemPerfInfo, &SysPerfInfo, sizeof(SYSTEM_PERFORMANCE_INFORMATION));
257
258 /*
259 * Save system cache info
260 */
261 memcpy(&SystemCacheInfo, &SysCacheInfo, sizeof(SYSTEM_FILECACHE_INFORMATION));
262
263 /*
264 * Save system processor time info
265 */
266 if (SystemProcessorTimeInfo) {
267 HeapFree(GetProcessHeap(), 0, SystemProcessorTimeInfo);
268 }
269 SystemProcessorTimeInfo = SysProcessorTimeInfo;
270
271 /*
272 * Save system handle info
273 */
274 SystemNumberOfHandles = SysHandleInfoData.NumberOfHandles;
275
276 for (CurrentKernelTime=0, Idx=0; Idx<(ULONG)SystemBasicInfo.NumberOfProcessors; Idx++) {
277 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].KernelTime);
278 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].DpcTime);
279 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].InterruptTime);
280 }
281
282 /* If it's a first call - skip idle time calcs */
283 if (liOldIdleTime.QuadPart != 0) {
284 /* CurrentValue = NewValue - OldValue */
285 dbIdleTime = Li2Double(SysPerfInfo.IdleProcessTime) - Li2Double(liOldIdleTime);
286 dbKernelTime = CurrentKernelTime - OldKernelTime;
287 dbSystemTime = Li2Double(SysTimeInfo.CurrentTime) - Li2Double(liOldSystemTime);
288
289 /* CurrentCpuIdle = IdleTime / SystemTime */
290 dbIdleTime = dbIdleTime / dbSystemTime;
291 dbKernelTime = dbKernelTime / dbSystemTime;
292
293 /* CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors */
294 dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
295 dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
296 }
297
298 /* Store new CPU's idle and system time */
299 liOldIdleTime = SysPerfInfo.IdleProcessTime;
300 liOldSystemTime = SysTimeInfo.CurrentTime;
301 OldKernelTime = CurrentKernelTime;
302
303 /* Determine the process count
304 * We loop through the data we got from NtQuerySystemInformation
305 * and count how many structures there are (until RelativeOffset is 0)
306 */
307 ProcessCountOld = ProcessCount;
308 ProcessCount = 0;
309 pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
310 while (pSPI) {
311 ProcessCount++;
312 if (pSPI->NextEntryOffset == 0)
313 break;
314 pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset);
315 }
316
317 /* Now alloc a new PERFDATA array and fill in the data */
318 pPerfData = (PPERFDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PERFDATA) * ProcessCount);
319
320 pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
321 for (Idx=0; Idx<ProcessCount; Idx++) {
322 /* Get the old perf data for this process (if any) */
323 /* so that we can establish delta values */
324 pPDOld = NULL;
325 if (pPerfDataOld) {
326 for (Idx2=0; Idx2<ProcessCountOld; Idx2++) {
327 if (pPerfDataOld[Idx2].ProcessId == pSPI->UniqueProcessId) {
328 pPDOld = &pPerfDataOld[Idx2];
329 break;
330 }
331 }
332 }
333
334 if (pSPI->ImageName.Buffer) {
335 /* Don't assume a UNICODE_STRING Buffer is zero terminated: */
336 int len = pSPI->ImageName.Length / 2;
337 /* Check against max size and allow for terminating zero (already zeroed): */
338 if(len >= MAX_PATH)len=MAX_PATH - 1;
339 wcsncpy(pPerfData[Idx].ImageName, pSPI->ImageName.Buffer, len);
340 } else {
341 LoadStringW(hInst, IDS_IDLE_PROCESS, pPerfData[Idx].ImageName,
342 sizeof(pPerfData[Idx].ImageName) / sizeof(pPerfData[Idx].ImageName[0]));
343 }
344
345 pPerfData[Idx].ProcessId = pSPI->UniqueProcessId;
346
347 if (pPDOld) {
348 double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime);
349 double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime);
350 double CpuTime = (CurTime - OldTime) / dbSystemTime;
351 CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
352 pPerfData[Idx].CPUUsage = (ULONG)CpuTime;
353 }
354 pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart;
355 pPerfData[Idx].WorkingSetSizeBytes = pSPI->WorkingSetSize;
356 pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSize;
357 if (pPDOld)
358 pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->WorkingSetSize - (LONG)pPDOld->WorkingSetSizeBytes);
359 else
360 pPerfData[Idx].WorkingSetSizeDelta = 0;
361 pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount;
362 if (pPDOld)
363 pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount);
364 else
365 pPerfData[Idx].PageFaultCountDelta = 0;
366 pPerfData[Idx].VirtualMemorySizeBytes = pSPI->VirtualSize;
367 pPerfData[Idx].PagedPoolUsagePages = pSPI->QuotaPeakPagedPoolUsage;
368 pPerfData[Idx].NonPagedPoolUsagePages = pSPI->QuotaPeakNonPagedPoolUsage;
369 pPerfData[Idx].BasePriority = pSPI->BasePriority;
370 pPerfData[Idx].HandleCount = pSPI->HandleCount;
371 pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads;
372 pPerfData[Idx].SessionId = pSPI->SessionId;
373 pPerfData[Idx].UserName[0] = UNICODE_NULL;
374 pPerfData[Idx].USERObjectCount = 0;
375 pPerfData[Idx].GDIObjectCount = 0;
376 ProcessUser = SystemUserSid;
377 ProcessSD = NULL;
378
379 if (pSPI->UniqueProcessId != NULL) {
380 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | READ_CONTROL, FALSE, PtrToUlong(pSPI->UniqueProcessId));
381 if (hProcess) {
382 /* don't query the information of the system process. It's possible but
383 returns Administrators as the owner of the process instead of SYSTEM */
384 if (pSPI->UniqueProcessId != (HANDLE)0x4)
385 {
386 if (OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken))
387 {
388 DWORD RetLen = 0;
389 BOOL Ret;
390
391 Ret = GetTokenInformation(hProcessToken, TokenUser, (LPVOID)Buffer, sizeof(Buffer), &RetLen);
392 CloseHandle(hProcessToken);
393
394 if (Ret)
395 ProcessUser = ((PTOKEN_USER)Buffer)->User.Sid;
396 else
397 goto ReadProcOwner;
398 }
399 else
400 {
401 ReadProcOwner:
402 GetSecurityInfo(hProcess, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, &ProcessUser, NULL, NULL, NULL, &ProcessSD);
403 }
404
405 pPerfData[Idx].USERObjectCount = GetGuiResources(hProcess, GR_USEROBJECTS);
406 pPerfData[Idx].GDIObjectCount = GetGuiResources(hProcess, GR_GDIOBJECTS);
407 }
408
409 GetProcessIoCounters(hProcess, &pPerfData[Idx].IOCounters);
410 CloseHandle(hProcess);
411 } else {
412 goto ClearInfo;
413 }
414 } else {
415 ClearInfo:
416 /* clear information we were unable to fetch */
417 ZeroMemory(&pPerfData[Idx].IOCounters, sizeof(IO_COUNTERS));
418 }
419
420 cwcUserName = sizeof(pPerfData[0].UserName) / sizeof(pPerfData[0].UserName[0]);
421 CachedGetUserFromSid(ProcessUser, pPerfData[Idx].UserName, &cwcUserName);
422
423 if (ProcessSD != NULL)
424 {
425 LocalFree((HLOCAL)ProcessSD);
426 }
427
428 pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart;
429 pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart;
430 pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset);
431 }
432 HeapFree(GetProcessHeap(), 0, pBuffer);
433 if (pPerfDataOld) {
434 HeapFree(GetProcessHeap(), 0, pPerfDataOld);
435 }
436 pPerfDataOld = pPerfData;
437 LeaveCriticalSection(&PerfDataCriticalSection);
438 }
439
440 ULONG PerfDataGetProcessIndex(ULONG pid)
441 {
442 ULONG idx;
443
444 EnterCriticalSection(&PerfDataCriticalSection);
445
446 for (idx = 0; idx < ProcessCount; idx++)
447 {
448 if (PtrToUlong(pPerfData[idx].ProcessId) == pid)
449 {
450 break;
451 }
452 }
453
454 LeaveCriticalSection(&PerfDataCriticalSection);
455
456 if (idx == ProcessCount)
457 {
458 return -1;
459 }
460 return idx;
461 }
462
463 ULONG PerfDataGetProcessCount(void)
464 {
465 ULONG Result;
466 EnterCriticalSection(&PerfDataCriticalSection);
467 Result = ProcessCount;
468 LeaveCriticalSection(&PerfDataCriticalSection);
469 return Result;
470 }
471
472 ULONG PerfDataGetProcessorUsage(void)
473 {
474 ULONG Result;
475 EnterCriticalSection(&PerfDataCriticalSection);
476 Result = (ULONG)dbIdleTime;
477 LeaveCriticalSection(&PerfDataCriticalSection);
478 return Result;
479 }
480
481 ULONG PerfDataGetProcessorSystemUsage(void)
482 {
483 ULONG Result;
484 EnterCriticalSection(&PerfDataCriticalSection);
485 Result = (ULONG)dbKernelTime;
486 LeaveCriticalSection(&PerfDataCriticalSection);
487 return Result;
488 }
489
490 BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, ULONG nMaxCount)
491 {
492 BOOL bSuccessful;
493
494 EnterCriticalSection(&PerfDataCriticalSection);
495
496 if (Index < ProcessCount) {
497 wcsncpy(lpImageName, pPerfData[Index].ImageName, nMaxCount);
498 bSuccessful = TRUE;
499 } else {
500 bSuccessful = FALSE;
501 }
502 LeaveCriticalSection(&PerfDataCriticalSection);
503 return bSuccessful;
504 }
505
506 ULONG PerfDataGetProcessId(ULONG Index)
507 {
508 ULONG ProcessId;
509
510 EnterCriticalSection(&PerfDataCriticalSection);
511
512 if (Index < ProcessCount)
513 ProcessId = PtrToUlong(pPerfData[Index].ProcessId);
514 else
515 ProcessId = 0;
516
517 LeaveCriticalSection(&PerfDataCriticalSection);
518
519 return ProcessId;
520 }
521
522 BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, ULONG nMaxCount)
523 {
524 BOOL bSuccessful;
525
526 EnterCriticalSection(&PerfDataCriticalSection);
527
528 if (Index < ProcessCount) {
529 wcsncpy(lpUserName, pPerfData[Index].UserName, nMaxCount);
530 bSuccessful = TRUE;
531 } else {
532 bSuccessful = FALSE;
533 }
534
535 LeaveCriticalSection(&PerfDataCriticalSection);
536
537 return bSuccessful;
538 }
539
540 BOOL PerfDataGetCommandLine(ULONG Index, LPWSTR lpCommandLine, ULONG nMaxCount)
541 {
542 static const LPWSTR ellipsis = L"...";
543
544 PROCESS_BASIC_INFORMATION pbi = {0};
545 UNICODE_STRING CommandLineStr = {0};
546
547 PVOID ProcessParams = NULL;
548 HANDLE hProcess;
549 ULONG ProcessId;
550
551 NTSTATUS Status;
552 BOOL result;
553
554 PCMD_LINE_CACHE new_entry;
555 LPWSTR new_string;
556
557 PCMD_LINE_CACHE cache = global_cache;
558
559 /* [A] Search for a string already in cache? If so, use it */
560 while (cache && cache->pnext != NULL)
561 {
562 if (cache->idx == Index && cache->str != NULL)
563 {
564 /* Found it. Use it, and add some ellipsis at the very end to make it cute */
565 wcsncpy(lpCommandLine, cache->str, CMD_LINE_MIN(nMaxCount, cache->len));
566 wcscpy(lpCommandLine + CMD_LINE_MIN(nMaxCount, cache->len) - wcslen(ellipsis), ellipsis);
567 return TRUE;
568 }
569
570 cache = cache->pnext;
571 }
572
573 /* [B] We don't; let's allocate and load a value from the process mem... and cache it */
574 ProcessId = PerfDataGetProcessId(Index);
575
576 /* Default blank command line in case things don't work out */
577 wcsncpy(lpCommandLine, L"", nMaxCount);
578
579 /* Ask for a handle to the target process so that we can read its memory and query stuff */
580 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
581 if (!hProcess)
582 goto cleanup;
583
584 /* First off, get the ProcessEnvironmentBlock location in that process' address space */
585 Status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL);
586 if (!NT_SUCCESS(Status))
587 goto cleanup;
588
589 /* Then get the PEB.ProcessParameters member pointer */
590 result = ReadProcessMemory(hProcess,
591 (PVOID)((ULONG_PTR)pbi.PebBaseAddress + FIELD_OFFSET(PEB, ProcessParameters)),
592 &ProcessParams,
593 sizeof(ProcessParams),
594 NULL);
595 if (!result)
596 goto cleanup;
597
598 /* Then copy the PEB->ProcessParameters.CommandLine member
599 to get the pointer to the string buffer and its size */
600 result = ReadProcessMemory(hProcess,
601 (PVOID)((ULONG_PTR)ProcessParams + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, CommandLine)),
602 &CommandLineStr,
603 sizeof(CommandLineStr),
604 NULL);
605 if (!result)
606 goto cleanup;
607
608 /* Allocate the next cache entry and its accompanying string in one go */
609 new_entry = HeapAlloc(GetProcessHeap(),
610 HEAP_ZERO_MEMORY,
611 sizeof(CMD_LINE_CACHE) + CommandLineStr.Length + sizeof(UNICODE_NULL));
612 if (!new_entry)
613 goto cleanup;
614
615 new_string = (LPWSTR)((ULONG_PTR)new_entry + sizeof(CMD_LINE_CACHE));
616
617 /* Bingo, the command line should be stored there,
618 copy the string from the other process */
619 result = ReadProcessMemory(hProcess,
620 CommandLineStr.Buffer,
621 new_string,
622 CommandLineStr.Length,
623 NULL);
624 if (!result)
625 {
626 /* Weird, after successfully reading the mem of that process
627 various times it fails now, forget it and bail out */
628 HeapFree(GetProcessHeap(), 0, new_entry);
629 goto cleanup;
630 }
631
632 /* Add our pointer to the cache... */
633 new_entry->idx = Index;
634 new_entry->str = new_string;
635 new_entry->len = CommandLineStr.Length;
636
637 if (!global_cache)
638 global_cache = new_entry;
639 else
640 cache->pnext = new_entry;
641
642 /* ... and print the buffer for the first time */
643 wcsncpy(lpCommandLine, new_string, CMD_LINE_MIN(nMaxCount, CommandLineStr.Length));
644
645 cleanup:
646 if (hProcess) CloseHandle(hProcess);
647 return TRUE;
648 }
649
650 void PerfDataDeallocCommandLineCache()
651 {
652 PCMD_LINE_CACHE cache = global_cache;
653 PCMD_LINE_CACHE cache_old;
654
655 while (cache && cache->pnext != NULL)
656 {
657 cache_old = cache;
658 cache = cache->pnext;
659
660 HeapFree(GetProcessHeap(), 0, cache_old);
661 }
662 }
663
664 ULONG PerfDataGetSessionId(ULONG Index)
665 {
666 ULONG SessionId;
667
668 EnterCriticalSection(&PerfDataCriticalSection);
669
670 if (Index < ProcessCount)
671 SessionId = pPerfData[Index].SessionId;
672 else
673 SessionId = 0;
674
675 LeaveCriticalSection(&PerfDataCriticalSection);
676
677 return SessionId;
678 }
679
680 ULONG PerfDataGetCPUUsage(ULONG Index)
681 {
682 ULONG CpuUsage;
683
684 EnterCriticalSection(&PerfDataCriticalSection);
685
686 if (Index < ProcessCount)
687 CpuUsage = pPerfData[Index].CPUUsage;
688 else
689 CpuUsage = 0;
690
691 LeaveCriticalSection(&PerfDataCriticalSection);
692
693 return CpuUsage;
694 }
695
696 LARGE_INTEGER PerfDataGetCPUTime(ULONG Index)
697 {
698 LARGE_INTEGER CpuTime = {{0,0}};
699
700 EnterCriticalSection(&PerfDataCriticalSection);
701
702 if (Index < ProcessCount)
703 CpuTime = pPerfData[Index].CPUTime;
704
705 LeaveCriticalSection(&PerfDataCriticalSection);
706
707 return CpuTime;
708 }
709
710 ULONG PerfDataGetWorkingSetSizeBytes(ULONG Index)
711 {
712 ULONG WorkingSetSizeBytes;
713
714 EnterCriticalSection(&PerfDataCriticalSection);
715
716 if (Index < ProcessCount)
717 WorkingSetSizeBytes = pPerfData[Index].WorkingSetSizeBytes;
718 else
719 WorkingSetSizeBytes = 0;
720
721 LeaveCriticalSection(&PerfDataCriticalSection);
722
723 return WorkingSetSizeBytes;
724 }
725
726 ULONG PerfDataGetPeakWorkingSetSizeBytes(ULONG Index)
727 {
728 ULONG PeakWorkingSetSizeBytes;
729
730 EnterCriticalSection(&PerfDataCriticalSection);
731
732 if (Index < ProcessCount)
733 PeakWorkingSetSizeBytes = pPerfData[Index].PeakWorkingSetSizeBytes;
734 else
735 PeakWorkingSetSizeBytes = 0;
736
737 LeaveCriticalSection(&PerfDataCriticalSection);
738
739 return PeakWorkingSetSizeBytes;
740 }
741
742 ULONG PerfDataGetWorkingSetSizeDelta(ULONG Index)
743 {
744 ULONG WorkingSetSizeDelta;
745
746 EnterCriticalSection(&PerfDataCriticalSection);
747
748 if (Index < ProcessCount)
749 WorkingSetSizeDelta = pPerfData[Index].WorkingSetSizeDelta;
750 else
751 WorkingSetSizeDelta = 0;
752
753 LeaveCriticalSection(&PerfDataCriticalSection);
754
755 return WorkingSetSizeDelta;
756 }
757
758 ULONG PerfDataGetPageFaultCount(ULONG Index)
759 {
760 ULONG PageFaultCount;
761
762 EnterCriticalSection(&PerfDataCriticalSection);
763
764 if (Index < ProcessCount)
765 PageFaultCount = pPerfData[Index].PageFaultCount;
766 else
767 PageFaultCount = 0;
768
769 LeaveCriticalSection(&PerfDataCriticalSection);
770
771 return PageFaultCount;
772 }
773
774 ULONG PerfDataGetPageFaultCountDelta(ULONG Index)
775 {
776 ULONG PageFaultCountDelta;
777
778 EnterCriticalSection(&PerfDataCriticalSection);
779
780 if (Index < ProcessCount)
781 PageFaultCountDelta = pPerfData[Index].PageFaultCountDelta;
782 else
783 PageFaultCountDelta = 0;
784
785 LeaveCriticalSection(&PerfDataCriticalSection);
786
787 return PageFaultCountDelta;
788 }
789
790 ULONG PerfDataGetVirtualMemorySizeBytes(ULONG Index)
791 {
792 ULONG VirtualMemorySizeBytes;
793
794 EnterCriticalSection(&PerfDataCriticalSection);
795
796 if (Index < ProcessCount)
797 VirtualMemorySizeBytes = pPerfData[Index].VirtualMemorySizeBytes;
798 else
799 VirtualMemorySizeBytes = 0;
800
801 LeaveCriticalSection(&PerfDataCriticalSection);
802
803 return VirtualMemorySizeBytes;
804 }
805
806 ULONG PerfDataGetPagedPoolUsagePages(ULONG Index)
807 {
808 ULONG PagedPoolUsage;
809
810 EnterCriticalSection(&PerfDataCriticalSection);
811
812 if (Index < ProcessCount)
813 PagedPoolUsage = pPerfData[Index].PagedPoolUsagePages;
814 else
815 PagedPoolUsage = 0;
816
817 LeaveCriticalSection(&PerfDataCriticalSection);
818
819 return PagedPoolUsage;
820 }
821
822 ULONG PerfDataGetNonPagedPoolUsagePages(ULONG Index)
823 {
824 ULONG NonPagedPoolUsage;
825
826 EnterCriticalSection(&PerfDataCriticalSection);
827
828 if (Index < ProcessCount)
829 NonPagedPoolUsage = pPerfData[Index].NonPagedPoolUsagePages;
830 else
831 NonPagedPoolUsage = 0;
832
833 LeaveCriticalSection(&PerfDataCriticalSection);
834
835 return NonPagedPoolUsage;
836 }
837
838 ULONG PerfDataGetBasePriority(ULONG Index)
839 {
840 ULONG BasePriority;
841
842 EnterCriticalSection(&PerfDataCriticalSection);
843
844 if (Index < ProcessCount)
845 BasePriority = pPerfData[Index].BasePriority;
846 else
847 BasePriority = 0;
848
849 LeaveCriticalSection(&PerfDataCriticalSection);
850
851 return BasePriority;
852 }
853
854 ULONG PerfDataGetHandleCount(ULONG Index)
855 {
856 ULONG HandleCount;
857
858 EnterCriticalSection(&PerfDataCriticalSection);
859
860 if (Index < ProcessCount)
861 HandleCount = pPerfData[Index].HandleCount;
862 else
863 HandleCount = 0;
864
865 LeaveCriticalSection(&PerfDataCriticalSection);
866
867 return HandleCount;
868 }
869
870 ULONG PerfDataGetThreadCount(ULONG Index)
871 {
872 ULONG ThreadCount;
873
874 EnterCriticalSection(&PerfDataCriticalSection);
875
876 if (Index < ProcessCount)
877 ThreadCount = pPerfData[Index].ThreadCount;
878 else
879 ThreadCount = 0;
880
881 LeaveCriticalSection(&PerfDataCriticalSection);
882
883 return ThreadCount;
884 }
885
886 ULONG PerfDataGetUSERObjectCount(ULONG Index)
887 {
888 ULONG USERObjectCount;
889
890 EnterCriticalSection(&PerfDataCriticalSection);
891
892 if (Index < ProcessCount)
893 USERObjectCount = pPerfData[Index].USERObjectCount;
894 else
895 USERObjectCount = 0;
896
897 LeaveCriticalSection(&PerfDataCriticalSection);
898
899 return USERObjectCount;
900 }
901
902 ULONG PerfDataGetGDIObjectCount(ULONG Index)
903 {
904 ULONG GDIObjectCount;
905
906 EnterCriticalSection(&PerfDataCriticalSection);
907
908 if (Index < ProcessCount)
909 GDIObjectCount = pPerfData[Index].GDIObjectCount;
910 else
911 GDIObjectCount = 0;
912
913 LeaveCriticalSection(&PerfDataCriticalSection);
914
915 return GDIObjectCount;
916 }
917
918 BOOL PerfDataGetIOCounters(ULONG Index, PIO_COUNTERS pIoCounters)
919 {
920 BOOL bSuccessful;
921
922 EnterCriticalSection(&PerfDataCriticalSection);
923
924 if (Index < ProcessCount)
925 {
926 memcpy(pIoCounters, &pPerfData[Index].IOCounters, sizeof(IO_COUNTERS));
927 bSuccessful = TRUE;
928 }
929 else
930 bSuccessful = FALSE;
931
932 LeaveCriticalSection(&PerfDataCriticalSection);
933
934 return bSuccessful;
935 }
936
937 ULONG PerfDataGetCommitChargeTotalK(void)
938 {
939 ULONG Total;
940 ULONG PageSize;
941
942 EnterCriticalSection(&PerfDataCriticalSection);
943
944 Total = SystemPerfInfo.CommittedPages;
945 PageSize = SystemBasicInfo.PageSize;
946
947 LeaveCriticalSection(&PerfDataCriticalSection);
948
949 Total = Total * (PageSize / 1024);
950
951 return Total;
952 }
953
954 ULONG PerfDataGetCommitChargeLimitK(void)
955 {
956 ULONG Limit;
957 ULONG PageSize;
958
959 EnterCriticalSection(&PerfDataCriticalSection);
960
961 Limit = SystemPerfInfo.CommitLimit;
962 PageSize = SystemBasicInfo.PageSize;
963
964 LeaveCriticalSection(&PerfDataCriticalSection);
965
966 Limit = Limit * (PageSize / 1024);
967
968 return Limit;
969 }
970
971 ULONG PerfDataGetCommitChargePeakK(void)
972 {
973 ULONG Peak;
974 ULONG PageSize;
975
976 EnterCriticalSection(&PerfDataCriticalSection);
977
978 Peak = SystemPerfInfo.PeakCommitment;
979 PageSize = SystemBasicInfo.PageSize;
980
981 LeaveCriticalSection(&PerfDataCriticalSection);
982
983 Peak = Peak * (PageSize / 1024);
984
985 return Peak;
986 }
987
988 ULONG PerfDataGetKernelMemoryTotalK(void)
989 {
990 ULONG Total;
991 ULONG Paged;
992 ULONG NonPaged;
993 ULONG PageSize;
994
995 EnterCriticalSection(&PerfDataCriticalSection);
996
997 Paged = SystemPerfInfo.PagedPoolPages;
998 NonPaged = SystemPerfInfo.NonPagedPoolPages;
999 PageSize = SystemBasicInfo.PageSize;
1000
1001 LeaveCriticalSection(&PerfDataCriticalSection);
1002
1003 Paged = Paged * (PageSize / 1024);
1004 NonPaged = NonPaged * (PageSize / 1024);
1005
1006 Total = Paged + NonPaged;
1007
1008 return Total;
1009 }
1010
1011 ULONG PerfDataGetKernelMemoryPagedK(void)
1012 {
1013 ULONG Paged;
1014 ULONG PageSize;
1015
1016 EnterCriticalSection(&PerfDataCriticalSection);
1017
1018 Paged = SystemPerfInfo.PagedPoolPages;
1019 PageSize = SystemBasicInfo.PageSize;
1020
1021 LeaveCriticalSection(&PerfDataCriticalSection);
1022
1023 Paged = Paged * (PageSize / 1024);
1024
1025 return Paged;
1026 }
1027
1028 ULONG PerfDataGetKernelMemoryNonPagedK(void)
1029 {
1030 ULONG NonPaged;
1031 ULONG PageSize;
1032
1033 EnterCriticalSection(&PerfDataCriticalSection);
1034
1035 NonPaged = SystemPerfInfo.NonPagedPoolPages;
1036 PageSize = SystemBasicInfo.PageSize;
1037
1038 LeaveCriticalSection(&PerfDataCriticalSection);
1039
1040 NonPaged = NonPaged * (PageSize / 1024);
1041
1042 return NonPaged;
1043 }
1044
1045 ULONG PerfDataGetPhysicalMemoryTotalK(void)
1046 {
1047 ULONG Total;
1048 ULONG PageSize;
1049
1050 EnterCriticalSection(&PerfDataCriticalSection);
1051
1052 Total = SystemBasicInfo.NumberOfPhysicalPages;
1053 PageSize = SystemBasicInfo.PageSize;
1054
1055 LeaveCriticalSection(&PerfDataCriticalSection);
1056
1057 Total = Total * (PageSize / 1024);
1058
1059 return Total;
1060 }
1061
1062 ULONG PerfDataGetPhysicalMemoryAvailableK(void)
1063 {
1064 ULONG Available;
1065 ULONG PageSize;
1066
1067 EnterCriticalSection(&PerfDataCriticalSection);
1068
1069 Available = SystemPerfInfo.AvailablePages;
1070 PageSize = SystemBasicInfo.PageSize;
1071
1072 LeaveCriticalSection(&PerfDataCriticalSection);
1073
1074 Available = Available * (PageSize / 1024);
1075
1076 return Available;
1077 }
1078
1079 ULONG PerfDataGetPhysicalMemorySystemCacheK(void)
1080 {
1081 ULONG SystemCache;
1082 ULONG PageSize;
1083
1084 EnterCriticalSection(&PerfDataCriticalSection);
1085
1086 PageSize = SystemBasicInfo.PageSize;
1087 SystemCache = SystemCacheInfo.CurrentSizeIncludingTransitionInPages * PageSize;
1088
1089 LeaveCriticalSection(&PerfDataCriticalSection);
1090
1091 return SystemCache / 1024;
1092 }
1093
1094 ULONG PerfDataGetSystemHandleCount(void)
1095 {
1096 ULONG HandleCount;
1097
1098 EnterCriticalSection(&PerfDataCriticalSection);
1099
1100 HandleCount = SystemNumberOfHandles;
1101
1102 LeaveCriticalSection(&PerfDataCriticalSection);
1103
1104 return HandleCount;
1105 }
1106
1107 ULONG PerfDataGetTotalThreadCount(void)
1108 {
1109 ULONG ThreadCount = 0;
1110 ULONG i;
1111
1112 EnterCriticalSection(&PerfDataCriticalSection);
1113
1114 for (i=0; i<ProcessCount; i++)
1115 {
1116 ThreadCount += pPerfData[i].ThreadCount;
1117 }
1118
1119 LeaveCriticalSection(&PerfDataCriticalSection);
1120
1121 return ThreadCount;
1122 }
1123
1124 BOOL PerfDataGet(ULONG Index, PPERFDATA *lppData)
1125 {
1126 BOOL bSuccessful = FALSE;
1127
1128 EnterCriticalSection(&PerfDataCriticalSection);
1129 if (Index < ProcessCount)
1130 {
1131 *lppData = pPerfData + Index;
1132 bSuccessful = TRUE;
1133 }
1134 LeaveCriticalSection(&PerfDataCriticalSection);
1135 return bSuccessful;
1136 }
1137