Professional System Library: Introduction

Foreword

Most software developers share the same pattern in their professional career of having to deal with projects of a similar nature, although a few developers manage to jump from one project to a completely different one.

Personally for me, I found one particular area that has always taken a great deal of my time from one project to another, and that's coding around retrieving and changing information about the system/OS, about the current process, threads, various hardware and software configuration of the system, security context, and so on. I do hope this all sounds very familiar to many developers.

Not only does one have to spend some time trying to figure out how to access the same information required, depending on which development platform is being used, but also this knowledge is very hard to interpolate from one platform to another. For example, VC++, VB6, C#, Delphi, Office—all so different in every way, your code from one may seem totally unusable in the other.

Then, the complexity kicks in. If we can pull just about any trick in C++ in quite a natural way, doing the same things in more restrictive environments either impossible or breaks the seemingly integrity of the system, like using unmanaged code in .NET or lots of external procedure imports for VB6, and so on.

Out of systematic practice in various development environments came the idea to summarise all my knowledge in this area and offer software developers a simple and unified way in which all such information can be accessed easily, in the same way in any development environment, and with the very minimum of effort.

This whole article is an introduction to the initiative of writing a library that would allow easy access to most frequently used information in the system, client's process, and environment.

It is a very recently started project (July 2008). All additional information about this project as well as the development efforts for it I am trying to organize on the www.prosyslib.org website.

Introduction

There are four ways in which an application can retrieve information from the system are as follows:

  1. Standard Windows API
  2. Undocumented Windows API
  3. Direct access to the system: Windows Registry + File System
  4. WMI (Windows Management Interface)

When it comes to choosing which method is best to use our choice depends mostly on the following criteria (given in the order in which your average developer looks at these things):

  1. Complexity of implementation
  2. Reliability
  3. Speed of execution
  4. Resource consumption

Professional System Library (ProSysLib) is a project that offers unification in accessing information about process/system/environment where the developer would no longer have to make a tough choice looking at these criteria trying to decide which one is most important or which can be sacrificed.

ProSysLib presents all information using the concept of a root namespace, very much similar to that in .NET where System is the root namespace for everything. Much like it, ProSysLib has its own System root namespace that defines the entry point for all the sub-namespaces and functionality of the library.

The picture at the beginning of this article shows the top hierarchy of namespaces below System. These define the basis for further classification of all the information that can be retrieved.

Technology Highlights

ProSysLib DLL is a Unicode COM in-process server that uses a Neutral memory model. It is Thread-Safe, and implements Automation interfaces only. The protocol (type library) declarations of 32-bit and 64-bit versions of the component are identical, thus allowing transparent integration with development tools that can mix 32-bit and 64-bit modes, while using the same type library (signature) of the component. ProSysLib is also immune to the DLL Hell problem (read ProSysLib SDK for details).

Implementation is done entirely in VC++ 2008, using only COM, ATL, STL, and Windows API.

The entire ProSysLib framework is based on Just-On-Time Activation, which means that each and every namespace and object is instantiated and initialized only when used by the client application for the first time; until then, ProSysLib is completely weightless resource-wise.

At the moment of publishing this article, only a few objects and namespaces of the library were introduced. As for the rest of the namespaces, properties and methods, if an application tries to use them, the library will throw the COM exception "NOT IMPLEMENTED" to tell you that you are trying to use something in the library that has been declared but not yet implemented.

Using the Code

Because the library concept is built upon a root namespace, it is the only interface that needs to be created by the client application to have access to everything else, much like System namespace in .NET. In fact, the foo-proof implementation of the library won't let you create any other interface of the library even if you try.

Declaring and instantiating a variable in different development environments can look different from each other, although using it will look pretty much the same. In this article, you simplify all your code examples for C# clients only. Any developer should be able to work it out how this would look in his environment of choice.

// Declare and instantiate ProSysLib root namespace;
PSLSystem sys = new PSLSystem();

Now, by using this variable you can access anything you want underneath the root namespace.

Even though ProSysLib is targeted to implement access to many kinds of information, the project started only recently, and there are not that many features implemented so far. However, I did not want to draw abstractions with a finger in the air; one can figure them out by looking at the ProSysLib Documentation, so all the examples provided here below are real ones; in other words, they are fully functional already.

So, consider a few examples of what you can do with ProSysLib as of today, which is less than one month from the beginning of the project.

Privileges

Many applications need to know about and control the availability to the process privileges. For instance, the Debug privilege can be important when accessing some advanced information in the system that's otherwise unavailable. ProSysLib provides a collection of all available privileges under the namespace of PSLSystem.Security.Privileges. If one needs to enable the Debug privilege in the process, the code would be as shown here:

sys.Security.Privileges.Find("SeDebugPrivilege").Enabled = true;

In other words, you access the collection of privileges, locate the privilege of interest, and enable it. You normally would need to verify that the Find method successfully located the privilege in the list, but because the Debug privilege is always available, you can simplify it here.

Process Enumeration

