1123 lines
27 KiB
C
1123 lines
27 KiB
C
/*++
|
|
|
|
Copyright (c) 1994-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
common.c
|
|
|
|
Abstract:
|
|
|
|
This module contains common apis used by tlist & kill.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 20-May-1994
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// global variables
|
|
//
|
|
PUCHAR CommonLargeBuffer;
|
|
ULONG CommonLargeBufferSize = 64*1024;
|
|
|
|
//
|
|
// prototypes
|
|
//
|
|
BOOL CALLBACK
|
|
EnumWindowsProc(
|
|
HWND hwnd,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
EnumWindowStationsFunc(
|
|
LPSTR lpstr,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
EnumDesktopsFunc(
|
|
LPSTR lpstr,
|
|
LPARAM lParam
|
|
);
|
|
|
|
|
|
DWORD
|
|
GetServiceProcessInfo(
|
|
LPENUM_SERVICE_STATUS_PROCESS* ppInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provides an API for getting a list of process information for Win 32
|
|
services that are running at the time of the API call.
|
|
|
|
Arguments:
|
|
|
|
ppInfo - address of a pointer to return the information.
|
|
*ppInfo points to memory allocated with malloc.
|
|
|
|
Return Value:
|
|
|
|
Number of ENUM_SERVICE_STATUS_PROCESS structures pointed at by *ppInfo.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwNumServices = 0;
|
|
SC_HANDLE hScm;
|
|
|
|
typedef
|
|
BOOL
|
|
(__stdcall * PFN_ENUMSERVICSESTATUSEXA) (
|
|
SC_HANDLE hSCManager,
|
|
SC_ENUM_TYPE InfoLevel,
|
|
DWORD dwServiceType,
|
|
DWORD dwServiceState,
|
|
LPBYTE lpServices,
|
|
DWORD cbBufSize,
|
|
LPDWORD pcbBytesNeeded,
|
|
LPDWORD lpServicesReturned,
|
|
LPDWORD lpResumeHandle,
|
|
LPCSTR pszGroupName);
|
|
|
|
PFN_ENUMSERVICSESTATUSEXA p_EnumServicesStatusEx;
|
|
HINSTANCE hAdv = LoadLibrary("advapi32.dll");
|
|
|
|
// Initialize the output parmeter.
|
|
*ppInfo = NULL;
|
|
|
|
if (hAdv)
|
|
{
|
|
p_EnumServicesStatusEx = (PFN_ENUMSERVICSESTATUSEXA)
|
|
GetProcAddress(hAdv, "EnumServicesStatusExA");
|
|
|
|
if (!p_EnumServicesStatusEx)
|
|
{
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
// Connect to the service controller.
|
|
//
|
|
hScm = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
|
|
if (hScm) {
|
|
LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL;
|
|
DWORD cbInfo = 4 * 1024;
|
|
DWORD cbExtraNeeded = 0;
|
|
DWORD dwErr;
|
|
DWORD dwResume;
|
|
DWORD cLoop = 0;
|
|
const DWORD cLoopMax = 2;
|
|
|
|
// First pass through the loop allocates from an initial guess. (4K)
|
|
// If that isn't sufficient, we make another pass and allocate
|
|
// what is actually needed. (We only go through the loop a
|
|
// maximum of two times.)
|
|
//
|
|
do {
|
|
free (pInfo);
|
|
cbInfo += cbExtraNeeded;
|
|
pInfo = (LPENUM_SERVICE_STATUS_PROCESS)malloc(cbInfo);
|
|
if (!pInfo) {
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
dwResume = 0;
|
|
if (!p_EnumServicesStatusEx(
|
|
hScm,
|
|
SC_ENUM_PROCESS_INFO,
|
|
SERVICE_WIN32,
|
|
SERVICE_ACTIVE,
|
|
(LPBYTE)pInfo,
|
|
cbInfo,
|
|
&cbExtraNeeded,
|
|
&dwNumServices,
|
|
&dwResume,
|
|
NULL)) {
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
while ((ERROR_MORE_DATA == dwErr) && (++cLoop < cLoopMax));
|
|
|
|
if ((ERROR_SUCCESS == dwErr) && dwNumServices) {
|
|
*ppInfo = pInfo;
|
|
} else {
|
|
free (pInfo);
|
|
dwNumServices = 0;
|
|
}
|
|
|
|
CloseServiceHandle(hScm);
|
|
}
|
|
|
|
return dwNumServices;
|
|
}
|
|
|
|
DWORD
|
|
GetTaskListEx(
|
|
PTASK_LIST pTask,
|
|
DWORD dwNumTasks,
|
|
BOOL fThreadInfo,
|
|
DWORD dwNumServices,
|
|
const ENUM_SERVICE_STATUS_PROCESS* pServiceInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provides an API for getting a list of tasks running at the time of the
|
|
API call. This function uses internal NT apis and data structures. This
|
|
api is MUCH faster that the non-internal version that uses the registry.
|
|
|
|
Arguments:
|
|
pTask - Array of TASK_LIST structures to fill.
|
|
dwNumTasks - Maximum number of tasks that the pTask array can hold.
|
|
fThreadInfo - TRUE if thread information is desired.
|
|
dwNumServices - Maximum number of entries in pServiceInfo.
|
|
pServiceInfo - Array of service status structures to reference
|
|
for supporting services in processes.
|
|
|
|
Return Value:
|
|
|
|
Number of tasks placed into the pTask array.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
|
|
NTSTATUS status;
|
|
ANSI_STRING pname;
|
|
PCHAR p;
|
|
ULONG TotalOffset;
|
|
ULONG totalTasks = 0;
|
|
|
|
retry:
|
|
|
|
if (CommonLargeBuffer == NULL) {
|
|
CommonLargeBuffer = VirtualAlloc (NULL,
|
|
CommonLargeBufferSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
if (CommonLargeBuffer == NULL) {
|
|
return 0;
|
|
}
|
|
}
|
|
status = NtQuerySystemInformation(
|
|
SystemProcessInformation,
|
|
CommonLargeBuffer,
|
|
CommonLargeBufferSize,
|
|
NULL
|
|
);
|
|
|
|
if (status == STATUS_INFO_LENGTH_MISMATCH) {
|
|
CommonLargeBufferSize += 8192;
|
|
VirtualFree (CommonLargeBuffer, 0, MEM_RELEASE);
|
|
CommonLargeBuffer = NULL;
|
|
goto retry;
|
|
}
|
|
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) CommonLargeBuffer;
|
|
TotalOffset = 0;
|
|
while (TRUE) {
|
|
pname.Buffer = NULL;
|
|
if ( ProcessInfo->ImageName.Buffer ) {
|
|
RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
|
|
if (pname.Buffer) {
|
|
p = strrchr(pname.Buffer,'\\');
|
|
if ( p ) {
|
|
p++;
|
|
}
|
|
else {
|
|
p = pname.Buffer;
|
|
}
|
|
} else {
|
|
p = "";
|
|
}
|
|
}
|
|
else {
|
|
p = "System Process";
|
|
}
|
|
|
|
strncpy( pTask->ProcessName, p, PROCESS_SIZE );
|
|
pTask->ProcessName[PROCESS_SIZE-1] = '\0';
|
|
pTask->flags = 0;
|
|
pTask->dwProcessId = (DWORD)(DWORD_PTR)ProcessInfo->UniqueProcessId;
|
|
pTask->dwInheritedFromProcessId = (DWORD)(DWORD_PTR)ProcessInfo->InheritedFromUniqueProcessId;
|
|
pTask->CreateTime.QuadPart = (ULONGLONG)ProcessInfo->CreateTime.QuadPart;
|
|
|
|
pTask->PeakVirtualSize = ProcessInfo->PeakVirtualSize;
|
|
pTask->VirtualSize = ProcessInfo->VirtualSize;
|
|
pTask->PageFaultCount = ProcessInfo->PageFaultCount;
|
|
pTask->PeakWorkingSetSize = ProcessInfo->PeakWorkingSetSize;
|
|
pTask->WorkingSetSize = ProcessInfo->WorkingSetSize;
|
|
pTask->NumberOfThreads = ProcessInfo->NumberOfThreads;
|
|
|
|
if (fThreadInfo) {
|
|
if (pTask->pThreadInfo = malloc(pTask->NumberOfThreads * sizeof(THREAD_INFO))) {
|
|
|
|
UINT nThread = pTask->NumberOfThreads;
|
|
PTHREAD_INFO pThreadInfo = pTask->pThreadInfo;
|
|
PSYSTEM_THREAD_INFORMATION pSysThreadInfo =
|
|
(PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
|
|
|
|
while (nThread--) {
|
|
pThreadInfo->ThreadState = pSysThreadInfo->ThreadState;
|
|
pThreadInfo->UniqueThread = pSysThreadInfo->ClientId.UniqueThread;
|
|
|
|
pThreadInfo++;
|
|
pSysThreadInfo++;
|
|
}
|
|
}
|
|
} else {
|
|
pTask->pThreadInfo = NULL;
|
|
}
|
|
|
|
pTask->MtsPackageNames[0] = 0;
|
|
pTask->SessionId = ProcessInfo->SessionId;
|
|
pTask->CommandLine[0] = 0;
|
|
|
|
// Initialize the ServiceNames if this task hosts any.
|
|
//
|
|
*pTask->ServiceNames = 0;
|
|
if (dwNumServices)
|
|
{
|
|
// For each service with this process id, append it's service
|
|
// name to the buffer. Separate each with a comma.
|
|
//
|
|
BOOL fFirstTime = TRUE;
|
|
DWORD iSvc;
|
|
size_t cchRemain = SERVICENAMES_SIZE - 1;
|
|
size_t cch;
|
|
|
|
for (iSvc = 0; iSvc < dwNumServices; iSvc++) {
|
|
if (pTask->dwProcessId == pServiceInfo[iSvc].ServiceStatusProcess.dwProcessId) {
|
|
cch = strlen(pServiceInfo[iSvc].lpServiceName);
|
|
|
|
if (fFirstTime) {
|
|
fFirstTime = FALSE;
|
|
|
|
strncpy(
|
|
pTask->ServiceNames,
|
|
pServiceInfo[iSvc].lpServiceName,
|
|
cchRemain);
|
|
|
|
// strncpy may not terminate the string if
|
|
// cchRemain <= cch so we do it regardless.
|
|
//
|
|
pTask->ServiceNames[cchRemain] = 0;
|
|
} else if (cchRemain > 1) { // ensure room for the comma
|
|
strncat(
|
|
pTask->ServiceNames,
|
|
",",
|
|
cchRemain--);
|
|
|
|
strncat(
|
|
pTask->ServiceNames,
|
|
pServiceInfo[iSvc].lpServiceName,
|
|
cchRemain);
|
|
}
|
|
|
|
// Counts are unsigned so we have to check before
|
|
// subtracting.
|
|
//
|
|
if (cchRemain < cch) {
|
|
// No more room for any more.
|
|
break;
|
|
} else {
|
|
cchRemain -= cch;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pTask++;
|
|
totalTasks++;
|
|
if (totalTasks == dwNumTasks) {
|
|
break;
|
|
}
|
|
if (ProcessInfo->NextEntryOffset == 0) {
|
|
break;
|
|
}
|
|
TotalOffset += ProcessInfo->NextEntryOffset;
|
|
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CommonLargeBuffer[TotalOffset];
|
|
}
|
|
|
|
return totalTasks;
|
|
}
|
|
|
|
DWORD
|
|
GetTaskList(
|
|
PTASK_LIST pTask,
|
|
DWORD dwNumTasks
|
|
)
|
|
{
|
|
return GetTaskListEx(pTask, dwNumTasks, FALSE, 0, NULL);
|
|
}
|
|
|
|
void
|
|
AddMtsPackageNames(
|
|
PTASK_LIST Tasks,
|
|
DWORD NumTasks
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
IMtsGrp* MtsGroup;
|
|
long Packages;
|
|
long i;
|
|
|
|
if ((Hr = CoInitialize(NULL)) != S_OK) {
|
|
return;
|
|
}
|
|
if ((Hr = CoCreateInstance(&CLSID_MtsGrp, NULL, CLSCTX_ALL,
|
|
&IID_IMtsGrp, (void **)&MtsGroup)) != S_OK) {
|
|
goto Uninit;
|
|
}
|
|
|
|
if ((Hr = MtsGroup->lpVtbl->Refresh(MtsGroup)) != S_OK ||
|
|
(Hr = MtsGroup->lpVtbl->get_Count(MtsGroup, &Packages)) != S_OK) {
|
|
goto ReleaseGroup;
|
|
}
|
|
|
|
for (i = 0; i < Packages; i++) {
|
|
IUnknown* Unk;
|
|
IMtsEvents* Events;
|
|
BSTR Name;
|
|
DWORD Pid;
|
|
DWORD TaskIdx;
|
|
|
|
if ((Hr = MtsGroup->lpVtbl->Item(MtsGroup, i, &Unk)) != S_OK) {
|
|
continue;
|
|
}
|
|
|
|
Hr = Unk->lpVtbl->QueryInterface(Unk, &IID_IMtsEvents,
|
|
(void **)&Events);
|
|
|
|
Unk->lpVtbl->Release(Unk);
|
|
|
|
if (Hr != S_OK) {
|
|
continue;
|
|
}
|
|
|
|
Hr = Events->lpVtbl->GetProcessID(Events, (PLONG)&Pid);
|
|
if (Hr == S_OK) {
|
|
Hr = Events->lpVtbl->get_PackageName(Events, &Name);
|
|
}
|
|
|
|
Events->lpVtbl->Release(Events);
|
|
|
|
if (Hr != S_OK) {
|
|
continue;
|
|
}
|
|
|
|
for (TaskIdx = 0; TaskIdx < NumTasks; TaskIdx++) {
|
|
if (Tasks[TaskIdx].dwProcessId == Pid) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TaskIdx < NumTasks) {
|
|
PSTR Str;
|
|
int Conv;
|
|
|
|
Str = Tasks[TaskIdx].MtsPackageNames +
|
|
strlen(Tasks[TaskIdx].MtsPackageNames);
|
|
if (Str > Tasks[TaskIdx].MtsPackageNames) {
|
|
*Str++ = ',';
|
|
}
|
|
|
|
Conv = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
Name,
|
|
-1,
|
|
Str,
|
|
MTS_PACKAGE_NAMES_SIZE -
|
|
(DWORD)(Str - Tasks[TaskIdx].MtsPackageNames) - 2,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
SysFreeString(Name);
|
|
|
|
if (Conv == 0 && Str > Tasks[TaskIdx].MtsPackageNames &&
|
|
*(Str - 1) == ',') {
|
|
*(Str - 1) = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
ReleaseGroup:
|
|
MtsGroup->lpVtbl->Release(MtsGroup);
|
|
Uninit:
|
|
CoUninitialize();
|
|
return;
|
|
}
|
|
|
|
void
|
|
AddCommandLines(
|
|
PTASK_LIST Tasks,
|
|
DWORD NumTasks
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DWORD TaskIdx;
|
|
PTASK_LIST Task;
|
|
|
|
Task = Tasks;
|
|
for (TaskIdx = 0; TaskIdx < NumTasks; TaskIdx++, Task++) {
|
|
|
|
HANDLE Process;
|
|
int Conv;
|
|
PROCESS_BASIC_INFORMATION Basic;
|
|
PEB Peb;
|
|
RTL_USER_PROCESS_PARAMETERS ProcParams;
|
|
ULONG Done;
|
|
SIZE_T DoneSize;
|
|
PWSTR CmdLine;
|
|
|
|
Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
|
FALSE, Task->dwProcessId);
|
|
if (!Process) {
|
|
continue;
|
|
}
|
|
|
|
NtStatus = NtQueryInformationProcess(Process, ProcessBasicInformation,
|
|
&Basic, sizeof(Basic), &Done);
|
|
if (!NT_SUCCESS(NtStatus) ||
|
|
Done != sizeof(Basic) ||
|
|
!Basic.PebBaseAddress ||
|
|
!ReadProcessMemory(Process, Basic.PebBaseAddress,
|
|
&Peb, sizeof(Peb), &DoneSize) ||
|
|
DoneSize != sizeof(Peb) ||
|
|
!ReadProcessMemory(Process, Peb.ProcessParameters,
|
|
&ProcParams, sizeof(ProcParams), &DoneSize) ||
|
|
DoneSize != sizeof(ProcParams) ||
|
|
!ProcParams.CommandLine.Buffer ||
|
|
!(CmdLine = (PWSTR)malloc(ProcParams.CommandLine.Length +
|
|
sizeof(WCHAR)))) {
|
|
goto EH_Process;
|
|
}
|
|
|
|
if (!ReadProcessMemory(Process, ProcParams.CommandLine.Buffer,
|
|
CmdLine, ProcParams.CommandLine.Length,
|
|
&DoneSize) ||
|
|
DoneSize < ProcParams.CommandLine.Length) {
|
|
goto EH_CmdLine;
|
|
}
|
|
|
|
CmdLine[DoneSize / sizeof(WCHAR)] = 0;
|
|
|
|
if (!WideCharToMultiByte(CP_ACP, 0, CmdLine, -1,
|
|
Task->CommandLine,
|
|
sizeof(Task->CommandLine) - 1,
|
|
NULL, NULL)) {
|
|
Task->CommandLine[0] = 0;
|
|
}
|
|
|
|
EH_CmdLine:
|
|
free(CmdLine);
|
|
EH_Process:
|
|
CloseHandle(Process);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
DetectOrphans(
|
|
PTASK_LIST pTask,
|
|
DWORD dwNumTasks
|
|
)
|
|
{
|
|
DWORD i, j;
|
|
BOOL Result = FALSE;
|
|
|
|
for (i=0; i<dwNumTasks; i++) {
|
|
if (pTask[i].dwInheritedFromProcessId != 0) {
|
|
for (j=0; j<dwNumTasks; j++) {
|
|
if (i != j && pTask[i].dwInheritedFromProcessId == pTask[j].dwProcessId) {
|
|
if (pTask[i].CreateTime.QuadPart <= pTask[j].CreateTime.QuadPart) {
|
|
pTask[i].dwInheritedFromProcessId = 0;
|
|
Result = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOL
|
|
EnableDebugPriv(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Changes the tlist process's privilige so that kill works properly.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - success
|
|
FALSE - failure
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE hToken;
|
|
LUID DebugValue;
|
|
TOKEN_PRIVILEGES tkp;
|
|
|
|
//
|
|
// Retrieve a handle of the access token
|
|
//
|
|
if (!OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&hToken)) {
|
|
printf("OpenProcessToken failed with %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enable the SE_DEBUG_NAME privilege or disable
|
|
// all privileges, depending on the fEnable flag.
|
|
//
|
|
if (!LookupPrivilegeValue((LPSTR) NULL,
|
|
SE_DEBUG_NAME,
|
|
&DebugValue)) {
|
|
printf("LookupPrivilegeValue failed with %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
tkp.PrivilegeCount = 1;
|
|
tkp.Privileges[0].Luid = DebugValue;
|
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (!AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tkp,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
(PTOKEN_PRIVILEGES) NULL,
|
|
(PDWORD) NULL)) {
|
|
//
|
|
// The return value of AdjustTokenPrivileges be texted
|
|
//
|
|
printf("AdjustTokenPrivileges failed with %d\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
KillProcess(
|
|
PTASK_LIST tlist,
|
|
BOOL fForce
|
|
)
|
|
{
|
|
HANDLE hProcess, hProcess1;
|
|
HDESK hdeskSave;
|
|
HDESK hdesk;
|
|
HWINSTA hwinsta;
|
|
HWINSTA hwinstaSave;
|
|
|
|
|
|
if (fForce || !tlist->hwnd) {
|
|
hProcess1 = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
|
|
if (hProcess1) {
|
|
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
|
|
if (hProcess == NULL) {
|
|
CloseHandle(hProcess1);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!TerminateProcess( hProcess, 1 )) {
|
|
CloseHandle( hProcess );
|
|
CloseHandle( hProcess1 );
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle( hProcess );
|
|
CloseHandle( hProcess1 );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// save the current windowstation
|
|
//
|
|
hwinstaSave = GetProcessWindowStation();
|
|
|
|
//
|
|
// save the current desktop
|
|
//
|
|
hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
|
|
|
|
//
|
|
// open the windowstation
|
|
//
|
|
hwinsta = OpenWindowStation( tlist->lpWinsta, FALSE, MAXIMUM_ALLOWED );
|
|
if (!hwinsta) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// change the context to the new windowstation
|
|
//
|
|
SetProcessWindowStation( hwinsta );
|
|
|
|
//
|
|
// open the desktop
|
|
//
|
|
hdesk = OpenDesktop( tlist->lpDesk, 0, FALSE, MAXIMUM_ALLOWED );
|
|
if (!hdesk) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// change the context to the new desktop
|
|
//
|
|
SetThreadDesktop( hdesk );
|
|
|
|
//
|
|
// kill the process
|
|
//
|
|
PostMessage( tlist->hwnd, WM_CLOSE, 0, 0 );
|
|
|
|
//
|
|
// restore the previous desktop
|
|
//
|
|
if (hdesk != hdeskSave) {
|
|
SetThreadDesktop( hdeskSave );
|
|
CloseDesktop( hdesk );
|
|
}
|
|
|
|
//
|
|
// restore the context to the previous windowstation
|
|
//
|
|
if (hwinsta != hwinstaSave) {
|
|
SetProcessWindowStation( hwinstaSave );
|
|
CloseWindowStation( hwinsta );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
GetWindowTitles(
|
|
PTASK_LIST_ENUM te
|
|
)
|
|
{
|
|
//
|
|
// enumerate all windows and try to get the window
|
|
// titles for each task
|
|
//
|
|
EnumWindowStations( EnumWindowStationsFunc, (LPARAM)te );
|
|
}
|
|
|
|
|
|
BOOL CALLBACK
|
|
EnumWindowStationsFunc(
|
|
LPSTR lpstr,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback function for windowstation enumeration.
|
|
|
|
Arguments:
|
|
|
|
lpstr - windowstation name
|
|
lParam - ** not used **
|
|
|
|
Return Value:
|
|
|
|
TRUE - continues the enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
|
|
HWINSTA hwinsta;
|
|
HWINSTA hwinstaSave;
|
|
|
|
|
|
//
|
|
// open the windowstation
|
|
//
|
|
hwinsta = OpenWindowStation( lpstr, FALSE, MAXIMUM_ALLOWED );
|
|
if (!hwinsta) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// save the current windowstation
|
|
//
|
|
hwinstaSave = GetProcessWindowStation();
|
|
|
|
//
|
|
// change the context to the new windowstation
|
|
//
|
|
SetProcessWindowStation( hwinsta );
|
|
|
|
te->lpWinsta = _strdup( lpstr );
|
|
|
|
//
|
|
// enumerate all the desktops for this windowstation
|
|
//
|
|
EnumDesktops( hwinsta, EnumDesktopsFunc, lParam );
|
|
|
|
//
|
|
// restore the context to the previous windowstation
|
|
//
|
|
if (hwinsta != hwinstaSave) {
|
|
SetProcessWindowStation( hwinstaSave );
|
|
CloseWindowStation( hwinsta );
|
|
}
|
|
|
|
//
|
|
// continue the enumeration
|
|
//
|
|
return TRUE;
|
|
}
|
|
BOOL CALLBACK
|
|
EnumMessageWindows(
|
|
WNDENUMPROC lpEnumFunc,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumarates message windows (which are not enumarated by EnumWindows)
|
|
|
|
Arguments:
|
|
|
|
lpEnumFunc - Callback function
|
|
lParam - Caller data
|
|
|
|
Return Value:
|
|
|
|
TRUE
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HWND hwnd = NULL;
|
|
do {
|
|
hwnd = FindWindowEx(HWND_MESSAGE, hwnd, NULL, NULL);
|
|
if (hwnd != NULL) {
|
|
if (!(*lpEnumFunc)(hwnd, lParam)) {
|
|
break;
|
|
}
|
|
}
|
|
} while (hwnd != NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
EnumDesktopsFunc(
|
|
LPSTR lpstr,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback function for desktop enumeration.
|
|
|
|
Arguments:
|
|
|
|
lpstr - desktop name
|
|
lParam - ** not used **
|
|
|
|
Return Value:
|
|
|
|
TRUE - continues the enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
|
|
HDESK hdeskSave;
|
|
HDESK hdesk;
|
|
|
|
|
|
//
|
|
// open the desktop
|
|
//
|
|
hdesk = OpenDesktop( lpstr, 0, FALSE, MAXIMUM_ALLOWED );
|
|
if (!hdesk) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// save the current desktop
|
|
//
|
|
hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
|
|
|
|
//
|
|
// change the context to the new desktop
|
|
//
|
|
SetThreadDesktop( hdesk );
|
|
|
|
te->lpDesk = _strdup( lpstr );
|
|
|
|
//
|
|
// enumerate all windows in the new desktop
|
|
//
|
|
|
|
((PTASK_LIST_ENUM)lParam)->bFirstLoop = TRUE;
|
|
EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
|
|
EnumMessageWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
|
|
|
|
((PTASK_LIST_ENUM)lParam)->bFirstLoop = FALSE;
|
|
EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
|
|
EnumMessageWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
|
|
|
|
//
|
|
// restore the previous desktop
|
|
//
|
|
if (hdesk != hdeskSave) {
|
|
SetThreadDesktop( hdeskSave );
|
|
CloseDesktop( hdesk );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CALLBACK
|
|
EnumWindowsProc(
|
|
HWND hwnd,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback function for window enumeration.
|
|
|
|
Arguments:
|
|
|
|
hwnd - window handle
|
|
lParam - pte
|
|
|
|
Return Value:
|
|
|
|
TRUE - continues the enumeration
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD pid = 0;
|
|
DWORD i;
|
|
CHAR buf[TITLE_SIZE];
|
|
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
|
|
PTASK_LIST tlist = te->tlist;
|
|
DWORD numTasks = te->numtasks;
|
|
|
|
|
|
//
|
|
// Use try/except block when enumerating windows,
|
|
// as a window may be destroyed by another thread
|
|
// when being enumerated.
|
|
//
|
|
try {
|
|
//
|
|
// get the processid for this window
|
|
//
|
|
if (!GetWindowThreadProcessId( hwnd, &pid )) {
|
|
return TRUE;
|
|
}
|
|
|
|
if ((GetWindow( hwnd, GW_OWNER )) ||
|
|
(!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)) && te->bFirstLoop) {
|
|
//
|
|
// not a top level window
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// look for the task in the task list for this window
|
|
// If this is the second time let invisible windows through if we don't
|
|
// have a window already
|
|
//
|
|
for (i=0; i<numTasks; i++) {
|
|
if ((tlist[i].dwProcessId == pid) && (te->bFirstLoop || (tlist[i].hwnd == 0))) {
|
|
tlist[i].hwnd = hwnd;
|
|
tlist[i].lpWinsta = te->lpWinsta;
|
|
tlist[i].lpDesk = te->lpDesk;
|
|
//
|
|
// we found the task no lets try to get the
|
|
// window text
|
|
//
|
|
if (GetWindowText( tlist[i].hwnd, buf, sizeof(buf) )) {
|
|
//
|
|
// go it, so lets save it
|
|
//
|
|
strcpy( tlist[i].WindowTitle, buf );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
|
|
//
|
|
// continue the enumeration
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MatchPattern(
|
|
PUCHAR String,
|
|
PUCHAR Pattern
|
|
)
|
|
{
|
|
INT c, p, l;
|
|
|
|
for (; ;) {
|
|
switch (p = *Pattern++) {
|
|
case 0: // end of pattern
|
|
return *String ? FALSE : TRUE; // if end of string TRUE
|
|
|
|
case '*':
|
|
while (*String) { // match zero or more char
|
|
if (MatchPattern (String++, Pattern))
|
|
return TRUE;
|
|
}
|
|
return MatchPattern (String, Pattern);
|
|
|
|
case '?':
|
|
if (*String++ == 0) // match any one char
|
|
return FALSE; // not end of string
|
|
break;
|
|
|
|
case '[':
|
|
if ( (c = *String++) == 0) // match char set
|
|
return FALSE; // syntax
|
|
|
|
c = toupper(c);
|
|
l = 0;
|
|
while (p = *Pattern++) {
|
|
if (p == ']') // if end of char set, then
|
|
return FALSE; // no match found
|
|
|
|
if (p == '-') { // check a range of chars?
|
|
p = *Pattern; // get high limit of range
|
|
if (p == 0 || p == ']')
|
|
return FALSE; // syntax
|
|
|
|
if (c >= l && c <= p)
|
|
break; // if in range, move on
|
|
}
|
|
|
|
l = p;
|
|
if (c == p) // if char matches this element
|
|
break; // move on
|
|
}
|
|
|
|
while (p && p != ']') // got a match in char set
|
|
p = *Pattern++; // skip to end of set
|
|
|
|
break;
|
|
|
|
default:
|
|
c = *String++;
|
|
if (toupper(c) != p) // check for exact char
|
|
return FALSE; // not a match
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
EmptyProcessWorkingSet(
|
|
DWORD pid
|
|
)
|
|
{
|
|
HANDLE hProcess;
|
|
SIZE_T dwMinimumWorkingSetSize;
|
|
SIZE_T dwMaximumWorkingSetSize;
|
|
|
|
|
|
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
|
|
if (hProcess == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetProcessWorkingSetSize(
|
|
hProcess,
|
|
&dwMinimumWorkingSetSize,
|
|
&dwMaximumWorkingSetSize
|
|
)) {
|
|
CloseHandle( hProcess );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
SetProcessWorkingSetSize( hProcess, 0xffffffff, 0xffffffff );
|
|
CloseHandle( hProcess );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
EmptySystemWorkingSet(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
SYSTEM_FILECACHE_INFORMATION info;
|
|
NTSTATUS status;
|
|
|
|
info.MinimumWorkingSet = 0xffffffff;
|
|
info.MaximumWorkingSet = 0xffffffff;
|
|
if (!NT_SUCCESS (status = NtSetSystemInformation(
|
|
SystemFileCacheInformation,
|
|
&info,
|
|
sizeof (info)))) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|