WEB开发网
开发学院软件开发汇编语言 实战DeviceIoControl之五:列举已安装的存储设备 阅读

实战DeviceIoControl之五:列举已安装的存储设备

 2010-01-10 09:37:27 来源:WEB开发网   
核心提示:Q 前几次我们讨论的都是设备名比较清楚的情况,有了设备名(路径),实战DeviceIoControl之五:列举已安装的存储设备,就可以直接调用CreateFile打开设备,进行它所支持的I/O操作了,可能不止1个int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath

Q 前几次我们讨论的都是设备名比较清楚的情况,有了设备名(路径),就可以直接调用CreateFile打开设备,进行它所支持的I/O操作了。如果事先并不能确切知道设备名,如何去访问设备呢?

A 访问设备必须用设备句柄,而得到设备句柄必须知道设备路径,这个套路以你我之力是改变不了的。每 个设备都有它所属类型的GUID,我们顺着这个GUID就能获得设备路径。 GUID是同类或同种设备的全球唯一识别码,它是一个128 bit(16字节)的整形数,真实面目为

typedef struct _GUID
{
 unsigned long  Data1;
 unsigned short Data2;
 unsigned short Data3;
 unsigned char  Data4[8];
} GUID, *PGUID;
例如, Disk类的GUID为“53f56307-b6bf-11d0-94f2-00a0c91efb8b”,在我们的程序里可以定义为

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];

1 2 3  下一页

Tags:实战 DeviceIoControl 列举

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接