One of very popular subjects that can be found in articles here is about enumerating all available processes in the system, or finding a particular process, or how to kill a process by name, and the like. ProSysLib enumerates all processes running in the system under the PSLSystem.Software.Processes namespace. This collection is very flexible and allows any kind of operation one needs to do with processes in the system.

Attached to this article is a simple C# application that shows just one example of how ProSysLib can be used. The example enumerates either all processes or the ones that were launched under the current user account. It displays just some of the available information about each process, and allows killing any process with the press of a button.

Here is just a small code snippet from the example where you populate a list view object with information about processes:

// Go through all processes;
foreach (PSLProcess p in sys.Software.Processes)
{
   ListViewItem item = ProcessList.Items.Add(p.ProcessID.ToString());

   string sProcessName = "";
   if (p.ProcessID == 0)    // System Idle Process
      sProcessName = "System Idle Process";
   else
   {
       sProcessName = p.FileName;
       // If OS is 64-bit, and the found process
       // is not 64-bit, we add " *32" like in TaskManager;
       if (sys.Software.OS.Is64Bit && p.Is64Bit == false)
            sProcessName += " *32";
   }

   // Adding some of the available process details...
   //
   // NOTE: p.FilePath for 64-bit processes will always be
   // empty for a 32-bit client running on a 64-bit system,
   // simply because Windows prohibits 32-bit processes to
   // have any access to 64-bit-specific folders;

   item.SubItems.Add(sProcessName);
   item.SubItems.Add(p.FilePath); 
   item.SubItems.Add(p.UserName);
   item.SubItems.Add(p.ThreadCount.ToString());
   item.SubItems.Add(p.HandleCount.ToString());

   // Associate each list item with the process object;
   item.Tag = p;
}

The demo application binary is provided both in 32-bit and 64-bit versions. One of the very interesting things about ProSysLib is that it offers new ways of efficient COM usage, bypassing the COM layer/requirements altogether. Both 32-bit and 64-bit versions will unpack and allow you to run the demo application, using ProSysLib COM library in spite of the fact that you do not register the component on your PC. If somebody assumes that this is COM Isolation for .NET, he would be wrong. This is an implementation of Stealth Deployment for COM, which I invented in my long practice of distributing COM projects. A full description of the idea is given in ProSysLib SDK, in the Deployment chapter.

Professional System Library: Introduction

Access Rights/Mask of a Named Object

Another typical task for many applications is to find out what access rights the current process has to a particular object in the system. Usually, it is either a file or folder that you want to know what you can do with it. I know for a fact that getting this information isn't that straightforward in C++, and can be even more cumbersome in other environments.

The PSLSystem.Security namespace offers the GetNamedObjectAccess function that allows getting Access Mask for any Named Object in the system (file, folder, printer, service, reg-key, network share) in just one line of code:

long AccessMask = 0;
long lErrorCode =
   sys.Security.GetNamedObjectAccess(ntFileOrFolder,
      "my file or folder path", ref AccessMask);

Process Affinity

Just one other small feature that I had a chance to implement in the library by now is to control the Process Affinity. The PSLSystem.Process namespace contains all the properties about the current process (or will, eventually). One of them is AffinityMask, which can be changed very easily. For instance, if you have a Dual-Core system, and would like to execute your process on the second core only, your code for that would be:

// 2 in binary corresponds to the second core;
sys.Process.AffinityMask = 2;

In the same way, for each process in the PSLSystem.Software.Processes collection, you have AffinityMask to get/set Affinity Mask for any other process in the system like the TaskManager can do. I didn't use this in the demo, because I can't show all at once anyway.

WMI

The Windows Management Interface is one of those hereditary technologies that sometimes could have been better dead than alive. In the case of WMI, I are talking about a number of problems caused by though very necessary yet poorly thought out technology. This was one more reason for writing ProSysLib, to be an alternative to getting information from the system in a much easier and faster way.

Following is a list of perhaps the main problems found in WMI:

  1. It is based on obsolete DCOM, which is very slow on its own, not to mention when you try to use it over the network. The Microsoft layer for WMI in .NET 2.0-3.5 looks more like a joke, because they are trying to merge the good and the bad into one.
  2. WMI is very much resource-consuming.
  3. WMI equipment vendors often make mistakes/bugs in their WMI providers, and using them results in the application's crash.
  4. WMI is supported by a minority of equipment vendors, and as a result lots of hardware and software information is not available via WMI.
  5. WMI usage can be quite complex for languages such as C++.

Unfortunately, regardless of all the flaws that WMI carries with it, some details about the system just seem impossible to acquire in any other way, or require too much effort. My personal suggestion: Only use WMI when you really have to.

For those situations, ProSysLib offers a much simplified access to WMI functionality via the namespace of PSLSystem.Tools.WMI. It has a few methods to get information from WMI in the simplest possible way.

Consider an example of getting the Caption property from the WMI class Win32_OperatingSystem, which is the title of the current operational system.

string OSCaption = sys.Tools.WMI.GetValue(null,
   "Win32_OperatingSystem", "Caption");

