607 lines
14 KiB
C++
607 lines
14 KiB
C++
// OXProcess.cpp: implementation of the COXProcess class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Version: 9.3
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "OXProcess.h"
|
|
#include "OXMainRes.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
typedef BOOL (FAR WINAPI *ISDEBUGGERPRESENT) (VOID);
|
|
|
|
BOOL IsRunningNT()
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if(!::GetVersionEx(&osvi))
|
|
return FALSE;
|
|
return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
|
}
|
|
|
|
|
|
BOOL COXProcess::m_bIsRunningNT=IsRunningNT();
|
|
|
|
BOOL COXProcess::m_bProcessFunctionsInitialized=FALSE;
|
|
HINSTANCE COXProcess::m_hProcessHelperLib=NULL;
|
|
// PSAPI functions
|
|
PFNENUMPROCESSES COXProcess::pfnEnumProcesses=NULL;
|
|
PFNENUMPROCESSMODULES COXProcess::pfnEnumProcessModules=NULL;
|
|
PFNGETMODULEFILENAMEEXA COXProcess::pfnGetModuleFileNameExA=NULL;
|
|
// Toolhelp32 functions
|
|
PFNCREATETOOLHELP32SNAPSHOT COXProcess::pfnCreateToolhelp32Snapshot=NULL;
|
|
PFNPROCESS32FIRST COXProcess::pfnProcess32First=NULL;
|
|
PFNPROCESS32NEXT COXProcess::pfnProcess32Next=NULL;
|
|
PFNMODULE32FIRST COXProcess::pfnModule32First=NULL;
|
|
PFNMODULE32NEXT COXProcess::pfnModule32Next=NULL;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Destructor
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
COXProcess::~COXProcess()
|
|
{
|
|
if(m_bProcessFunctionsInitialized && m_hProcessHelperLib!=NULL)
|
|
{
|
|
::FreeLibrary(m_hProcessHelperLib);
|
|
m_bProcessFunctionsInitialized=FALSE;
|
|
m_hProcessHelperLib=NULL;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Static Functions
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD COXProcess::GetCurrentProcessID()
|
|
{
|
|
return ::GetCurrentProcessId();
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetCurrentProcessEnvironment(CStringArray& arrEnvironmentString)
|
|
{
|
|
|
|
arrEnvironmentString.RemoveAll();
|
|
|
|
// Get a pointer to the environment block.
|
|
LPVOID lpvEnv=::GetEnvironmentStrings();
|
|
if(lpvEnv==NULL)
|
|
{
|
|
TRACE(_T("COXProcess::GetCurrentProcessEnvironment: GetEnvironmentStrings() returned NULL pointer to environment block\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Variable strings are separated by NULL byte, and the block is
|
|
// terminated by a NULL byte.
|
|
CString sEnvironmentString;
|
|
LPTSTR lpszVariable=(LPTSTR)lpvEnv;
|
|
for(;;)
|
|
{
|
|
sEnvironmentString=lpszVariable;
|
|
if(sEnvironmentString.IsEmpty())
|
|
break;
|
|
else
|
|
{
|
|
arrEnvironmentString.Add(sEnvironmentString);
|
|
lpszVariable+=(sEnvironmentString.GetLength()+1)*sizeof(TCHAR);
|
|
}
|
|
}
|
|
|
|
::FreeEnvironmentStrings((LPTSTR)lpvEnv);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXProcess::IsDebuggerPresent()
|
|
{
|
|
// get handle of the KERNEL.LIB
|
|
BOOL bAlreadyLoaded=TRUE;
|
|
HINSTANCE hKernel=::GetModuleHandle(_T("kernel32.dll"));
|
|
if(hKernel==NULL)
|
|
{
|
|
// load the DLL
|
|
hKernel=::LoadLibrary(_T("kernel32.dll"));
|
|
bAlreadyLoaded=FALSE;
|
|
}
|
|
|
|
BOOL bResult=FALSE;
|
|
|
|
if(hKernel)
|
|
{
|
|
/*
|
|
You must get this function explicitly because earlier versions
|
|
don't implement this function.
|
|
*/
|
|
ISDEBUGGERPRESENT pIsDebuggerPresent=
|
|
(ISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent");
|
|
|
|
if(pIsDebuggerPresent)
|
|
bResult=(*pIsDebuggerPresent)();
|
|
|
|
if(!bAlreadyLoaded)
|
|
::FreeLibrary(hKernel);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL COXProcess::IsValidProcessID(DWORD dwProcessID)
|
|
{
|
|
if(GetCurrentProcessID()==dwProcessID || dwProcessID==0 || dwProcessID==2)
|
|
return TRUE;
|
|
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=
|
|
::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,dwProcessID);
|
|
if(hProcess!=NULL)
|
|
{
|
|
::CloseHandle(hProcess);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXProcess::GetProcessImageFileName(DWORD dwProcessID, CString& sFileName)
|
|
{
|
|
COXProcess process(dwProcessID);
|
|
if(!process.IsValid())
|
|
return FALSE;
|
|
|
|
return process.GetImageFileName(sFileName);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Protected Functions
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL COXProcess::InitializeProcessFunctions() const
|
|
{
|
|
if(m_bProcessFunctionsInitialized)
|
|
return TRUE;
|
|
|
|
if(m_bIsRunningNT)
|
|
{
|
|
m_hProcessHelperLib=::LoadLibrary(_T("PSAPI.DLL"));
|
|
if(m_hProcessHelperLib==NULL)
|
|
return FALSE;
|
|
|
|
pfnEnumProcesses=
|
|
(PFNENUMPROCESSES)::GetProcAddress(m_hProcessHelperLib,"EnumProcesses");
|
|
pfnEnumProcessModules=
|
|
(PFNENUMPROCESSMODULES)::GetProcAddress(m_hProcessHelperLib,"EnumProcessModules");
|
|
pfnGetModuleFileNameExA=
|
|
(PFNGETMODULEFILENAMEEXA)::GetProcAddress(m_hProcessHelperLib,"GetModuleFileNameExA");
|
|
|
|
if(!pfnEnumProcesses || !pfnEnumProcessModules || !pfnGetModuleFileNameExA)
|
|
{
|
|
::FreeLibrary(m_hProcessHelperLib);
|
|
m_hProcessHelperLib=NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL bWasLoaded=TRUE;
|
|
HINSTANCE m_hProcessHelperLib=::GetModuleHandle(_T("KERNEL32.DLL"));
|
|
if(m_hProcessHelperLib==NULL)
|
|
{
|
|
HINSTANCE m_hProcessHelperLib=::LoadLibrary(_T("KERNEL32.DLL"));
|
|
if(m_hProcessHelperLib==NULL)
|
|
return FALSE;
|
|
bWasLoaded=FALSE;
|
|
}
|
|
|
|
pfnCreateToolhelp32Snapshot=
|
|
(PFNCREATETOOLHELP32SNAPSHOT)
|
|
::GetProcAddress(m_hProcessHelperLib,"CreateToolhelp32Snapshot");
|
|
pfnProcess32First=
|
|
(PFNPROCESS32FIRST)::GetProcAddress(m_hProcessHelperLib,"Process32First");
|
|
pfnProcess32Next=
|
|
(PFNPROCESS32NEXT)::GetProcAddress(m_hProcessHelperLib,"Process32Next");
|
|
pfnModule32First=
|
|
(PFNMODULE32FIRST)::GetProcAddress(m_hProcessHelperLib,"Module32First");
|
|
pfnModule32Next=
|
|
(PFNMODULE32NEXT)::GetProcAddress(m_hProcessHelperLib,"Module32Next");
|
|
|
|
if(!pfnCreateToolhelp32Snapshot || !pfnProcess32First ||
|
|
!pfnProcess32Next || !pfnModule32First || !pfnModule32Next)
|
|
{
|
|
if(!bWasLoaded)
|
|
::FreeLibrary(m_hProcessHelperLib);
|
|
m_hProcessHelperLib=NULL;
|
|
return (FALSE);
|
|
}
|
|
|
|
if(bWasLoaded)
|
|
m_hProcessHelperLib=NULL;
|
|
}
|
|
|
|
m_bProcessFunctionsInitialized=TRUE;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Public Functions
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL COXProcess::GetImageFileName(CString& sFileName) const
|
|
{
|
|
if(GetCurrentProcessID()==m_dwProcessID)
|
|
{
|
|
LPTSTR pszBuffer=sFileName.GetBuffer(MAX_PATH);
|
|
ASSERT(pszBuffer!=NULL);
|
|
BOOL bResult=(::GetModuleFileName(NULL,pszBuffer,MAX_PATH)>0);
|
|
sFileName.ReleaseBuffer();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
VERIFY(InitializeProcessFunctions());
|
|
|
|
if(m_bIsRunningNT)
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(
|
|
PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
{
|
|
if(m_dwProcessID==0)
|
|
{
|
|
VERIFY(sFileName.LoadString(IDS_OX_PROCESSIDLE));//"System Idle Process"
|
|
return TRUE;
|
|
}
|
|
if(m_dwProcessID==2 || m_dwProcessID==8)
|
|
{
|
|
VERIFY(sFileName.LoadString(IDS_OX_PROCESSSYSTEM));//"System"
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HMODULE moduleArray[1024];
|
|
DWORD cbNeeded;
|
|
// EnumProcessModules returns an array of HMODULEs for the process
|
|
if(!pfnEnumProcessModules(hProcess,moduleArray,sizeof(moduleArray),&cbNeeded))
|
|
{
|
|
::CloseHandle(hProcess);
|
|
if(m_dwProcessID==0)
|
|
{
|
|
VERIFY(sFileName.LoadString(IDS_OX_PROCESSIDLE));//"System Idle Process"
|
|
return TRUE;
|
|
}
|
|
if(m_dwProcessID==2 || m_dwProcessID==8)
|
|
{
|
|
VERIFY(sFileName.LoadString(IDS_OX_PROCESSSYSTEM));//"System"
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// First module is the EXE
|
|
char szModuleName[MAX_PATH];
|
|
// GetModuleFileNameEx is like GetModuleFileName, but works
|
|
// in other process address spaces
|
|
pfnGetModuleFileNameExA(
|
|
hProcess,moduleArray[0],szModuleName,sizeof(szModuleName));
|
|
sFileName=szModuleName;
|
|
|
|
::CloseHandle(hProcess); // We're done with this process handle
|
|
}
|
|
else
|
|
{
|
|
// Create a ToolHelp32 snapshot containing the process list
|
|
//
|
|
HANDLE hSnapshotProcess;
|
|
hSnapshotProcess=pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
if(hSnapshotProcess==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Iterate through each of the processes in the snapshot
|
|
PROCESSENTRY32 procEntry={ sizeof(PROCESSENTRY32) };
|
|
BOOL bProcessContinue;
|
|
BOOL bSuccess=FALSE;
|
|
for(bProcessContinue=pfnProcess32First(hSnapshotProcess,&procEntry);
|
|
bProcessContinue;
|
|
bProcessContinue=pfnProcess32Next(hSnapshotProcess,&procEntry))
|
|
{
|
|
if(m_dwProcessID==procEntry.th32ProcessID)
|
|
{
|
|
sFileName=procEntry.szExeFile;
|
|
bSuccess=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
::CloseHandle(hSnapshotProcess); // Done with process list snapshot
|
|
|
|
if(!bSuccess)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetPriorityClass(DWORD& dwPriorityClass) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
dwPriorityClass=::GetPriorityClass(hProcess);
|
|
if(dwPriorityClass==0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetVersion(DWORD& dwVersion) const
|
|
{
|
|
dwVersion=::GetProcessVersion(m_dwProcessID);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Windows NT functions
|
|
//
|
|
|
|
BOOL COXProcess::IsPriorityBoostDisabled(BOOL& bDisabled) const
|
|
{
|
|
#if (_WIN32_WINNT >= 0x0400)
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
return ::GetProcessPriorityBoost(hProcess,&bDisabled);
|
|
#else
|
|
UNREFERENCED_PARAMETER(bDisabled);
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetMinMaxWorkingSetSize(DWORD& dwMinWorkingSetSize,
|
|
DWORD& dwMaxWorkingSetSize) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
return ::GetProcessWorkingSetSize(hProcess,
|
|
&dwMinWorkingSetSize,&dwMaxWorkingSetSize);
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetCreationTime(FILETIME& fileTime) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
FILETIME exitTime, kernelTime, userTime;
|
|
return ::GetProcessTimes(hProcess,&fileTime,&exitTime,&kernelTime,&userTime);
|
|
}
|
|
|
|
BOOL COXProcess::GetCreationTime(CTime& time) const
|
|
{
|
|
FILETIME creationTime;
|
|
if(!GetCreationTime(creationTime))
|
|
return FALSE;
|
|
|
|
CTime timeCopy(creationTime);
|
|
time=timeCopy;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXProcess::GetCreationTime(COleDateTime& oleTime) const
|
|
{
|
|
FILETIME creationTime;
|
|
if(!GetCreationTime(creationTime))
|
|
return FALSE;
|
|
|
|
COleDateTime timeCopy(creationTime);
|
|
oleTime=timeCopy;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetExitTime(FILETIME& fileTime) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
FILETIME creationTime, kernelTime, userTime;
|
|
return ::GetProcessTimes(hProcess,&creationTime,&fileTime,&kernelTime,&userTime);
|
|
}
|
|
|
|
BOOL COXProcess::GetExitTime(CTime& time) const
|
|
{
|
|
FILETIME creationTime;
|
|
if(!GetExitTime(creationTime))
|
|
return FALSE;
|
|
|
|
CTime timeCopy(creationTime);
|
|
time=timeCopy;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXProcess::GetExitTime(COleDateTime& oleTime) const
|
|
{
|
|
FILETIME creationTime;
|
|
if(!GetExitTime(creationTime))
|
|
return FALSE;
|
|
|
|
COleDateTime timeCopy(creationTime);
|
|
oleTime=timeCopy;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetKernelTime(DWORDLONG& timeSpent) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
FILETIME creationTime, exitTime, kernelTime, userTime;
|
|
if(::GetProcessTimes(hProcess,&creationTime,&exitTime,&kernelTime,&userTime))
|
|
{
|
|
timeSpent=(((DWORDLONG)kernelTime.dwHighDateTime)<<32)+
|
|
((DWORDLONG)kernelTime.dwLowDateTime);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL COXProcess::GetUserTime(DWORDLONG& timeSpent) const
|
|
{
|
|
// Using the process ID, open up a handle to the process
|
|
HANDLE hProcess=::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
|
|
FALSE,m_dwProcessID);
|
|
if(hProcess==NULL)
|
|
return FALSE;
|
|
|
|
FILETIME creationTime, exitTime, kernelTime, userTime;
|
|
if(::GetProcessTimes(hProcess,&creationTime,&exitTime,&kernelTime,&userTime))
|
|
{
|
|
timeSpent=(((DWORDLONG)userTime.dwHighDateTime)<<32)+
|
|
((DWORDLONG)userTime.dwLowDateTime);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOL COXProcessIterator::MakeSnapshot()
|
|
{
|
|
Cleanup();
|
|
|
|
if(!InitializeProcessFunctions())
|
|
return FALSE;
|
|
|
|
if(m_bIsRunningNT)
|
|
{
|
|
// an array for 1024 processes should be enough :-)
|
|
DWORD pidArray[1024];
|
|
DWORD cbNeeded;
|
|
// EnumProcesses returns an array of process IDs
|
|
if(!pfnEnumProcesses(pidArray,sizeof(pidArray),&cbNeeded))
|
|
return FALSE;
|
|
|
|
// Iterate through each process in the array
|
|
for(int nProcess=0; nProcess<(int)(cbNeeded/sizeof(DWORD)); nProcess++)
|
|
m_arrProcesses.Add(pidArray[nProcess]);
|
|
}
|
|
else
|
|
{
|
|
// Create a ToolHelp32 snapshot containing the process list
|
|
//
|
|
HANDLE hSnapshotProcess;
|
|
hSnapshotProcess=pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
if(hSnapshotProcess==NULL)
|
|
return FALSE;
|
|
|
|
// Iterate through each of the processes in the snapshot
|
|
PROCESSENTRY32 procEntry={ sizeof(PROCESSENTRY32) };
|
|
BOOL bProcessContinue;
|
|
for(bProcessContinue=pfnProcess32First(hSnapshotProcess,&procEntry);
|
|
bProcessContinue;
|
|
bProcessContinue=pfnProcess32Next(hSnapshotProcess,&procEntry))
|
|
{
|
|
m_arrProcesses.Add(procEntry.th32ProcessID);
|
|
}
|
|
|
|
::CloseHandle(hSnapshotProcess); // Done with process list snapshot
|
|
}
|
|
|
|
m_bCanIterate=TRUE;
|
|
|
|
ASSERT(GetProcessCount()>0);
|
|
m_nCurrentIndex=0;
|
|
m_dwProcessID=m_arrProcesses[0];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcessIterator::Next(UINT nOffset)
|
|
{
|
|
if(!CanIterate())
|
|
return FALSE;
|
|
|
|
if(nOffset==0)
|
|
return TRUE;
|
|
|
|
if(m_nCurrentIndex+(int)nOffset>=GetProcessCount())
|
|
return FALSE;
|
|
|
|
m_nCurrentIndex+=nOffset;
|
|
m_dwProcessID=m_arrProcesses[m_nCurrentIndex];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXProcessIterator::Prev(UINT nOffset)
|
|
{
|
|
if(!CanIterate())
|
|
return FALSE;
|
|
|
|
if(nOffset==0)
|
|
return TRUE;
|
|
|
|
if(m_nCurrentIndex-nOffset<0)
|
|
return FALSE;
|
|
|
|
m_nCurrentIndex-=nOffset;
|
|
m_dwProcessID=m_arrProcesses[m_nCurrentIndex];
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|