获取 Windows OS 上运行的驱动程序列表并使用纯 Win32 调用在 ListView 中显示






4.58/5 (13投票s)
本文介绍如何获取 Windows OS 上运行的驱动程序列表,并使用 Win32 调用将其显示在 ListView 中。
引言
本文档介绍了以下内容
- 如何获取 Windows 计算机上运行的驱动程序列表
- 如何使用纯 Win32 调用将驱动程序列表显示在 ListView 中
注意:本文档包含一篇早期文章的最新代码,并更新了本文中介绍的功能。请单击此处访问我的早期文章。
如何获取计算机上的驱动程序列表
驱动程序实际上是在操作系统上运行的服务。要获取服务列表,首先打开 SCM(服务控制管理器),然后调用 EnumServicesStatus()
枚举服务。
如果需要比 EnumServicesStatus()
返回的信息更多的信息(本例中就是如此),那么必须使用 OpenService()
打开服务,并使用 QueryServiceConfig()
查询一些必需的详细信息。这些调用在 CDriverInfoData::Initialize()
函数中完成。EnumServicesStatus()
将获取以下信息
- 驱动程序名称
- 驱动程序描述
- 驱动程序的当前状态
- 系统中安装的驱动程序数量
- 驱动程序类型
以下是枚举服务的代码片段
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);
}
尽管使用了 EnumServicesStatus()
,但驱动程序的启动类型和驱动程序路径仍然缺失。为此,必须使用 OpenService()
打开服务,并使用 QueryServiceConfig()
查询有关服务的信息。使用 QueryServiceConfig()
,将获得以下附加信息
- 驱动程序的启动类型
- 驱动程序文件的路径
以下代码片段显示了打开服务和查询服务的代码
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;
}
驱动程序信息子窗口中每个字段的含义
- 序号。:驱动程序列表的序号,仅供有兴趣的用户查看驱动程序计数。
- 驱动程序名称:这是驱动程序名称,通常与驱动程序文件名相同。
- 描述:驱动程序的描述。
- 驱动程序类型:显示驱动程序的类型,无论是内核驱动程序还是文件系统驱动程序。
- 启动类型:显示启动的类型。有四种启动模式加上一种禁用状态。它们是
- 自动启动 - 在系统启动期间由 SCM 自动启动。
- 引导启动 - 在驱动程序的情况下由系统加载程序启动。
- 按需启动 - 通过调用
StartService()
按需启动。 - 系统启动 - 在驱动程序的情况下由
IoInitSystem()
调用启动。 - 禁用 - 此状态表示驱动程序已被禁用。
- 状态:显示驱动程序的当前状态。驱动程序可能处于以下状态之一:未运行、正在启动、正在运行、暂停待定、已暂停、继续待定、正在停止。
- 映像路径:驱动程序文件的路径。
如何创建、添加标题以及向列表视图添加元素
列表视图在 CDriverInfoView
类中的 CDriverInfoView::Draw()
函数中创建。创建列表视图的调用如下所示。需要 LVS_REPORT
样式才能获取列标题。
列表视图通过以下调用创建。应将 WC_LISTVIEW
用作类名。这在 bool CDriverInfoView::Draw()
函数中完成。下面显示了执行此操作的代码片段
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
通过调用 SendMessage()
并使用 LVM_INSERTCOLUMN
来添加列标题。wParam
代表列号。这在 bool CDriverInfoView::FillData(CDriverInfoData &pDriverInfoData)
函数中完成,如下所示
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);
插入行是通过首先插入具有值的行的第一个单元格,然后为后续单元格设置值来完成的。使用 SendMessage
和 LVM_INSERTITEM
和 LVM_SETITEM
消息来实现此目的。下面显示了执行相同操作的代码片段
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
创建驱动程序信息 MDI 子窗口
显示驱动程序信息的 MDI 子窗口是在主框架窗口过程 SigmaFrameWndProc
中收到 ID_INFORMATION_DRIVERINFORMATION
命令消息时创建的。在此,在堆上创建了一个 CDriverInfo
对象。然后使用此 g_pDriverInfo
对象来创建窗口并填充列表控件。
CDriverInfo::CreateDriverInfoWindow()
注册子窗口并创建 MDI 子窗口。代码片段如下所示
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
用于设置子窗口参数。这作为 SendMessage
的最后一个参数传递。SendMessage
用于向主框架窗口的客户端区域发送 WM_MDICREATE
消息。
调用 InitCommonControlsEx()
来初始化通用控件。这是创建列表控件所必需的。
类及其功能
CDriverInfo
- 此类通过CDriverInfoData
和CDriverInfoView
类分别表示数据和视图的成员元素。在此类中创建子窗口。CDriverInfoData
- 此类存储应在列表视图中显示的数据。CDriverInfoView
- 此类用于初始化列表视图,并将CDriverInfoData
中可用的数据填充到列表视图中。
环境
本文档仅在以下环境开发和测试:联想 T61 笔记本电脑、VC++ 6.0、UNICODE、C++ 和 XP SP3。