Environment: The source is UNICODE compliant and was tested with both Visual C++ 5 SP3 and Visual C++ 6 SP2.
The demo is a Visual C++ 6 project.
In a few of my projects I have to deal with processes. To protect me from implementing all of the hard bits again and again, I
developed a set of classes. These are mainly a process manager class and a process enumerator class.
The Process Enumerator Class CProcessList
This class makes it easy to take a snapshot of all currently running processes and iterate them. There is no need for you to
determine the type of system your application is running on. The enumerator selects the best enumeration method available.
Because of this fact, you cannot simply instantiate an object of the process enumerator. You have to "Create()" one instead:
CProcessList * pProcessList = CProcessList::Create();
Now that you have a valid object, you can take a snapshot of the process list:
pProcessList->SnapShot();
After having done this, you can iterate the processes:
CProcess * pProcess; while((pProcess = pProcessList->GetNextProcess()) != 0) { TRACE("process' filename: "%s" PID: %lun", LPCTSTR(pProcess->GetFilename()), pProcess->GetPID()); }
You can reuse the enumerator by taking another snapshot.
If you don’t need the process enumerator any longer, you have to delete it:
delete pProcessList;
A detailed class documentation is inside the source archives.
The Process Manager Class CProcessMgr
CProcessMgr has the following member functions (description follows below):
// split a command string
BOOL ParseCommand(
const CString & CmdLine,
CString & Directory,
CString & Cmd,
CString & Args
); // execute a command
DWORD Execute(
const CString & strCmd,
const CString & strArgs,
const CString & strDir = "",
BOOL bWait = FALSE
);
DWORD Execute(
const CString & strCmdLine,
BOOL bWait = FALSE
); // wait for another process
DWORD Wait( DWORD PID ) const; // check wether a program is running
DWORD IsProgramRunning(const CString & FileName) const;
DWORD IsProgramRunning(DWORD PID) const; // switch to another running application
BOOL SwitchProcessIntoForeground(DWORD PID) const;
BOOL SwitchProcessIntoForeground( const CString & FileName ) const; // get informations about a shell-link (known as "shortcut")
BOOL GetLinkInfo(const CString & LinkName, CString & Path) const; // handle an error
virtual void OnExecError( int nErrorCode, const CString & strCommand );
One of the main goals of this class is, that it understands complex command strings. This is very useful since one can store
such a command string in the registry (or in a file or database or whatever) at once. The syntax of such a command string is
as follows (BNF-notation):
CmdLine : command | command arguments | 'cd' directory ';' command | 'cd' directory ';' command arguments command : string arguments: string | arguments string directory: string /* shall consist of a full path ! */ string : '[^ t]+' /* string without blanks/tabs */ | '"' '[^"]*' '"' /* quoted string can contain any character except " itself */
OK – not all of you are familiar with BNF, so let me give some examples:
cmd cmd /c dir cd C:windows ; cmd /c dir cd "C:Program FilesInformix" ; cmd /c dir cd "C:Program FilesPictures" ; "\picardSoftwareGraphic UtilitiesPSPpsp.exe" Title.jpg
All of these are valid command strings. Note that these samples are not in C/C++ notation !
The Parse() method splits such a command string into its components "directory", "command" and "arguments". Any special
tokens are stripped off, so if you parse the last example, it would give you C:Program FilesPictures as the directory,
\picardSoftwareGraphic UtilitiesPSPpsp.exe as the command and Title.jpg as the argument to the command. You can
pass a complete command string to the Execute() method. If the command part of the string is not an executable file, then
Execute() searches for the associated executable. The return value of Execute() depends on the <bWait> parameter. If
<bWait> is TRUE, then it returns the exit code of the execution, otherwise a process-ID (PID) will return.
With the Wait() method you can explicitly wait for the end of a running process; just give Wait() the process id of that
process.
To check whether a special program is currently running, you can use the IsProgramRunning() method. If you pass the name
of an executable file, this method checks the process table and gives you the PID of the process or 0 (zero) if that program is
currently not running. If you’re developing an application, that does not provide a window, but this program must run only
once per machine, you cannot use FindWindow() to determine, whether the application is already running. The use of
mutexes or similar resources might be an inacceptable overhead too. In such a case, one can simply use the following code:
TCHAR szName[1024]; GetModuleFileName(0, szName, 1023); if( CProcessMgr().IsProgramRunning(szName) != DWORD(getpid()) ) { // the application is already running on this machine }
The code above works correctly, because a newly created process appears after a previously created process in the
process table, so the method finds the other application first.
At last: the SwitchProcessIntoForeground() method switches a process into the foreground; i.e. makes that process the
active process. If the main window of that process is minimized, then it will be restored to its previous state. If
IsProgramRunning() indicates that a certain Process is running and SwitchProcessIntoForeground() says "I cannot switch to
that process", then the process is possibly a DDE/OLE server that has currently hidden windows only or it is a process
without a window (an NT service for instance).
There is a detailed class documentation in either the source- and the sample archive (in the htmldocs subdirectory; start with
index.html).
Download
The process manager/enumerator package consists of four files
ProcessMgr.[h|cpp]
Processes.[h|cpp]
Note that ProcessMgr.* depends on Processes.* ; but not vice versa (thus you can use the enumerator "stand alone").
Date Last Updated: April 18, 1999