List installed programs (Windows)

Started by
5 comments, last by iliak 18 years, 10 months ago
Hi Does someone know how to list installed programs under windows in c/c++ via Windows API ?
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
Advertisement
The only way I know is via WMI but it's relatively complicated because it uses COM model. It has one advantage - once you set it up you can query a lot of useful info from system.
I can post some code if you want.
WMI... Ok I'll look, if you can post some code it would be nice :)
thx
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
You could look in the registry. Usually applications put a key into HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall when they are installed.
So as you asked, here is some basic code to get WMI up and detect all installed applications.

#define _WIN32_DCOM#include <comdef.h>#include <Wbemidl.h>#include <string>#include <iostream>#include <sstream>using namespace std;// this library is required#pragma comment(lib, "wbemuuid.lib")/* Forward declarations */string DoubleToString(double d);string VariantToString(const VARIANT &var);string GetPropertyAsString(LPCWSTR name, IWbemClassObject *Object);int main(void){    HRESULT hres;    // Initialize COM.    hres =  CoInitializeEx(0, COINIT_MULTITHREADED);     if (FAILED(hres))    {        cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;        return 1;    }    // Set general COM security levels    hres =  CoInitializeSecurity(NULL,                          // Security descriptor                                 -1,                            // COM authentication                                 NULL,                          // Authentication services                                 NULL,                          // Reserved                                 RPC_C_AUTHN_LEVEL_DEFAULT,     // Default authentication                                  RPC_C_IMP_LEVEL_IMPERSONATE,   // Default Impersonation                                   NULL,                          // Authentication info                                 EOAC_NONE,                     // Additional capabilities                                  NULL);                         // Reserved                          if (FAILED(hres))    {        cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;        CoUninitialize();        return 2;    }        // Obtain the initial locator to WMI    IWbemLocator *Locator = NULL;    hres = CoCreateInstance(CLSID_WbemLocator,                            0,                            CLSCTX_INPROC_SERVER,                            IID_IWbemLocator,                            (LPVOID *) &Locator);    if (FAILED(hres))    {        cout << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << endl;        CoUninitialize();        return 3;    }    // Connect to WMI through the IWbemLocator::ConnectServer method    IWbemServices *Services = NULL;	    // Connect to the root\cimv2 namespace, this namespace contains all we want    hres = Locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),      // Connect to CIMV2 namespace of WMI                                  NULL,                         // User Name (NULL = curren user)                                  NULL,                         // User Password (NULL = current)                                  0,                            // Locale, current                                  NULL,                         // Security flags                                  0,                            // Authority                                  0,                            // Context object                                  &Services);                   // IWbemServices proxy        if (FAILED(hres))    {        cout << "Could not connect. Error code = 0x" << hex << hres << endl;        Locator->Release();             CoUninitialize();        return 4;    }    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;    // Set security levels on the proxy    hres = CoSetProxyBlanket(Services,                          // Indicates the proxy to set                             RPC_C_AUTHN_WINNT,                 // RPC_C_AUTHN_xxx                             RPC_C_AUTHZ_NONE,                  // RPC_C_AUTHZ_xxx                             NULL,                              // Server principal name                              RPC_C_AUTHN_LEVEL_CALL,            // RPC_C_AUTHN_LEVEL_xxx                              RPC_C_IMP_LEVEL_IMPERSONATE,       // RPC_C_IMP_LEVEL_xxx                             NULL,                              // client identity                             EOAC_NONE);                        // proxy capabilities     if (FAILED(hres))    {        cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;        Services->Release();        Locator->Release();             CoUninitialize();        return 5;    }    // Enumerator is used to enumerate CIM objects    IEnumWbemClassObject *Enumerator = NULL;    // Crate enumerator which contains all installed products    // Queries are specified in language similar to SQL    // Here we select all objects with class Win32_Product (this class represents installed application)    hres = Services->ExecQuery(bstr_t("WQL"),                   // Query language, must be WQL                               bstr_t("SELECT * FROM Win32_Product"),   // Query                               WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,                               NULL,                               &Enumerator);      if (FAILED(hres))    {        cout << "Query for enumerator failed." << " Error code = 0x" << hex << hres << endl;        Services->Release();        Locator->Release();        CoUninitialize();        return 6;    }    HRESULT             hRes = WBEM_S_NO_ERROR;       // while we have something in enumeration    while (hRes == WBEM_S_NO_ERROR)    {        const int           object_count = 1;   // number of objects to return        ULONG               returned = 0;       // number of objects actually returned        IWbemClassObject    *ClassObjects[object_count] = {NULL}; // space to hold returned objects        // get next object_count objects from enumerator        hRes = Enumerator->Next(WBEM_INFINITE, object_count, ClassObjects, &returned);        // no error        if (SUCCEEDED(hRes))        {            // for each returned object output its properties to screen            for (unsigned int i = 0; i < returned; i++)            {                // Output some of the properties                cout << "Name: " << GetPropertyAsString(L"Name", ClassObjects) << endl;                cout << "Vendor: " << GetPropertyAsString(L"Vendor", ClassObjects) << endl;                cout << "Version: " << GetPropertyAsString(L"Version", ClassObjects) << endl;                cout << "********" << endl;                ClassObjects->Release();            }        }    }    // Cleanup    Services->Release();    Locator->Release();    Enumerator->Release();    CoUninitialize();    getchar();    return 0;}/* Convert double to string */string DoubleToString(double d) {        stringstream str;    str << d;    return str.str();}/* Convert value stored in VARIANT to string for easier manipulation */string VariantToString(const VARIANT &var) {	char buffer[40] = {0};                                      // Temp buffer for numbers	switch (var.vt) {        		default:		case VT_NULL:                                           // no value		case VT_EMPTY:                                          // no value		case VT_EMPTY | VT_BYREF:                               // bad variant			return string("unknown");		case VT_UI1:                                            // char			_ultoa((long) var.bVal, buffer, 10);			break;		case VT_UI1 | VT_BYREF:                                 // Reference to char			_ultoa((long) *var.pbVal, buffer, 10);			break;		case VT_UI2:                                            // 16 bit unsigned int			_ultoa((long) var.uiVal, buffer, 10);			break;		case VT_UI2 | VT_BYREF:                                 // Reference to 16 bit unsigned int			_ultoa((long) *var.puiVal, buffer, 10);			break;		case VT_UI4:                                            // 32 bit unsigned int			_ultoa((long) var.ulVal, buffer, 10);			break;		case VT_UI4 | VT_BYREF:                                 // Reference to 32 bit unsigned int			_ultoa((long) *var.pulVal, buffer, 10);			break;		case VT_UI8:                                            // 64 bit unsigned int			_ui64toa((unsigned __int64) var.ullVal, buffer, 10);			break;		case VT_UI8 | VT_BYREF:                                 // Reference to 64 bit unsigned int			_ui64toa((unsigned __int64) *var.pullVal, buffer, 10);			break;		case VT_UINT:                                           // Unsigned int			_ultoa((long) var.uintVal, buffer, 10);			break;		case VT_UINT | VT_BYREF:                                // Reference to unsigned int			_ultoa((long) *var.puintVal, buffer, 10);			break;		case VT_INT:                                            // int			_ltoa((long) var.intVal, buffer, 10);			break;		case VT_INT | VT_BYREF:                                 // Reference to int			_ltoa((long) *var.puintVal, buffer, 10);			break;		case VT_I1:                                             // char			_ltoa((long) var.cVal, buffer, 10);			break;		case VT_I1 | VT_BYREF:                                  // reference to char			_ltoa((long) *var.pcVal, buffer, 10);			break;		case VT_I2:                                             // 16 bit int			_ltoa((long) var.iVal, buffer, 10);			break;		case VT_I2 | VT_BYREF:                                  // Pointer to 16 bit int			_ltoa((long) *var.piVal, buffer, 10);			break;		case VT_I4:                                             // 32 bit int			_ltoa((long) var.lVal, buffer, 10);			break;		case VT_I4 | VT_BYREF:                                  // Pointer to 32 bit int			_ltoa((long) *var.plVal, buffer, 10);			break;		case VT_I8:                                             // 64 bit int			_i64toa((__int64) var.llVal, buffer, 10);			break;		case VT_I8 | VT_BYREF:                                  // Pointer to 64 bit int			_i64toa((__int64) *var.pllVal, buffer, 10);			break;		case VT_R4:                                             // 32 bit real (float)			return DoubleToString((double) var.fltVal);		case VT_R4 | VT_BYREF:                                  // Pointer to 32 bit real (float)			return DoubleToString((double) *var.pfltVal);		case VT_R8:                                             // double			return DoubleToString(var.dblVal);		case VT_R8 | VT_BYREF:                                  // Pointer to double			return DoubleToString(*var.pdblVal);		case VT_BSTR:                                           // string (BSTR)			{				char    str[1024] = "";				WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, str, 1024, NULL, NULL);				return string(str);			}		case VT_BSTR | VT_BYREF:                                // Pointer to string (BSTR)			{				char    str[1024] = "";				WideCharToMultiByte(CP_ACP, 0, *var.pbstrVal, -1, str, 1024, NULL, NULL);				return string(str);			}		case VT_BOOL:                                           // BOOL			if (var.boolVal == 0) {				strcpy(buffer, "false");			} else {				strcpy(buffer, "true");			}			break;		case VT_BOOL | VT_BYREF:                                // Pointer to BOOL			if (*var.pboolVal == 0) {				strcpy(buffer, "false");			} else {				strcpy(buffer, "true");			}			break;	}	return string(buffer);}/* Get value of property named name from given object and convert it to std::string */string GetPropertyAsString(LPCWSTR name, IWbemClassObject *Object){    string result;    VARIANT Value;    // error, return empty string    if (Object == NULL) return string("");    // initialize variant to empty one    VariantInit(&Value);    // get value of property    Object->Get(name, 0, &Value, 0, 0);    // convert it to string    result = VariantToString(Value);    // free memory used by variant    VariantClear(&Value);    return result;}


The biggest part of this code is just to provide nicer interface to VARIANTS which store values of properties in WMI objects.
Actual detection of installed applications happens in the line which contains
Services->ExecQuery(...)

There you query WMI for all objects of type Win32_Product. This classes store info about installed applications.
For more info about properties of such class look into MSDN documentation.

NOTE: I have tested this application and it works nicely. However there can be stupid errors in VariantToString() function as I can't test all possible VARIANTS.
Nice, many thanks :)
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
For the ones who are interested, here's a MSDN link explaining the way to handle : Creating a WMI Application Using C++
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]

This topic is closed to new replies.

Advertisement