Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Getting the list of drivers running on Windows OS and displaying it in a ListView using pure Win32 calls

4.58/5 (13 votes)
20 Jul 2009CPOL4 min read 67.9K   3.4K  
This article explains how to get the list of drivers running on Windows OS and display the same in a ListView using Win32 calls.

Introduction

This article explains the following:

  • How to get the list of drivers running on a Windows machine
  • How to display the list of drivers in a ListView using pure Win32 calls

Note: This article has the latest code for an earlier article, and is updated with the features explained in this article. Please click here to reach my earlier article.

How to get the list of drivers on the machine

Drivers are, in fact, services which run on the OS. To get the list of services, first open the SCM (Service Control Manager) and then call EnumServicesStatus() to enumerate the services.

If more information is required than the ones returned by EnumServicesStatus() (which is the case here), then the service will have to be opened using OpenService() to query some of the required details using QueryServiceConfig(). These calls are made in the function CDriverInfoData::Initialize(). EnumServicesStatus() will get following information:

  • Driver name
  • Driver description
  • Current state of Driver
  • Number of Drivers installed in the system
  • Driver type

Here is the code snippet to enumerate the services:

C++
ENUM_SERVICE_STATUS struct_ServiceStatus;
ENUM_SERVICE_STATUS *lpServiceStatus;
BOOL b_RetVal = FALSE;
DWORD dw_BytesNeeded;
DWORD dw_ServiceCount;
DWORD dw_ResumeHandle = 0;
DWORD dw_ServiceType;
DWORD dw_ServiceState;
//We are interested only in drivers
dw_ServiceType = SERVICE_DRIVER;
// interested to know about drivers in all states
dw_ServiceState = SERVICE_STATE_ALL;
//Call EnumServicesStatus using the handle returned by OpenSCManager
b_RetVal = ::EnumServicesStatus(h_SCM,
                                dw_ServiceType,
                                dw_ServiceState,
                                &struct_ServiceStatus,
                                sizeof(struct_ServiceStatus),
                                &dw_BytesNeeded,
                                &dw_ServiceCount,
                                &dw_ResumeHandle);
DWORD dw_Error = GetLastError();
// Verify if EnumServicesStatus needs more memory space
if ((b_RetVal == FALSE) || dw_Error == ERROR_MORE_DATA) 
{
     DWORD dw_Bytes = dw_BytesNeeded + sizeof(ENUM_SERVICE_STATUS);
     lpServiceStatus = new ENUM_SERVICE_STATUS [dw_Bytes];
     EnumServicesStatus(h_SCM,
                    dw_ServiceType,
                    dw_ServiceState,
                    lpServiceStatus,
                    dw_Bytes,
                    &dw_BytesNeeded,
                    &dw_ServiceCount,
                    &dw_ResumeHandle);
}

Despite using EnumServicesStatus(), the driver startup type and path of the driver is still missing. For this, OpenService() will have to be used to open the service and query the information regarding the service using QueryServiceConfig(). Using QueryServiceConfig(), the following additional information will be obtained:

  • Driver startup type
  • Path of driver file

The code snippet to open the service and query the services is shown below:

C++
h_ServiceHandle = NULL;
h_ServiceHandle = OpenService(h_SCM, 
  lpServiceStatus[i].lpServiceName, SERVICE_ALL_ACCESS);
if(NULL != h_ServiceHandle)
{
     LPQUERY_SERVICE_CONFIG lpqscBuf; 
     DWORD dwBytesNeeded; 
     BOOL bSuccess=TRUE;
     // Allocate a buffer for the configuration information.
     lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096); 
     if (lpqscBuf == NULL) 
     {
         return FALSE;
     }
     // Get the configuration information. 
     if (!QueryServiceConfig(h_ServiceHandle, 
                         lpqscBuf, 
                         4096, // buffer size 
                         &dwBytesNeeded)) 
     {
         bSuccess = FALSE; 
     }

Meaning of each field in the Driver Information child window

Image 1

  • Serial No.: Sequence number of list of drivers, just allows interested users to see the count of drivers.
  • Driver Name: This is the driver name and is mostly the same as the driver file name.
  • Description: Description of the driver.
  • Driver Type: Shows the type of driver, whether it’s a Kernel driver or a File System driver.
  • Start Type: Shows the kind of start up. There are four types of startup modes plus one disable state. They are:
    • Auto start- Automatically started by SCM during system startup.
    • Boot start- Started by the system loader in case of drivers.
    • Demand start- Started on demand by calling StartService().
    • System start- Started by the IoInitSystem() call in the case of drivers.
    • Disabled- This state mentions that the driver is disabled.
  • Status: Shows the current status of the driver. The driver could be in one of the following states: Not Running, Starting, Running, Pause is pending, Paused, Continue is pending, Stopping.
  • Image Path: Path of the driver file.

How to create, add headers, and add elements to the list view

The listview is created in the CDriverInfoView class in the function CDriverInfoView::Draw(). The call to create the list view is shown below. The LVS_REPORT style is required to get the header for the columns.

The listview is created by the following call. WC_LISTVIEW should be used as the class name. This is done in the function bool CDriverInfoView::Draw(). The code snippet to do this is shown below:

