标 题:
【原创】获取设备范例ID
作 者: downres
时 间: 2011-07-14,14:21:36
链 接: http://bbs.pediy.com/showthread.php?t=137138
近来正好在学习磁盘过滤驱动相关的知识,有一需求需要得到与磁盘分别对应的设备范例ID号,如上图所示,可以看出来windows的设备管理器找到了这种对应的关联,不同的磁盘对应着不同的设备范例ID。于是我就尝识了下去获得这个设备范例ID。百度了下收集了点资料,自己把方法总结了下大概有两种。
方法一、向磁盘设备发送IOCTL_STORAGE_QUERY_PROPERTY,这样将返回这样的一个结构体
typedef struct _STORAGE_DEVICE_DESCRIPTOR { ULONG Version; ULONG Size; UCHAR DeviceType; UCHAR DeviceTypeModifier; BOOLEAN RemovableMedia; BOOLEAN CommandQueueing; ULONG VendorIdOffset; ULONG ProductIdOffset; ULONG ProductRevisionOffset; ULONG SerialNumberOffset; STORAGE_BUS_TYPE BusType; ULONG RawPropertiesLength; UCHAR RawDeviceProperties[1];} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
利用返回的信息、自已组合得到设备范例ID,至此也说明是一种对应关系。
方法二、可以通过SetupApi系列API进行获取。于是翻了下MSDN,查询了下SetupApi系列。大概实现的思路就是利用SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_DISK,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)枚举磁盘设备信息,然后利用SetupDiEnumDeviceInterfaces(hdevInfo, NULL, (LPGUID)&GUID_DEVINTERFACE_DISK, ndx, &devInfData)枚举磁盘设备,然后对磁盘设备调用SetupDiGetDeviceInterfaceDetail(hdevInfo, &devIntfData, NULL, 0, &reqSize, NULL),得到磁盘设备路径,向该设备发送IOCTL_STORAGE_GET_DEVICE_NUMBER,可以得到磁盘的设备号,至此也就说明了两者是一种对应关系了。
还有一种方法,我黑盒分析了下,发现windows的设备管理器,在你点击对应磁盘选属性的时候是MMC向WMIDataDevice,发送0x224004,会得到的该设备范例ID,写了测试代码没有实现。
方法一代码简单,只是要自己组装,而且不能完全组装出完整设备范例ID。
方法二实现的代码如下(细节没有处理,误拍砖,只是说明可以实现):
#include
#include
#include
#include
#include
#pragma comment(lib, "setupapi.lib")
DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
/************************************************************************/
/*
Function: GetDiskIdNumber()
Parameters: CHAR*
Description: 获取磁盘的ID
Date: 2011-07-13
Author: By EvilMind
*/
/************************************************************************/
ULONG GetDiskIdNumber(CHAR* szPath)
{
HANDLE hDevice = CreateFile(szPath,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
STORAGE_DEVICE_NUMBER storageDeviceNumber2;
DWORD dwByteReturned = 0;
if (DeviceIoControl(hDevice,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,
0,
&storageDeviceNumber2,
(DWORD)
sizeof(STORAGE_DEVICE_NUMBER),
&dwByteReturned,
NULL))
{
//printf("%d", storageDeviceNumber2.DeviceNumber);
return storageDeviceNumber2.DeviceNumber;
}
}
CloseHandle(hDevice);
return -1;
}
/************************************************************************/
/*
Function: GetDiskInstancePath()
Parameters: CHAR*, CHAR* szDisk
Description: 获取目标磁盘的实例ID
Date: 2011-07-13
Author: By EvilMind
*/
/************************************************************************/
BOOL GetDiskInstancePath(CHAR *szInstancePath, CHAR *szTargetDisk)
{
//
// 利用SetupApi枚举得到各设备的实例ID.
// 获取枚举后得到各设备的磁盘ID,与目标磁盘的
// 磁盘ID对比,如果相等,则为目标磁盘的实例ID
//
HDEVINFO hdevInfo;
HRESULT hr;
SP_DEVICE_INTERFACE_DATA devIntfData;
DWORD dwTargetId = GetDiskIdNumber(szTargetDisk);
hdevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_DISK,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
hr = (hdevInfo != INVALID_HANDLE_VALUE) ? S_OK : E_UNEXPECTED;
for (DWORD ndx = 0; SUCCEEDED(hr); ndx++)
{
ZeroMemory(&devIntfData,
sizeof(devIntfData));
devIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
hr = (SetupDiEnumDeviceInterfaces(hdevInfo,
NULL,
(LPGUID)&GUID_DEVINTERFACE_DISK,
ndx,
&devIntfData)) ? S_OK : E_UNEXPECTED;
if (SUCCEEDED(hr))
{
DWORD reqSize = 0;
//
// 获取实际的所需的内存大小
//
hr = (SetupDiGetDeviceInterfaceDetail(hdevInfo,
&devIntfData,
NULL,
0,
&reqSize,
NULL)) ? E_UNEXPECTED : ERROR_INSUFFICIENT_BUFFER;
//
// 获取实例ID
//
if (hr == ERROR_INSUFFICIENT_BUFFER)
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pDiDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, reqSize);
hr = (pDiDetail != NULL) ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
pDiDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA devInfoData;
ZeroMemory(&devInfoData,
sizeof(devInfoData));
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiGetDeviceInterfaceDetail(hdevInfo,
&devIntfData,
pDiDetail,
reqSize,
NULL,
&devInfoData))
{
if (dwTargetId == GetDiskIdNumber(pDiDetail->DevicePath))
{
printf("disk %s path is %s", szTargetDisk, pDiDetail->DevicePath);
}
}
}
}
}
}
return TRUE;
}
void main()
{
GetDiskInstancePath(NULL, "\\\\.\\PhysicalDrive0");
GetDiskInstancePath(NULL, "\\\\.\\PhysicalDrive1");
GetDiskInstancePath(NULL, "\\\\.\\PhysicalDrive2");
}
代码没什么技术含量,小菜只有疑问望高手解答下:
如图二所示,我用WINDBG查看了下信息,对比devicetree,当然实际上只用windbg就能获取足够信息了,我看到这个设备实际上是atapi的一个设备。这是为什么呢?为什么不是disk的设备呢?
如图三所示,从图三看信息推论,设备应该是DISK的啊,但实事上就是如1所述为atapi的设备,设备范例ID有什么用呢?
希望我准确的表达了我想问的问题,希望高手解答下小菜的疑问。