Finding applications installed on a machine (the ones that you see in Control Panel Add/Remove programs) could be a little bit tricky, because there isn’t a bulletproof API or method. Each of the available methods has its own weak points. WMI is slow and can actually be disabled on a machine. MSI API only shows applications installed with an MSI, and reading directly from the Windows Registry is not an officially supported alternative. Thus it is an open point which one is the most appropriate, though the official answer will probably be MSI API.

In this post I will go through all of these three methods and show how to query for the installed applications and display the name, publisher, vendor and installation location (if available). Notice these are just some samples, and if you want to use this in your applications you’ll probably want to do additional things like better error checking. Because I want the code to work both with ANSI and UNICODE I will use the following defines

WMI
Win32_Product is a WMI class that represents a product installed by Windows Installer. For fetching the list of installed applications with WMI I will reuse the WMIQuery class I first shown in this post. You need to include Wbemidl.h and link with wbemuuid.lib.

In the code shown below WmiQueryValue() is a function that reads a property from the current record and returns it as an STL string (UNICODE or ANSI). WmiEnum() is a function that fetches and displays in the console all the installed applications.

A sample from the output of this WmiEnum() function looks like this:

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

One can notice that the code is relatively long, but most important it is very slow.

MSI API
Two of the MSI API functions can help fetching the list of installed applications:

  • MsiUnumProductsEx: enumerates through one or all the instances of products that are currently advertised or installed (requires Windows Installer 3.0 or newer)
  • MsiGetProductInfoEx: returns product information for advertised and installed products

In order to use these functions you need to include msi.h and link to msi.lib.

In the code below, MsiQueryProperty() is a function that returns the value of product property (as a tstring as defined above) by calling MsiGetProductInfoEx. MsiEnum() is a function that iterates through all the installed applications and prints in the console the name, publisher, version and installation location.

And this is a sample for the WmiEnum() function.

Java(TM) 6 Update 25
– Oracle
– 6.0.250
– C:\Program Files\Java\jre6\

Java(TM) SE Development Kit 6 Update 25
– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft .NET Framework 4 Client Profile
– Microsoft Corporation
– 4.0.30319

Microsoft Sync Framework Services v1.0 SP1 (x86)
– Microsoft Corporation
– 1.0.3010.0

Microsoft ASP.NET MVC 2 – Visual Studio 2010 Tools
– Microsoft Corporation
– 2.0.50217.0

Adobe Reader X (10.0.1)
– Adobe Systems Incorporated
– 10.0.1
– C:\Program Files\Adobe\Reader 10.0\Reader\

Windows Registry
Installed applications are listed in Windows Registry under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall. The KB247501 article explains the structure of the information under this Registry key. Make sure you read it if you decide to use this approach.

In the code shown below, RegistryQueryValue() is a function that queries the value of a name/value pair in the registry and returns the value as a tstring. RegistryEnum() is a function that prints to the console all the installed application as found in the registry.

And a sample output of the RegistryEnum() function:

Java(TM) SE Development Kit 6 Update 25

– Oracle
– 1.6.0.250
– C:\Program Files\Java\jdk1.6.0_25\

Microsoft Visual Studio 2005 Tools for Office Runtime

– Microsoft Corporation
– 8.0.60940.0

MSDN Library for Visual Studio 2008 – ENU

– Microsoft
– 9.0.21022
– C:\Program Files\MSDN\MSDN9.0\

Microsoft SQL Server Compact 3.5 SP2 ENU

– Microsoft Corporation
– 3.5.8080.0
– C:\Program Files\Microsoft SQL Server Compact Edition\

Microsoft .NET Framework 4 Client Profile

– Microsoft Corporation
– 4.0.30319

, , , , Hits for this post: 36734 .

It is possible to register both 32-bit and 64-bit versions of the same COM server on 64-bit machine. This leads to several questions such as how are they registered and which one of the two is used. I will try to answer them below. But first, let’s start with an example.

Example
Let’s say we have the a simple COM local server called COM3264Server.exe. There is just one interface called ICoCOM3264Server. Here is the IDL file:

The implementation of the method SayHello() is straight forward; it just displays a message box with a text that varies between the two architectures, x64 and x86.