In this example, you passed null for the namespace because the Win32_OperatingSystem class typically resides in the default namespace of "root\\cimv2" (also property DefaultNamespace of the interface).

he WMI namespace offers a few methods to get information from it in the simplest possible way. And, although using it simplifies WMI coding under .NET by two times at best, for C++ developers this simplifies WMI usage by 90%.

If, for instance, you wanted to get information for the "BuildNumber", "CountryCode", and "Locale" properties from the same class, you could use the following method:

Array a = sys.Tools.WMI.GetColValues(null,
   "Win32_OperatingSystem", "BuildNumber, CountryCode, Locale");

In other words, the WMI namespace has a method that takes a comma-separated list of property names and returns their values as an array of variants. This is for use with single-record WMI classes.

Similarly, if you wanted to get values for all records but just one column (multi-record WMI classes), you could make a call like this:

Array a = sys.Tools.WMI.GetRowValues(null,
   "Win32_Product", "Caption");

This method returns values for all rows and the selected column, also as an array of variants.

And if you want to use WMI in full, to issue a WQL query to get a whole table of data, your code would look as this:

// Selecting Caption and DeviceID for all queued printers:
PSLTable t = sys.Tools.WMI.GetData(null, "SELECT Caption,
   DeviceID FROM Win32_Printer WHERE Queued=True");
// Adding our table into the list of values:
for(int i = 0;i < t.nRows;i ++)
{
   // Adding Caption value to the list;
   MyList.Add(t.GetValue(i, 0).ToString());
   // Adding DeviceID value to the list;
   MyList.Add(t.GetValue(i, 1).ToString());
}

This method returnsthe PSLTable object that simplifies access to the data using array type of addressing as {row, column}. Plus, it has what a recordset object would, the ability to always get the list of columns, using:

// We would get "Caption" for our example here;
string FirstColumnName  = t.GetColName(0);
// "DeviceID"
string SecondColumnName = t.GetColName(1);

This is particularly useful when you issue a WQL query using SELECT *, selecting all columns, so you don't know which column is where.

Error and Exception Handling

ProSysLib lives up to its name in the area of handling errors and exceptions as well. Any error/exception is handled gracefully and exposed to the client via COM Exceptions, providing both numerical and verbal interpretation of any problem in functionality.

COM Exceptions are easy to handle and are supported automatically in any environment. For instance, in .NET COM exceptions are handled by the System.Runtime.InteropServices.COMException object, while in C++ they are handled via the _com_error type that's generated by the type library import mechanism.

The ProSysLib root namespace contains the DecodeException method that allows easy interpretation of the numerical COM error as an enumerated type. Consider an example of exception handling, in which you try to access a collection object with an index beyond what's reasonable, expecting an Index-Out-Of-Range type of exception:

try
{
   string sName = sys.Software.Processes[100000].FileName;
}
catch(System.Runtime.InteropServices.COMException ex)
{
   if(sys.DecodeException(ex.ErrorCode) ==
      PSLException.exceptionIndexOutOfRange)
   {
      // Yes, this is the exception that we indeed expected;
   }
   MessageBox.Show(ex.Message);    // Show the exception message;
}

Summary

These were just a very few examples of what has been already implemented within the ProSysLib architecture, and it has much more currently in progress. If you look at the tree of namespaces and ProSysLib SDK Documentation, you can find how far this project is meant to stretch. This article, again, just scratches the surface of the project. And, I do hope it finds developers who would like to join in to work on this project, providing their unique C++ experience to make their knowledge available to developers in all software platforms.

As I continue development of the project, I will be publishing more articles here with a focus on particular features as they become available, without considering the whole thing again.

Points of Interest

I always enjoy writing professional COM servers that make intense use of COM collections, internal COM instantiations, automated event marshallers, and many other neat tricks with COM, coverage for which in the internet is typically poor. There was in fact plenty that I learnt with this project.

For example, a great deal of code for the project is based on either undocumented Windows API or poorly documented API, learning which is a good challenge. It was fun digging out the truth about 64-bit implementations of API ZwQuerySystemInformation function, which required code debugging to see what the reality was. All information in the internet about the ZwQuerySystemInformation classes is for 32-bit only, but seems like nobody knows that; even Microsoft published misleading information about it in MSDN.

Anyway, these tricks and many others in implementation of ProSysLib I am planning to publish when I get around it, for I believe this is all a separate subject, and for now just trying to keep it simple for this article.

History

  • August 11, 2008. The first draft of the article.

Source Code and Downloads

Complete source code for both the program example provided here, plus other examples, along with the ProSysLib COM library itself is installed as part of ProSysLib SDK, which is available from www.prosyslib.org (is a free open-source project).



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Cisco and Intel have harnessed flash memory technology and truly innovative system software to blast through the boundaries of today's I/O-bound server/storage architectures. See how they are bringing real-time responsiveness to data-intensive applications—for unmatched business advantage. Sponsored by Cisco and Intel® Partnering in Innovation

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds