Introduction
Did you ever wonder how the Windows Taskmanager
was implemented? Well, here are 3 classes to start with.
The classes implement the enumeration of all running processes,
all loaded modules (executables and dynamically loaded libraries)
and also all threads.
The classes are derived from the MFC class
CArray
or the STL template class stl::vector
.
The STL implementation does not need any MFC components
but supports the most commonly used CArray
functions (GetSize(), RemoveAll(), operator[], GetAt()
),
so it can be used wherever a CArray
is used. You can enable the STL
implementation by defining the symbol USE_STL
in the
preprocessor settings.
The header file will automatically instruct the
linker to use the appropriate lib files. All classes make
use of the
Toolhelper Library and the
Process Status Helper in psapi.lib. You can find the
whole documentation on MSDN.
Please note: you must have the Platform SDK installed
in order to use PSAPI. More information on using Toolhelp and
PSAPI can be found
here
The classes are far from being complete, there
is lot of space for improvements. A commercial application would need
to delve a bit deeper into the security related aspects of process
handling but this is out of the scope of this article.
Enumerating Processes
With the CProcessList
class you get
the complete set of running processes. The class provides you
with all necessary information on all processes.
CProcessList pl;
for(int i = 0; i < pl.GetSize(); ++i)
TRACE("Process %s has %i threads\n", pl[i].szModule, pl[i].pe32.cntThreads);
CProcessList
derives from
CArray<PROCESS_INFORMATION_EX, PROCESS_INFORMATION_EX>
(
or stl::vector<PROCESS_INFORMATION_EX>)
.
PROCESS_INFORMATION_EX
is roughly defined as
typedef struct _PROCESS_INFORMATION_EX
{
... some ctors...
PROCESSENTRY32 pe32;
PSID pSid;
TCHAR szModule[MAX_MODULE_NAME32 + 1];
} PROCESS_INFORMATION_EX;
The biggest part of information comes from
the PROCESSENTRY32
structure defined in tlhelp32.h. Also
included are the SID of the user owning the process and the
real name of the module which contains the code for this process.
The pSid
member can easily be used
to retrieve the full name and domain of the user:
SID_NAME_USE use;
DWORD dwName = 256;
DWORD dwDomain = 256;
TCHAR uname[256];
TCHAR udomain[256];
if(LookupAccountSid(NULL, pl[i].pSid, &uname[0], &dwName, &udomain[0], &dwDomain, &use))
{
TRACE("%s\\%s", &udomain[0], &uname[0]);
}
Note: For a commercial application you will need a bit
more code, but for home use and demonstration this is sufficient.
The destructor of CProcessList
takes care of correctly freeing all allocated memory.
Just be aware that the SID cant be copied like a structure.
See the w32process.h file for more information.
To exclude processes to which you
don't have access because you don't have sufficient privileges
(system processes) you can use the optional boolean parameter
in the constructor of the class.
Enumerating Modules
Since most processes make use of many different
modules there is also a class to enumerate these. CModuleList
is
also derived from one of the collection template classes CArray
or vector containing the MODULEENTRY32
structure defined in tlhelp32.h. Its basically just a wrapper around the structure.
When you pass a process ID to the constructor it will
enumerate all loaded(!) modules used by the given process.
The default constructor enumerates the modules of the current process.
Please be aware that the module list may change during
the lifetime of the process because the process may
dynamically load and unload DLL's. If you want accurate
results you must create a instance of CModuleList
and immediately use it.
Enumerating Threads
The CThreadList
class is the last of
the classes in w32process.h and is, like the others, derived
from the collection templates CArray
or vector
. It implements
the THREAD_INFORMATION_EX
structure which is defined as:
typedef struct _THREAD_INFORMATION_EX
{
... some ctors...
THREADENTRY32 te32;
CONTEXT ctx;
} THREAD_INFORMATION_EX;
The constructor takes 2 arguments: the process ID
and a optional boolean. If the process ID is 0 it enumerates
the threads of the current process. If the boolean parameter
is true, the ctx
member will be filled in with
the threads context information. This is rather specific
information so it is excluded by default.
Important to note is that if you need context
information, the class must temporarily suspend each thread
to obtain the context information.
Sample Application
The sample application represents a simple process list,
showing basic process information. When you select a process,
you can view the processes modules and threads.
Compatibility
All classes are fully MBCS/Unicode enabled and can
be used either MFC CArray
derived or STL vector derived. Written,
compiled and tested under VC7 but should also compile with VC6 and below.
The sample application comes with STL, MFC and UNICODE configurations.