1.判断磁盘的类型
if (GetDriveType(szRootPathName) != DRIVE_REMOVABLE)
{
m_csErrorMsg.Format(_T(“该磁盘不是可移动磁盘”));
}
csLogicDisk.Format(_T("\\\\.\\%c:"), csDiskSymbol[0]);
HANDLE hVolume = CreateFile(csLogicDisk, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if (hVolume == INVALID_HANDLE_VALUE)
{
return false;
}
2.通过DeviceIoControl获取设备根据盘符得到第一个STORAGE_DEVICE_NUMBER --> sdnDiskDeviceNum
if (!DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdnDiskDeviceNum, sizeof(sdnDiskDeviceNum), &dwBytesReturned, NULL))
{
return false;
}
3.枚举磁盘设备,GUID_DEVINTERFACE_DISK,
依次用到
SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail
—HDEVINFO hDevInfo = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
—SetupDiEnumDeviceInterfaces(hDevInfo, NULL, pGuid, index, &DevInterfaceData)
—SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, pDevInterfaceDetailData, dwRequiredSize, &dwRequiredSize, &DevInfoData)
4.再次调用CreateFile,这次的文件名是来自于SetupDiGetDeviceInterfaceDetail返回的buffer的path
HANDLE hDrive = CreateFile(pDevInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
5.通过DeviceIoControl获取设备根据盘符得到第二个STORAGE_DEVICE_NUMBER --> sdnDeviceInfoByEnumDevice
DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,
0,
&sdnDeviceInfoByEnumDevice,
sizeof(sdnDeviceInfoByEnumDevice),
&dwBytesReturned2,
NULL
)
6.比较两个STORAGE_DEVICE_NUMBER是否相同
typedef struct _STORAGE_DEVICE_NUMBER {
DEVICE_TYPE DeviceType;
ULONG DeviceNumber;
ULONG PartitionNumber;
} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
比较前面的两个成员就可以了,第三个成员可能不一样,前面两个成员就可以确定是同一个设备了.
7.获取ID
DWORD dwInstanceParent = 0;
CM_Get_Parent(&dwInstanceParent, dwInstance, 0);
WCHAR buffer[256] = { 0 };
CM_Get_Device_ID(dwInstanceParent, buffer, sizeof(buffer), 0); // 得到设备ID,如 USB\VID_17EF&PID_3801\907117000F7F
参数dwInstance来自与枚举设备的时候找到相同设备时SP_DEVINFO_DATA这个结构里面的 DevInst成员
获取到的ID像这样的 : USB\VID_17EF&PID_3801\907117000F7F
对应 设备管理器->USB大容量存储设备->详细信息->设备实例路径
下面是整个实现的函数,传入盘符,得到设备实例路径,粗略实测是有效的,
//需要的头文件等:
#include “stdafx.h”
#include <setupapi.h> //SetupDi系列函数
#include <winioctl.h>
#include <cfgmgr32.h>
#pragma comment(lib, “setupapi.lib”)
static GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10L, 0x6530, 0x11D2,{ 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
//<usbiodef.h>里面有,不包含头文件时直接自己写一个
// 功能:通过U盘盘符得到U盘的ID 包含pid, vid
// 入口参数:
// [out] csDeviceID:设备ID信息, 如 USB\VID_17EF&PID_3801\907117000F7F
// [in] csDiskSymbol:可移动设备的盘符 单个字母 如 H
// 返回值:
// 成功返回true
// 失败返回false
bool GetDiskDeviceIDBySymbol(CString csDiskSymbol, CString& csDeviceID)
{
CString m_csErrorMsg;
//判断该盘符对应的磁盘类型
WCHAR szRootPathName[] = _T("X:\\");
szRootPathName[0] = csDiskSymbol[0];
UINT uDriveType = GetDriveType(szRootPathName);
if (uDriveType != DRIVE_REMOVABLE)
{
m_csErrorMsg.Format(_T("该磁盘不是可移动磁盘"));
return false;
}
//得到设备的文件名 如 \\.\X:
WCHAR szDeviceName[] = _T("X:"); // "X:"
szDeviceName[0] = csDiskSymbol[0];
CString csLogicDisk;
csLogicDisk.Format(_T("\\\\.\\%c:"), csDiskSymbol[0]);
HANDLE hVolume = CreateFile(csLogicDisk, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if (hVolume == INVALID_HANDLE_VALUE)
{
m_csErrorMsg.Format(_T("CreateFile fail, error code:%d"), GetLastError());
return false;
}
//通过DeviceIoControl获取设备的STORAGE_DEVICE_NUMBER
STORAGE_DEVICE_NUMBER sdnDiskDeviceNum; //包含有关设备的信息。
DWORD dwBytesReturned = 0;
if (!DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdnDiskDeviceNum, sizeof(sdnDiskDeviceNum), &dwBytesReturned, NULL))
{
m_csErrorMsg.Format(_T("DeviceIoControl fail, error code:%d"), GetLastError());
return false;
}
CloseHandle(hVolume);
if (sdnDiskDeviceNum.DeviceNumber == -1)
{
m_csErrorMsg.Format(_T("DeviceNumber = -1, error code:%d"), GetLastError());
return false;
}
//
//已根据盘符得到设备的STORAGE_DEVICE_NUMBER,然后枚举USB设备,找到相同的STORAGE_DEVICE_NUMBER的设备, (只需比较DeviceNumber和DeviceType)
const GUID* pGuid = &GUID_DEVINTERFACE_DISK; //GUID_DEVINTERFACE_DISK GUID_DEVINTERFACE_USB_DEVICE
HDEVINFO hDevInfo = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
m_csErrorMsg.Format(_T("SetupDiGetClassDevs, error code:%d"), GetLastError());
return false;
}
SP_DEVINFO_DATA DevInfoData;
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
SP_DEVICE_INTERFACE_DATA DevInterfaceData;
DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevInterfaceDetailData = NULL; //SetupDiGetDeviceInterfaceDetail用于存放信息,需要根据实际大小动态分配
DWORD dwRequiredSize = 0; //保存SetupDiGetDeviceInterfaceDetail返回的实际需要的缓存区大小
DWORD dwInstance = 0; //设备Instance
//枚举所有设备
DWORD index = 0;
while (SetupDiEnumDeviceInterfaces(hDevInfo, NULL, pGuid, index, &DevInterfaceData))
{
//先直接调用函数,目的是获取第一个设备所需要的缓存区大小dwRequiredSize;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, NULL, 0, &dwRequiredSize, &DevInfoData);
//得到大小后分配内存
pDevInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(dwRequiredSize);
pDevInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//再次调用获取信息
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, pDevInterfaceDetailData, dwRequiredSize, &dwRequiredSize, &DevInfoData))
{
m_csErrorMsg.Format(_T("SetupDiGetDeviceInterfaceDetail, error code:%d"), GetLastError());
free(pDevInterfaceDetailData);
SetupDiDestroyDeviceInfoList(hDevInfo);
return false;
}
HANDLE hDrive = CreateFile(pDevInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDrive == INVALID_HANDLE_VALUE)
{
m_csErrorMsg.Format(_T("CreateFile INVALID_HANDLE_VALUE, error code:%d"), GetLastError());
free(pDevInterfaceDetailData);
SetupDiDestroyDeviceInfoList(hDevInfo);
return false;
}
STORAGE_DEVICE_NUMBER sdnDeviceInfoByEnumDevice; //每次枚举时获取的设备信息
DWORD dwBytesReturned2 = 0;
if (DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,
0,
&sdnDeviceInfoByEnumDevice,
sizeof(sdnDeviceInfoByEnumDevice),
&dwBytesReturned2,
NULL
))
{
// 比较由盘符获取的DeviceNumber,DeviceType与枚举时获取的DeviceNumber,DeviceType,相同则说明盘符对应此USB设备
if (sdnDiskDeviceNum.DeviceNumber == sdnDeviceInfoByEnumDevice.DeviceNumber &&
sdnDiskDeviceNum.DeviceType == sdnDeviceInfoByEnumDevice.DeviceType)
{
dwInstance = DevInfoData.DevInst;
}
}
free(pDevInterfaceDetailData);
CloseHandle(hDrive);
++index;
}
if (index == 0)
{
m_csErrorMsg.Format(_T("SetupDiEnumDeviceInterfaces, error code:%d"), GetLastError());
SetupDiDestroyDeviceInfoList(hDevInfo);
return false;
}
m_csErrorMsg.Format(_T("SetupDiEnumDeviceInterfaces, error code:%d"), GetLastError());
//获取InstanceParent
DWORD dwInstanceParent = 0;
CM_Get_Parent(&dwInstanceParent, dwInstance, 0);
WCHAR buffer[256] = { 0 };
CM_Get_Device_ID(dwInstanceParent, buffer, sizeof(buffer), 0); // 得到设备ID,如 USB\VID_17EF&PID_3801\907117000F7F
SetupDiDestroyDeviceInfoList(hDevInfo);
csDeviceID.Format(_T("%s"), buffer); //找到的设备的ID, 我也不知道有没有可能两个设备这个ID是相同的
csDeviceID.MakeUpper();
return true;
}