*
* perfdata.c
*
- * Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
+ * Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
+ * Copyright (C) 2014 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <aclapi.h>
#define NTOS_MODE_USER
+#include <ndk/psfuncs.h>
#include <ndk/exfuncs.h>
CRITICAL_SECTION PerfDataCriticalSection;
PPERFDATA pPerfDataOld = NULL; /* Older perf data (saved to establish delta values) */
-PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */
+PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */
ULONG ProcessCountOld = 0;
ULONG ProcessCount = 0;
double dbIdleTime;
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemProcessorTimeInfo = NULL;
PSID SystemUserSid = NULL;
+PCMD_LINE_CACHE global_cache = NULL;
+
+#define CMD_LINE_MIN(a, b) (a < b ? a - sizeof(WCHAR) : b)
+
typedef struct _SIDTOUSERNAME
{
LIST_ENTRY List;
pPerfData[Idx].HandleCount = pSPI->HandleCount;
pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads;
pPerfData[Idx].SessionId = pSPI->SessionId;
- pPerfData[Idx].UserName[0] = L'\0';
+ pPerfData[Idx].UserName[0] = UNICODE_NULL;
pPerfData[Idx].USERObjectCount = 0;
pPerfData[Idx].GDIObjectCount = 0;
ProcessUser = SystemUserSid;
return (ULONG)dbKernelTime;
}
-BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, int nMaxCount)
+BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, ULONG nMaxCount)
{
BOOL bSuccessful;
return ProcessId;
}
-BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, int nMaxCount)
+BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, ULONG nMaxCount)
{
BOOL bSuccessful;
return bSuccessful;
}
+BOOL PerfDataGetCommandLine(ULONG Index, LPWSTR lpCommandLine, ULONG nMaxCount)
+{
+ static const LPWSTR ellipsis = L"...";
+
+ PROCESS_BASIC_INFORMATION pbi = {0};
+ UNICODE_STRING CommandLineStr = {0};
+
+ PVOID ProcessParams = NULL;
+ HANDLE hProcess;
+ ULONG ProcessId;
+
+ NTSTATUS Status;
+ BOOL result;
+
+ PCMD_LINE_CACHE new_entry;
+ LPWSTR new_string;
+
+ PCMD_LINE_CACHE cache = global_cache;
+
+ /* [A] Search for a string already in cache? If so, use it */
+ while (cache && cache->pnext != NULL)
+ {
+ if (cache->idx == Index && cache->str != NULL)
+ {
+ /* Found it. Use it, and add some ellipsis at the very end to make it cute */
+ wcsncpy(lpCommandLine, cache->str, CMD_LINE_MIN(nMaxCount, cache->len));
+ wcscpy(lpCommandLine + CMD_LINE_MIN(nMaxCount, cache->len) - sizeof(ellipsis)/sizeof(WCHAR), ellipsis);
+ return TRUE;
+ }
+
+ cache = cache->pnext;
+ }
+
+ /* [B] We don't; let's allocate and load a value from the process mem... and cache it */
+ ProcessId = PerfDataGetProcessId(Index);
+
+ /* Default blank command line in case things don't work out */
+ wcsncpy(lpCommandLine, L"", nMaxCount);
+
+ /* Ask for a handle to the target process so that we can read its memory and query stuff */
+ hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId);
+ if (!hProcess)
+ goto cleanup;
+
+ /* First off, get the ProcessEnvironmentBlock location in that process' address space */
+ Status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL);
+ if (!NT_SUCCESS(Status))
+ goto cleanup;
+
+ /* Then get the PEB.ProcessParameters member pointer */
+ result = ReadProcessMemory(hProcess,
+ (PVOID)((ULONG_PTR)pbi.PebBaseAddress + FIELD_OFFSET(PEB, ProcessParameters)),
+ &ProcessParams,
+ sizeof(ProcessParams),
+ NULL);
+ if (!result)
+ goto cleanup;
+
+ /* Then copy the PEB->ProcessParameters.CommandLine member
+ to get the pointer to the string buffer and its size */
+ result = ReadProcessMemory(hProcess,
+ (PVOID)((ULONG_PTR)ProcessParams + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, CommandLine)),
+ &CommandLineStr,
+ sizeof(CommandLineStr),
+ NULL);
+ if (!result)
+ goto cleanup;
+
+ /* Allocate the next cache entry and its accompanying string in one go */
+ new_entry = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(CMD_LINE_CACHE) + CommandLineStr.Length + sizeof(UNICODE_NULL));
+ if (!new_entry)
+ goto cleanup;
+
+ new_string = (LPWSTR)((ULONG_PTR)new_entry + sizeof(CMD_LINE_CACHE));
+
+ /* Bingo, the command line should be stored there,
+ copy the string from the other process */
+ result = ReadProcessMemory(hProcess,
+ CommandLineStr.Buffer,
+ new_string,
+ CommandLineStr.Length,
+ NULL);
+ if (!result)
+ {
+ /* Weird, after sucessfully reading the mem of that process
+ various times it fails now, forget it and bail out */
+ HeapFree(GetProcessHeap(), 0, new_entry);
+ goto cleanup;
+ }
+
+ /* Add our pointer to the cache... */
+ new_entry->idx = Index;
+ new_entry->str = new_string;
+ new_entry->len = CommandLineStr.Length;
+
+ if (!global_cache)
+ global_cache = new_entry;
+ else
+ cache->pnext = new_entry;
+
+ /* ... and print the buffer for the first time */
+ wcsncpy(lpCommandLine, new_string, CMD_LINE_MIN(nMaxCount, CommandLineStr.Length));
+
+cleanup:
+ if (hProcess) CloseHandle(hProcess);
+ return TRUE;
+}
+
+void PerfDataDeallocCommandLineCache()
+{
+ PCMD_LINE_CACHE cache = global_cache;
+ PCMD_LINE_CACHE cache_old;
+
+ while (cache && cache->pnext != NULL)
+ {
+ cache_old = cache;
+ cache = cache->pnext;
+
+ HeapFree(GetProcessHeap(), 0, cache_old);
+ }
+}
+
ULONG PerfDataGetSessionId(ULONG Index)
{
ULONG SessionId;