Registry
When you register the COM server, the 32-bit and 64-bit versions are registered in different parts of the registry. On 64-bit machine, the registry has two views (or modes):

  • a native view, for 64-bit application; (e.g. registry path for CLSIDs is HKEY_CLASSES_ROOT\CLSID\)
  • a WOW64 view, which enables redirections for 32-bit applications, a process transparent to the user (e.g. registry path for CLSIDs is HKEY_CLASSES_ROOT\Wow6432Node\CLSID\)

Here is the Registry registration of the (native) 64-bit COM server (notice the registry key in the status bar of the editor, and the path to the server executable).

On, the other hand, the 32-bit COM server is registered under the Wow6432 node.

So if both versions are registered in Windows Registry, which one is picked? Well, both the server and the client can specify which architecture to use:

  • the COM server can do this via the PreferredServerBitness Registry value
  • the client can do this using one of the flags CLSCTX_ACTIVATE_32_BIT_SERVER and CLSCTX_ACTIVATE_64_BIT_SERVER, which overrides the server preference

If neither the client nor the server specifies a preference, then:

  • If the computer that hosts the server is running Windows Server 2003 with Service Pack 1 (SP1) or a later system, then COM will try to match the server architecture to the client architecture. In other words, for a 32-bit client, COM will activate a 32-bit server if available; otherwise it will activate a 64-bit version of the server. For a 64-bit client, COM will activate a 64-bit server if available; otherwise it will activate a 32-bit server.
  • If the computer that hosts the server is running Windows XP or Windows Server 2003 without SP1 or later installed, then COM will prefer a 64-bit version of the server if available; otherwise it will activate a 32-bit version of the server.

Server Preference
The server can specify its preferred architecture in the PreferredServerBitness value under AppId (available only on 64-bit Windows). This integer value can be:

  • 1: Match the server architecture to the client architecture. For example, if the client is 32-bit, use a 32-bit version of the server, if it is available. If not, the client’s activation request will fail.
  • 2: Use a 32-bit version of the server. If one does not exist, the client’s activation request will fail.
  • 3: Use a 64-bit version of the server. If one does not exist, the client’s activation request will fail.

Here is the value set in Registry to specify the 64-bit architecture.

When you run the client, it launches the 64-bit version and in my example the following window pops-up:

If I change the value to indicate the 32-bit architecture, the other COM server is launched and the displayed message is:

Client Preference
The client code I used so far looked like this:

However, the 64-bit version of Windows added new flags to the CLSCTX enumeration.

  • CLSCTX_ACTIVATE_32_BIT_SERVER: used to activate or connect to a 32-bit version of the server; fail if one is not registered.
  • CLSCTX_ACTIVATE_64_BIT_SERVER: used to activate or connect to a 64 bit version of the server; fail if one is not registered.

As I mentioned earlier, if the client uses one of these flags, it overrides the server preference (specified via the PreferredServerBitness Registry value).

In the following example, the client requests the 64-bit COM server:

And if you run it, no matter what the server specified, the 64-bit COM server is launched.

To read more about the subject see the MSDN links above.

, , , Hits for this post: 58904 .

COM and Registry

If you are working with COM there are several registry entries that are important and that you need to understand. I will try in this post to clarify them. But before that, let’s enumerate the three possible COM server scenarios. (As a side note, a COM server is a DLL or EXE can contains one or more COM objects; a client is an entity that uses a COM object, which means a COM server can also be the client of another COM server.)

  • inproc: the COM server is loaded into the client process; in this case accessing the COM methods is as simple as using an interface pointer when the client and the in-proc server are in the same thread
  • local: the COM server and the client are loaded in different processes on the same machine; communication is achieved with the use of proxies and stubs via Lightweight RPC
  • remote: the COM server and the client are loaded in different processes on different machines; communication is achieved with the use of proxies and stubs via RPC

In order for the COM Library to be able to locate and instantiate the COM objects correctly, different information is stored in the Windows Registry. The most important information is located under the keys CLSID, TypeLib, Interface and AppID from HKEY_CLASSES_ROOT. The images below show examples for IIS.

HKEY_CLASSES_ROOT\CLSID
Every coclass from the COM server has at least an entry under this key, specifying the CLSID and the ProgID. The CLSID is a GUID that uniquely identifies the class, and the ProgID (programmatic identifier) is a string that identifies the class in a more human readable form. Each ProgID is mapped to a CLSID. The following image shows the mapping for the IIS ProgID.