C++
RECT rect;
GetClientRect(m_hwndParent, &rect);
m_hwndListView = CreateWindowEx(WS_EX_CLIENTEDGE,
                                WC_LISTVIEW,
                                "", //caption not required
                                WS_CHILD | WS_VISIBLE | LVS_REPORT,
                                0,  
                                0, 
                                rect.right, // width
                                rect.bottom,// height
                                m_hwndParent,
                                NULL,
                               (HINSTANCE) GetWindowLong (m_hwndParent, GWL_HINSTANCE),
                                NULL);
// Set the single row select style
SendMessage(m_hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 
                  0, LVS_EX_FULLROWSELECT); // Set style

Adding column headers is done by calling SendMessage() with LVM_INSERTCOLUMN. wParam represents the column number. This is done in the function bool CDriverInfoView::FillData(CDriverInfoData &pDriverInfoData) as shown below:

C++
LVCOLUMN ListviewCol;
memset((void*)&ListviewCol, 0, sizeof(ListviewCol));
    
ListviewCol.mask = LVCF_TEXT | LVCF_WIDTH; // Mask
ListviewCol.cx = 0x40;                       // column width
ListviewCol.pszText = "Serial No";                         
SendMessage(m_hwndListView,LVM_INSERTCOLUMN,0,(LPARAM)&ListviewCol);
ListviewCol.pszText = "Driver Name";                         
SendMessage(m_hwndListView,LVM_INSERTCOLUMN,1,(LPARAM)&ListviewCol);

Inserting rows is done by first inserting the first cell in a row with the value and then subsequent cells are set with values. SendMessage with the LVM_INSERTITEM and LVM_SETITEM messages are used to achieve this. The code snippet to do the same is shown below:

C++
DRIVERINFO_STRUCT structDriverInfo;
memset((void*)&structDriverInfo, 0, sizeof(structDriverInfo));
pDriverInfoData.Get_FirstDriverInfo(&structDriverInfo);
int i_Col = 0;
TCHAR szSlNo[12];
do
{
     // Fill Serial number
     // main item number, this can be considered as row number 
     ListviewItem.iItem = i_Col;
     // Put in the first column
     ListviewItem.iSubItem = DRIVERINFO_SERIALNO_COL;
     memset((void*)szSlNo, 0, sizeof(TCHAR[12]));
     sprintf(szSlNo, "%d", i_Col + 1);
     // Text to display (can be from a char variable) (Items)
     ListviewItem.pszText = TEXT(szSlNo);
     SendMessage(m_hwndListView,LVM_INSERTITEM,0,(LPARAM)&ListviewItem);
     // Send to the Listview
  
     // Fill Driver Name column
     // main item number, this can be considered as row number 
     ListviewItem.iItem = i_Col;
     ListviewItem.iSubItem = DRIVERINFO_NAME_COL;  // Put in second coluom
     // Text to display (can be from a char variable) (Items)
     ListviewItem.pszText = TEXT(structDriverInfo.DriverName);
     SendMessage(m_hwndListView,LVM_SETITEM,0,(LPARAM)&ListviewItem);
     // Send to the Listview

Creation of Driver Information MDI child window

The MDI child window which shows Driver Information is created on getting the command message of ID_INFORMATION_DRIVERINFORMATION in the main frame window proc of SigmaFrameWndProc. Here, a CDriverInfo object is created on the heap. This g_pDriverInfo object is then used to create the window and fill in the list control.

CDriverInfo::CreateDriverInfoWindow() registers the child window and creates the MDI child window. The code snippet is shown below:

C++
MDICREATESTRUCT    MDIChildCreateStruct;
MDIChildCreateStruct.szClass = TEXT("SigmaDriverInfoWnd");
MDIChildCreateStruct.szTitle = TEXT("Driver Information");
MDIChildCreateStruct.hOwner  = ghInstance;
MDIChildCreateStruct.x   = CW_USEDEFAULT;
MDIChildCreateStruct.y   = CW_USEDEFAULT;
MDIChildCreateStruct.cx   = CW_USEDEFAULT;
MDIChildCreateStruct.cy   = CW_USEDEFAULT;
MDIChildCreateStruct.style  = 0;
MDIChildCreateStruct.lParam  = 0;
 
m_hwndDriverInformation = (HWND) SendMessage(ghMDIClientArea,
                                          WM_MDICREATE, 
                                          0,
                              (LPARAM) (LPMDICREATESTRUCT) &MDIChildCreateStruct) ;

// return if its not possible to create the child window
if(NULL == m_hwndDriverInformation)
{
    return 0;
}

MDICREATESTRUCT is used to set the child window parameters. This is passed as the last parameter of SendMessage. SendMessage is used to send WM_MDICREATE messages to the client area of the main frame window.

InitCommonControlsEx() is called to initialize the common controls. This is required for the list control to be created.

Classes and their functionality

  • CDriverInfo – This class holds member elements representing Data and View by means of the CDriverInfoData and CDriverInfoView classes, respectively. A child window is created in this class.
  • CDriverInfoData – This stores the data that should be shown in the listview.
  • CDriverInfoView – This class is used to initialize the listview and fill in data that is available in CDriverInfoData into the listview.

Environment

This article had been developed and tested under the following environment only: Lenovo T61 laptop, VC++ 6.0, UNICODE, C++, and XP SP3.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)