实战DeviceIoControl之五:列举已安装的存储设备
2010-01-10 09:37:27 来源:WEB开发网Q 前几次我们讨论的都是设备名比较清楚的情况,有了设备名(路径),就可以直接调用CreateFile打开设备,进行它所支持的I/O操作了。如果事先并不能确切知道设备名,如何去访问设备呢?
A 访问设备必须用设备句柄,而得到设备句柄必须知道设备路径,这个套路以你我之力是改变不了的。每 个设备都有它所属类型的GUID,我们顺着这个GUID就能获得设备路径。 GUID是同类或同种设备的全球唯一识别码,它是一个128 bit(16字节)的整形数,真实面目为
typedef struct _GUID
例如, Disk类的GUID为“53f56307-b6bf-11d0-94f2-00a0c91efb8b”,在我们的程序里可以定义为
{
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID, *PGUID;
const GUID DiskClassGuid = {0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb,0x8b)};
或者用一个宏来定义
DEFINE_GUID(DiskClassGuid, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb,0x8b);
通过GUID 找出设备路径,需要用到一组设备管理的API函数SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces,SetupDiGetInterfaceDeviceDetail,SetupDiDestroyDeviceInfoList,以 及结构SP_DEVICE_INTERFACE_DATA, SP_DEVICE_INTERFACE_DETAIL_DATA。
有关信息请查阅MSDN ,这里就不详细介绍了。 实现GUID到设备路径的代码如下:
// SetupDiGetInterfaceDeviceDetail所需要的输出长度,定义足够大
#define INTERFACE_DETAIL_SIZE (1024)
// 根据GUID获得设备路径
// lpGuid: GUID指针
// pszDevicePath: 设备路径指针的指针
// 返回: 成功得到的设备路径个数,可能不止1个
int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath)
{
HDEVINFO hDevInfoSet;
SP_DEVICE_INTERFACE_DATA ifdata;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
int nCount;
BOOL bResult;
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, // class GUID
NULL, // 无关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // 目 前存在的设备
// 失败...
if(hDevInfoSet == INVALID_HANDLE_VALUE)
{
return 0;
}
// 申请设备接口数据空间
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT,
INTERFACE_DETAIL_SIZE);
pDetail->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
nCount = 0;
bResult = TRUE;
// 设备 序号=0,1,2... 逐一测试设备接口,到失败为止
while (bResult)
{
ifdata.cbSize=sizeof(ifdata);
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInterfaces( hDevInfoSet, // 设备信息集句柄
NULL, // 不需额 外的设备描述
lpGuid, // GUID
(ULONG)nCount, // 设备信息集里的设备序号
&ifdata); // 设备接口信息
if(bResult)
{
// 取得该设备接口的 细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifdata, // 设备接口信息
pDetail, // 设备接口细节(设 备路径)
INTERFACE_DETAIL_SIZE, // 输出缓冲区大小
NULL, // 不需计算输出 缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
if(bResult)
{
// 复制设备路径到输出缓冲区
::strcpy(pszDevicePath[nCount], pDetail ->DevicePath);
// 调整计数值
nCount++;
}
}
}
// 释放设备接口数据空间
::GlobalFree(pDetail);
// 关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
return nCount;
}
调用 GetDevicePath函数时要注意,pszDevicePath是个指向字符串指针的指针,例如可以这样
int i;
char* szDevicePath[MAX_DEVICE]; // 设备路径
// 分配需要的空间
for(i=0; i<MAX_DEVICE; i++) szDevicePath[i] = new char[256]; // 取设备路径
nDevice = ::GetDevicePath((LPGUID)&DiskClassGuid, szDevicePath);
// 逐一获取设备信息
for(i=0; i<nDevice; i++)
{
// 打开设备
hDevice = ::OpenDevice (szDevicePath[i]);
if(hDevice != INVALID_HANDLE_VALUE)
{
... ... // I/O操作
::CloseHandle(hDevice);
}
}
// 释放空间
for (i=0;i<MAX_DEVICE;i++) delete []szDevicePath[i];
Tags:实战 DeviceIoControl 列举
编辑录入:爽爽 [复制链接] [打 印]- ››实战案例分析:高质量软文对网站百度排名的影响
- ››实战经验浅谈网站搬家后的优化工作
- ››实战Active Directory站点部署与管理,Active Dir...
- ››实战操作主机角色转移,Active Directory系列之十...
- ››实战经验:巧用微博推广淘宝网店
- ››实战iPhone GPS定位系统
- ››实战Linux环境配置DBD:Oracle模块
- ››实战DeviceIoControl系列之一:通过API访问设备驱...
- ››实战DeviceIoControl系列之二:获取软盘/硬盘/光盘...
- ››实战DeviceIoControl系列之三:制作磁盘镜像文件
- ››实战DeviceIoControl系列之四:获取硬盘的详细信息...
- ››实战DeviceIoControl之五:列举已安装的存储设备
更多精彩
赞助商链接