Contents
Foreword
This article continues the series about the Professional System Library project as it develops further on. This time, we go over the features of the library that allow us to access various information about the current process in an easy way via the namespace System->Process
of the ProSysLib component.
For those of you who are reading about the ProSysLib project for the first time, it is much recommended to get familiar with the project and its objectives from the ProSysLib Introduction article. The present article does not reiterate the purposes pursued by the ProSysLib project.
Articles about the ProSysLib project are published here immediately as new features get implemented, for it is a rather young project. This article refers to version 0.5 of the library, where most changes were to provide information about the current process.
Introduction
Any client application needs to deal with information about its own processes to adjust and control its own state, to be aware of many aspects and statuses of the current process. Within ProSysLib, all information relevant to the current process is available under the namespace System->Process
. In this article, we will go through most of the process-related properties available from the latest version of the library just to show how easily all such information can be accessed from within ProSysLib.
The auuthor apologizes that the only COM-client application shown in this article is written in C# 2005, for it is indeed unfair towards developers in other environments like VC++, VB6, Delphi, Java, BC++, Office, FoxPro, etc., who can use the library in just the same simple way, but their number is simply overwhelming, and I am faced with the choice of picking one type of COM client, simply limited by time, like all of us. I’m making a valid effort to include more types of environment examples in the future versions of the ProSysLib SDK. I could, of course, just use VB6 to show all that the library can do, but then it is getting less popular, with problems regarding conversion into the newer VS, and can't use 64-bit examples, which I like very much to point out every time this project is 100% 64-bit ready. So yes, these are tough choices, that's why I am sticking with C# 2005 for now, given the time that I have.
The example considered here, called ProcessInfo, allows viewing most of the current process properties, and it doesn’t allow changing the properties at all, which ProSysLib allows, but implementing it in the example would pointlessly complicate it, while I’m only trying to provide an overview of what’s available, in general. I do, however, mention read/write capabilities in the quick lists of object properties below, but I recommend using the documentation available with the ProSysLib SDK.
The example itself, in essence, is very much a dummy project, and as you open it in visual studio you will find that the code within the project is not just simple, it’s dull simple. All it does - populates the list controls with information provided by ProSysLib, and absolutely nothing else. However, this is the point, to show the simplicity, so developers in other platforms that I mentioned before can see how to use the same for their own projects, plain and simple.
As usual, the source code for the binary example here as well as other examples and the source code for the ProSysLib component itself are installed with the ProSysLib SDK.
All efforts about the project development are organized on the project’s website.
Example: Process Information
Here, we consider a very simple application that displays various information about the current process. Although it is implemented in C#, it could have been any other type of COM client, like VB.NET, VB6, C++, Delphi, FoxPro, Office, etc., and their implementation would have been pretty much identical, just reading values from the ProSysLib library and displaying them in the UI. See the source code of the example in the ProSysLib SDK.
The application is split into eight tabs, that way grouping information in a logical way. The chapters below provide a screenshot for each such tab, explaining the nature of the information displayed with a short description.
General Information
General process information is just a list of many process properties that we couldn't group in any other way. Here we have static properties, i.e., the ones that never change in the process while it is running, and dynamic properties that either change on their own or can be changed by the application logic.
Static Properties
- Application Name
- Application Path
- Application Directory
- Process Created
- Process ID
- Process is 64-bit
- File Version
- Product Version
All these properties are quite self-describing. I will only comment on the properties File Version and Product Version. The namespace System->Process
contains the property Version
of the type PSLModuleVersion
that can extract the version information from the Version resource of the current process. This is, in fact, just the first implementation of an interface that can extract information from the Version resource and present it in a nice form, and for this reason, it is simplified. For the current version of ProSysLib, I only implemented the extraction of such information as the actual version (FileVersion + ProductVersion), because the rest of the information in a Version resource is localizable, and I didn't want to complicate things there just yet. However, PSLModuleVersion
is a universal interface, and can be used to extract version information for any module. The namespace System->Software
has the method GetModuleVersion
that creates a version object associated with any module in the system.
Dynamic Properties
- Current Directory (read/write), API
GetCurrentDirectory
/SetCurrentDirectory
- Affinity Mask (read/write), API
GetProcessAffinityMask
/SetProcessAffinityMask
- Priority (read/write), API
GetPriorityClass
/SetPriorityClass
- Handle Count (read-only), API
GetProcessHandleCount
/NtQueryInformationProcess
- GDI Object Count (read-only), API
GetGuiResources
- USER Object Count (read-only), API
GetGuiResources
- Is Debugged (read-only), API
CheckRemoteDebuggerPresent
/NtQueryInformationProcess
/IsDebuggerPresent
- Shutdown Level (read/write), API
GetProcessShutdownParameters
/SetProcessShutdownParameters
- Shutdown Flags (read/write), API
GetProcessShutdownParameters
/SetProcessShutdownParameters
A basic API reference is provided for each property here. For more details, you can check out the source code of the ProSysLib component, in the class CPSLCurrentProcess
.
Resources: Memory + IO Counters
Information about memory usage for the current process is available via the property System->Process->Memory
of the type PSLProcessMemory
. Most of the information is extracted from the system via the API GetProcessMemoryInfo
, and the properties have the same names as in MSDN for consistency. All the properties of PSLProcessMemory
are read-only.
Information about IO Counters is available via the property System->Process->IO
of type PSLProcessIO
. All current properties are extracted from the system via the API GetProcessIoCounters
, and have the same names as described in MSDN for consistency. All properties of PSLProcessIO
are read-only.
Environment Variables
Proper usage of environment variables is quite important for many applications. For instance, we can configure an application using a BAT file, specifying all the parameters via the command SET
that registers the environment variables for the process. And, if we create a command-line utility, this can be a far better solution than just using the command-line parameters that can be way more awkward, and sometimes simply not usable. Sometimes, the parent process needs to pass important information into the child process, and this is where environment variables come into use as well. I know from my experience that in such environments as VC++ and VB6, for example, there is no interface for properly accessing environment variables (I do not know about it in .NET).
Access to the current process' environment variables is done via the property-collection System->Process->EnvVars
of type PSLEnvironmentVars
. This collection allows any kind of manipulation on the environment variables in the simplest possible way: Add, Set, Delete, or Find a variable.
Command-Line Parameters
Command-line parameters is an essential information for many programs, and it is quite important how easy it is to access and process them. In environments like C++ or .NET, what we get is a list of commands that have undergone only the most basic parsing, separating one command from another. In other environments, however, it can be more complicated than that.
While providing a unified access to command-line parameters from any environment, ProSysLib takes it one step further, parsing each command to be split into Parameter Name + Parameter Value. You can see on the screenshot above how commands can be parsed. All command-line parameters are available via the property System->Process->Commands
of type PSLCmdParams
, which is a collection of pre-parsed commands.
In order to make it possible to parse commands into pairs of {Name, Value}
, the command-line syntax must satisfy the existing unwritten rules about the command-line format, and those rules are as follows...
A command can only start with the symbol '-' or '/', followed by the command name without spaces. If the command has a parameter/value, such is separated from the parameter name using either ':' or '='. The command parameter/value is either single non-spaced or embraced by double quotes. Also, the syntax allows parsing values without any commands, i.e., a command that starts with anything other than symbols '-' and '/' is considered to be a simple value. See on the screenshot how a few parameters passed into the application get parsed: we can see the original command (property Command
), and what ProSysLib was able to make out of it as a pair of properties Name
+ Value
.
Windows
The property System->Process->Windows
of type PSLWindows
provides access to all windows created within the current process. Each element of the collection is of type PSLWindow
, and is a window representation within the ProSysLib component. Using PSLWindow
, we can do anything with the window directly, and while accessed via the collection of all windows in the process, we are free to do whatever we want with all the windows created in the process.
The property System->Process->Windows->Filter
of type PSLWindowsFilter
allows us to setup a flexible filter that will be used when enumerating all the windows. By default, the filter is unset, and allows enumeration of all windows in the process, but it can be easily changed as shown in the demo application to pass certain requirements for each window being enumerated within the collection. Please note that the demo application does not show all the filters that can be used (see the interface PSLWindowsFilter
in the SDK help, for details).
ProSysLib also allows to process any window in the system as its own. The method System->Software->WindowFromHandle
allows to create a new window object associated with any window handle. This can be quite useful if we need to override the window behavior in an environment that doesn’t allow direct interaction with the windows. In the current implementation, PSLWindow
already implements all the basic methods necessary to control the window, such as SendMsg
, PostMsg
, and often hidden properties of the Window ID, Parent Window, Class Name, Thread ID, Process ID, control over Styles, and so on.
Threads
The property System->Process->Threads
of type PSLThreads
gives access to all the threads created within the current process. Each element in the collection is of type PSLThread
, which provides all the necessary information about the thread, also allowing you change thread priority, affinity, or boost value, simply by setting the corresponding property value.
Using direct access to the threads allows engineering better load balance and synchronization in the application. For instance, a well planned application would make use of the process affinity mask (property System->Process->AffinityMask
), and position all threads to run on the subset of cores in such a way that best serves the needs of the process to optimize the resource consumption.
The collection type PSLThread
implements all the basic methods for monitoring and controlling any thread within the process, such as PostMsg
, Wait
, Suspend
, Resume
, and Terminate
that execute for the thread object the corresponding API functions of PostThreadMessage
, WaitForSingleObject
, SuspendThread
, ResumeThread
, and TerminateThread
. For more details about the interface methods and properties, see their description in the ProSysLib SDK Help.
Modules
The property System->Process->Modules
of type PSLModules
is a collection of all the modules loaded by the current process. This allows monitoring what the application is loading, so we know for sure when planning the software distribution, if necessary. All properties of this collection are read-only.
Privileges
Even though located under the namespace System->Security
, the property Privileges
provides information relevant for the current process settings, so I also included it into the demo, because privilege as such is always a process privilege, first of all. The property is a collection of privileges that allow you to easily get or set information about privileges in the current process. You can find out a little more, and a code example about using privileges, in the ProSysLib Introduction article.
Background
All the background for the ProSysLib project itself is within the C++ source code that the SDK offers. As for this article, getting into version 0.5 of the component and implementing all the properties of the current process implied dealing a lot with all kinds of enumeration APIs first of all, among which were the following key functions:
EnumWindows
, EnumChildWindows
, and EnumThreadWindows
to implement the collection of windows (class CPSLWindows
); CreateToolhelp32Snapshot
, Thread32First
, and Thread32Next
to enumerate all the threads in the process (class CPSLThreads
); EnumProcessModules
to enumerate modules used by the current process (class CPSLModules
); GetCommandLine
, plus lots of my own parsing to properly organize the collection of command-line parameters (class CPSLCmdParams
); GetEnvironmentStrings
and SetEnvironmentVariable
, plus my own parsing to organize the collection of environment variables (class CPSLEnvironmentVars
);
You can see all for yourself in the ProSysLib source code, details for which are outside the topic of this article.
Summary
Not all information about the current process that’s available via the ProSysLib library is viewed by the demo application here. For further details, I recommend using the help system that’s installed with the ProSysLib SDK and available online at www.prosyslib.org. It is not claimed that considerations made in this article and the current version of ProSysLib are in any way complete. There is always additional information that can be found within the current process. And, while future versions of ProSysLib may include some of those advanced process properties, the library focuses on what’s most interesting to developers in general, and not on providing access to rarely used information.
History
- August 12, 2008; Initial draft of the article
- August 13, 2008; Second revision included more details throughout, plus the Background chapter
- August 30, 2008; Updated links to the original ProSysLib article that got published since the last time and moved to a different category
- September 6, 2008; Just notifying my readers that the library is evolving very quickly, and today I released ProSysLib v0.6 that's available to download from www.prosyslib.org
- October 12, 2010: Updated source code
- November 20, 2010: Updated download files