For each COM class, there must be a key under HKEY_CLASSES_ROOT\CLSID, with the CLSID as the name. The most important sub-keys here are:

  • ProgID: the programmatic identifier, mapped on the CLSID; cam contain a version number (as a suffix)
  • VersionIndependentProgID: a programmatic identifier without the version information
  • InprocServer32: specifies the path of the DLL for the inproc servers
  • LocalServer32: specifies the path of the COM executable for the local (out-of-process) servers
  • TypeLib: indicates the LIBID of the type library that contains the coclass

Here are several screenshots from registry for IIS CLSID.


HKEY_CLASSES_ROOT\TypeLib
Each type library has a key under HKEY_CLASSES_ROOT\TypeLib, with the name of the LIBID. The sub-keys provide information about the physical location of the type library file (.tlb file) and others, such as flags (FLAGS key) the directory that contains the help file for the type library (HELPDIR key). A LIBID is a GUID that uniquely identifies a type library. A *.TLB file is a binary version of an IDL file. This is used by languages such as VB, Java, Javascript and many others in order to be able to use the COM objects.

The following image shows the type lib information for IIS.

HKEY_CLASSES_ROOT\Interface
Information for all interfaces defined in an IDL file (type library) must be added to the registry. Under HKEY_CLASSES_ROOT\Interface must be a key with the IID of the interface. The IID (interface identifier) is a GUID that uniquely identifies an interface. The most important sub-keys are:

  • TypeLib: the LIBID of the type library containing the interface
  • ProxyStubClsid32: the CLSID of the marshaller used to marshal the interface; value {00020424-0000-0000-C000-000000000046} identifies oleaut32.dll, which is the universal marshaler.

The following images show the registry entry for the interface IISBaseObject.

HKEY_CLASSES_ROOT\AppID
An AppID (application identifier) is a GUID that uniquely identifies a COM server and is used to describe security and activation settings; it is used for out-of-proc (local or remote) scenarios. Usually the AppID is the same with a CLSID of a coclass from the COM server (without the risk of collision, because the CLSID and the AppID server different purposes). The most important settings are:

  • AccessPermission: defines the ACL of users that can access the server
  • AuthenticationLevel: defines the authentication level
  • DllSurrogate: identifies the surrogate that can host the DLL; if no value is specified, the default dllhost.exe surrogate is used
  • LaunchPermissions: defines the ACL of users that can launch the application
  • RemoteServerName: identifies the remove server machine

The following images shows the values for an AppID key.

, Hits for this post: 43388 .

Working correctly with the Windows Registry might prove a little difficult, especially for beginners. One thing one should care about for example is using the correct access rights (not just the default ones) when creating a registry key. To ease the burden of directly using the Win32 registry API, I decided to wrap them inside two classes and make them available for anyone that wants to use them.

The classes that I put together are:

  • SecurityAttributesUtils: this is transparent for the developer, and is used to create the necessary access rights for creating a registry key;
  • RegistryUtils: offers static functions for creating, deleting and closing a key, as well as reading and writing double words, strings and binary data to/from the registry;
  • RegistryUtilsEx: a class based on RegistryUtils used for reading and writing strings and binary data, that uses STL’s std::string or std::wstring classes.

To create a key you should use RegistryUtils::CreateKey. It takes a handle to an open key (usually one of the predefined keys HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, etc. or an already opened key), the name of the subkey the function opens or creates and the desire access rights. It returns the handle to the opened or created key as the first argument, and a value indicating the success or failure.

To write a string use either RegistryUtils::WriteString or RegistryUtilsEx::WriteString string if you use STL std::string or std::wstring. It takes the handle to the key, the name of the value and the value to write.

To read a string use either RegistryUtils::ReadString or RegistryUtilsEx::ReaderString, the later for working with STL’s strings.

Simillary, you can use ReadDword() and WriteDword() for reading and writing integer values, and ReadBinary() and WriteBinary() for generic binary data.

To close an opened key call RegistryUtils::CloseKey().

Additionally, RegistryUtils::DeleteKey() can be used to delete a specified key, along with all its sub-keys and values.

The code is available for download here.

, , Hits for this post: 26938 .