概述: PnP 相关代码汇总
1. 弹出U盘
1.1. EjectVolume 弹出U盘
STDAPI_(BOOL) EjectVolume(DWORD dwVolLetter)
{
MYTRACE(L"Enter EjectVolume\n");
DWORD_PTR lrRet = 0;
HWND hWnd = FindWindow(WNDCLASS_CACHEWND, NULL);
LRESULT lr = 0;
if (NULL != hWnd)
{
lr = SendMessageTimeout(hWnd, WM_DEREGISTER_UDISK, dwVolLetter, 0, SMTO_BLOCK, 3000, &lrRet);
}
WCHAR wszVolShort[20] = {};
WCHAR szParentInstanceId[MAX_DEVICE_ID_LEN] = {};
VOLUMECOLLECTION VolCll = {};
BOOL bRet = FALSE;
BOOL bUsed = FALSE;
HANDLE hVolume = INVALID_HANDLE_VALUE;
CONFIGRET conRet = 0;
DEVINST dnDevInst = NULL;
EnableXXXPrivilege(SE_LOAD_DRIVER_NAME);
EnableXXXPrivilege(SE_UNDOCK_NAME);
bRet = GetVolumeCollection((BYTE)dwVolLetter, &VolCll, szParentInstanceId);
if (!bRet)
{
MYTRACE(L"Get volume instance id error!\n");
return FALSE;
}
StringCchPrintf(wszVolShort, ARRAYSIZE(wszVolShort), L"%c:\\", dwVolLetter);
if (!PathFileExists(wszVolShort))
{
MYTRACE(L"Not Find Volume:%c, Delete letter\n", dwVolLetter);
return TRUE;
}
// 不要直接尝试弹出
// 先判断是否占用
DWORD volumeFlags = GENERIC_READ | GENERIC_WRITE;
hVolume = CreateVolumeHandleFromDriveLetter((WCHAR)dwVolLetter,volumeFlags);
if (INVALID_HANDLE_VALUE == hVolume)
{
MYTRACE(L"ERROR! Can not open volume! Maybe it's locked\n");
return FALSE;
}
else
{
CloseHandle(hVolume);
hVolume = INVALID_HANDLE_VALUE;
}
PNP_VETO_TYPE VetoType;
bRet = CMRequestRemoveDev(dwVolLetter, szParentInstanceId, VetoType);
if (!bRet)
{
switch (VetoType)
{
case PNP_VetoTypeUnknown:
MYTRACE(L"[Eject] for unspecified reason");
break;
case PNP_VetoLegacyDevice:
MYTRACE(L"[Eject] due to legacy device");
break;
case PNP_VetoPendingClose:
MYTRACE(L"[Eject] due to pending close");
break;
case PNP_VetoWindowsApp:
MYTRACE(L"[Eject] due to windows application");
break;
case PNP_VetoWindowsService:
MYTRACE(L"[Eject] due to service");
break;
case PNP_VetoOutstandingOpen:
MYTRACE(L"[Eject] due to outstanding handles on device");
break;
case PNP_VetoDevice:
MYTRACE(L"[Eject] by device");
break;
case PNP_VetoDriver:
MYTRACE(L"[Eject] by driver");
break;
case PNP_VetoIllegalDeviceRequest:
{
MYTRACE(L"[Eject] as the request was invalid for the device");
if (EjectVolumeForce(dwVolLetter))
{
CMRequestRemoveDev(dwVolLetter, szParentInstanceId, VetoType);
bRet = TRUE;
}
}
break;
case PNP_VetoInsufficientPower:
MYTRACE(L"[Eject] because there would be insufficient system power to continue");
break;
case PNP_VetoNonDisableable:
MYTRACE(L"[Eject] due to non-disableable device");
break;
case PNP_VetoLegacyDriver:
MYTRACE(L"[Eject] due to legacy driver");
break;
case PNP_VetoInsufficientRights:
MYTRACE(L"[Eject] insufficient permissions");
break;
default:
MYTRACE(L"[Eject] due to uncoded reason");
break;
}
}
return bRet;
}1.2. GetVolumeCollection 获取设备ID
STDAPI_(BOOL) GetVolumeCollection(BYTE byVolLetter, PVOLUMECOLLECTION pVolCll, LPWSTR pParentInstId)
{
WCHAR szParentInstanceId[MAX_DEVICE_ID_LEN] = {};
WCHAR szTmpInstanceId[MAX_DEVICE_ID_LEN] ={};
WCHAR szDriveLetters[26*2*4] ={};
BOOL bRet;
DWORD cbBytesReturned;
LPWSTR pszDriveRoot = NULL;
size_t uStrlen;
pVolCll->dwCount = 0;
bRet = GetParentInstanceId(byVolLetter, szParentInstanceId, NULL, 0);
if (!bRet)
return FALSE; pszLogicalDrives);
cbBytesReturned = GetLogicalDriveStrings (ARRAYSIZE(szDriveLetters)*sizeof(WCHAR),
szDriveLetters);
for (pszDriveRoot = szDriveLetters; *pszDriveRoot != TEXT('\0');
pszDriveRoot += uStrlen + 1)
{
StringCchLength(pszDriveRoot, 26*2*4, &uStrlen);
if (((BYTE)(*pszDriveRoot) == 'A') || ((BYTE)(*pszDriveRoot) == 'a')
|| ((BYTE)(*pszDriveRoot) == 'B') || ((BYTE)(*pszDriveRoot) == 'b')) //skip floppy and the target volume
continue;
bRet = GetParentInstanceId((BYTE)(*pszDriveRoot), szTmpInstanceId, NULL, 0);
if (bRet && (StrCmpI(szParentInstanceId,szTmpInstanceId) == 0))
{
pVolCll->byVolume[pVolCll->dwCount] = (BYTE)(*pszDriveRoot);
pVolCll->dwCount++;
}
}
if (pParentInstId)
StringCchCopy(pParentInstId, MAX_DEVICE_ID_LEN, szParentInstanceId);
return TRUE;
}
BOOL GetParentInstanceId(BYTE byVolLetter,LPWSTR pParentInstId, LPWSTR pParentDevName,DWORD dwBufSize)
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
WCHAR szDeviceName[8];
STORAGE_PROPERTY_QUERY spq;
STORAGE_DEVICE_NUMBER sdn;
STORAGE_DEVICE_NUMBER sdnTmp;
BOOL bSuccess;
DWORD cbBytesReturned;
BYTE byBuffer[4096];
BOOL bRet = FALSE;
GUID *pGuidInferface = NULL;
// GUID *pGuidClass = NULL;
HDEVINFO hIntDevInfo = INVALID_HANDLE_VALUE;
DWORD dwIndex;
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA deviceInfoData;
CONFIGRET configret;
DEVINST dnDevInstParent;
WCHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN]={};
HANDLE hDev = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
StringCchPrintf(szDeviceName, ARRAYSIZE(szDeviceName), L"\\\\.\\%c:", byVolLetter);
hDevice = CreateFile (szDeviceName,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
return FALSE;
}
spq.PropertyId = StorageDeviceProperty;
spq.QueryType = PropertyStandardQuery;
spq.AdditionalParameters[0] = 0;
bSuccess = DeviceIoControl (hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&spq, sizeof(spq),
&byBuffer, sizeof(byBuffer),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
STORAGE_DEVICE_DESCRIPTOR *psdp = (STORAGE_DEVICE_DESCRIPTOR *)byBuffer;
if (!bSuccess || psdp->BusType != BusTypeUsb) //Not USB device, just return
{
CloseHandle (hDevice);
return FALSE;
}
bSuccess = DeviceIoControl (hDevice,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
(LPVOID)&sdn, sizeof(sdn),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
// GetLastError of ERROR_MORE_DATA indicates to the caller that the buffer was not large enough to accommodate the data requested
if (!bSuccess)
{
CloseHandle (hDevice);
return FALSE;
}
if (sdn.DeviceType == FILE_DEVICE_CD_ROM || sdn.DeviceType == FILE_DEVICE_DVD)
{
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_CDROM;
// pGuidClass = (GUID*)&GUID_DEVCLASS_CDROM;
}
else //if (sdn.DeviceType == FILE_DEVICE_DISK)
{
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_DISK;
// pGuidClass = (GUID*)&GUID_DEVCLASS_DISKDRIVE;
}
CloseHandle (hDevice);
hDevice = INVALID_HANDLE_VALUE;
hIntDevInfo = SetupDiGetClassDevs (pGuidInferface, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (INVALID_HANDLE_VALUE == hIntDevInfo)
return FALSE;
for (dwIndex = 0; ;dwIndex ++)
{
ZeroMemory(&interfaceData, sizeof(interfaceData));
interfaceData.cbSize = sizeof(interfaceData);
bSuccess = SetupDiEnumDeviceInterfaces (hIntDevInfo, NULL, pGuidInferface, dwIndex, &interfaceData);
if (!bSuccess) {
DWORD dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_NO_MORE_ITEMS)
break;
//else
// break; // ERROR!!!
}
cbBytesReturned = 0;
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData, NULL, 0, &cbBytesReturned, NULL);
if ((!bSuccess && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|| cbBytesReturned == 0)
continue; // ERROR!!!
if (pInterfaceDetailData)
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalFree (pInterfaceDetailData);
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc (LPTR, cbBytesReturned);
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ZeroMemory (&deviceInfoData, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(deviceInfoData);
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData,
pInterfaceDetailData, cbBytesReturned, &cbBytesReturned, &deviceInfoData);
if (!bSuccess)
continue;
hDev = CreateFile (pInterfaceDetailData->DevicePath,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hDev == INVALID_HANDLE_VALUE)
continue; //ERROR
bSuccess = DeviceIoControl (hDev,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
(LPVOID)&sdnTmp, sizeof(sdnTmp),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
CloseHandle(hDev);
if (!bSuccess)
continue;
if ((sdn.DeviceType != sdnTmp.DeviceType) || (sdn.DeviceNumber != sdnTmp.DeviceNumber))
{
continue;
}
//found the device
// MYTRACE(L"pInterfaceDetailData->DevicePath: %s", pInterfaceDetailData->DevicePath);
configret = CM_Get_Parent (&dnDevInstParent, deviceInfoData.DevInst, 0);
if (CR_SUCCESS != configret)
break;
configret = CM_Get_Device_ID (dnDevInstParent, szDeviceInstanceID, ARRAYSIZE(szDeviceInstanceID), 0);
if (CR_SUCCESS != configret)
break;
if (pParentInstId)
StringCchCopy(pParentInstId, MAX_DEVICE_ID_LEN, szDeviceInstanceID);
if (pParentDevName && dwBufSize > 8)
{
LPWSTR pDevName = pInterfaceDetailData->DevicePath;
LPWSTR pfind = StrStrI(pDevName, L"ven_");
if (pfind)
{
pDevName = pfind + 4;
pfind = StrChr(pDevName, '&');
StringCbCopyN(pParentDevName, dwBufSize, pDevName, (pfind-pDevName)*sizeof(WCHAR));
StringCbCat(pParentDevName, dwBufSize, L" ");
pDevName = pInterfaceDetailData->DevicePath;
}
pfind = StrStrI(pDevName, L"prod_");
if (pfind)
{
pDevName = pfind + 5;
pfind = StrChr(pDevName, '&');
StringCbCatN(pParentDevName, dwBufSize, pDevName, (pfind-pDevName)*sizeof(WCHAR));
}
//replace '_' with ' '
pDevName = pParentDevName;
do
{
pfind = StrChr(pDevName, '_');
if (!pfind)
break;
*pfind = ' ';
pDevName = pfind +1;
}while(1);
wcsupr(pParentDevName);
//_wcsupr_s(pParentDevName, wcslen());
}
bRet = TRUE; //Success
break;
}
if (pInterfaceDetailData)
LocalFree( pInterfaceDetailData);
if (hIntDevInfo )
SetupDiDestroyDeviceInfoList(hIntDevInfo);
return bRet;
}1.3. CMRequestRemoveDev 移除设备
BOOL CMRequestRemoveDev(DWORD dwVolLetter, WCHAR* szParentInstanceId, PNP_VETO_TYPE& VetoType)
{
DEVINST dnDevInst = NULL;
DEVINST parentDevInst = NULL;
VOLUMECOLLECTION VolCll = {};
CONFIGRET conRet = 0;
conRet = CM_Locate_DevNode(&dnDevInst, szParentInstanceId, NULL);
if (conRet == CR_SUCCESS)
{
WCHAR szVetoName[MAX_PATH] = { 0 };
MYTRACE(L"CM_Request_Device_Eject_Ex");
conRet = CM_Request_Device_Eject_Ex(dnDevInst, &VetoType, szVetoName, MAX_PATH, 0, NULL);
MYTRACE(L"CM_Request_Device_Eject_Ex ! rt:%d, VetoType:%d, info:%s", conRet, VetoType, szVetoName);
if (conRet == CR_SUCCESS)
{
MYTRACE(L"CM_Request_Device_Eject_Ex SUCCESS!\n");
return TRUE;
}
else
{
if (conRet == CR_REMOVE_VETOED && VetoType == PNP_VetoIllegalDeviceRequest)
{
conRet = CM_Query_And_Remove_SubTree(dnDevInst,
&VetoType,
szVetoName,
MAX_PATH,
// We have to add the `CM_REMOVE_NO_RESTART` flag because
// otherwise the just-removed device may be immediately
// redetected, which might happen on XP and Vista.
// See https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal
CM_REMOVE_NO_RESTART);
if (conRet == CR_SUCCESS)
{
return TRUE;
}
}
MYTRACE(L"CM_Request_Device_Eject_Ex FAILED! rt:%d, VetoType:%d, info:%s", conRet, VetoType, szVetoName);
}
}
MYTRACE(L"CM_Locate_DevNode eject %d volume(s) error!\n", VolCll.dwCount);
return FALSE;
}2. 强制弹出U盘
BOOL LockVolume(HANDLE volume)
{
DWORD bytesReturned;
for (size_t tries = 0; tries < 20; tries++)
{
if (DeviceIoControl(volume,
FSCTL_LOCK_VOLUME,
NULL, 0,
NULL, 0,
&bytesReturned,
NULL)) {
return TRUE;
}
Sleep(500);
}
return FALSE;
}
BOOL UnlockVolume(HANDLE volume)
{
DWORD bytesReturned;
return DeviceIoControl(volume,
FSCTL_UNLOCK_VOLUME,
NULL, 0,
NULL, 0,
&bytesReturned,
NULL);
}
STDAPI_(BOOL) EjectVolumeForce(DWORD dwVolLetter)
{
BOOL bRet = FALSE;
WCHAR wszVolShort[20] = {};
DWORD dwReturn = 0;
HANDLE hVolume = INVALID_HANDLE_VALUE;
StringCchPrintf(wszVolShort, ARRAYSIZE(wszVolShort), L"%c:\\", dwVolLetter);
DWORD volumeFlags = GENERIC_READ | GENERIC_WRITE;
hVolume = CreateVolumeHandleFromDriveLetter(dwVolLetter, volumeFlags);
if (hVolume == INVALID_HANDLE_VALUE)
{
MYTRACE(L"ERROR! Can not open volume!\n");
return FALSE;
}
do
{
if (DRIVE_FIXED == GetDriveType(wszVolShort))
{
MYTRACE(L"DRIVE_FIXED == GetDriveType");
ULONG deviceNumber = GetDeviceNumberFromVolumeHandle(hVolume);
if (!deviceNumber)
{
MYTRACE(L"Couldn't get device number from volume handle");
bRet = FALSE;
break;
}
if (!CloseHandle(hVolume))
{
MYTRACE(L"Couldn't close volume handle");
break;
}
MYTRACE(L"Ejecting fixed drive");
bRet = EjectFixedDriveByDeviceNumber(deviceNumber);
break;
}
if (!LockVolume(hVolume))
{
MYTRACE(L"LockVolume Failed");
break;
}
// 开始暴力弹出
if (DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwReturn, NULL))
{
DWORD dwTmp = 0;
MYTRACE(L"IOCTL_STORAGE_MEDIA_REMOVAL");
bRet = DeviceIoControl(hVolume, IOCTL_STORAGE_MEDIA_REMOVAL, &dwTmp, sizeof(dwTmp), NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_STORAGE_MEDIA_REMOVAL, bRet==%d", bRet);
bRet = DeviceIoControl(hVolume, IOCTL_DISK_EJECT_MEDIA, NULL, 0, NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_DISK_EJECT_MEDIA bRet==%d", bRet);
bRet = DeviceIoControl(hVolume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_STORAGE_EJECT_MEDIA bRet==%d", bRet);
}
if (!UnlockVolume(hVolume))
{
MYTRACE(L"UnlockVolume Failed");
break;
}
// 弹出是否成功
if (!PathFileExists(wszVolShort))
{
DeleteJunctionPoint(dwVolLetter);
bRet = TRUE;
break;
}
else
{
bRet = FALSE;
break;
}
} while (0);
if (INVALID_HANDLE_VALUE != hVolume)
{
CloseHandle(hVolume);
hVolume = INVALID_HANDLE_VALUE;
}
// 避免不生效,多调用几个
// RefreshFolderViews(CSIDL_DESKTOP, SHCNE_UPDATEDIR);
NotifyDeviceRemoval(dwVolLetter);
SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATH, wszVolShort, NULL);
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, wszVolShort, NULL);
return bRet;
}3. 弹出硬盘
// Adapted from https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal
// which is licensed under "The Code Project Open License (CPOL) 1.02"
// https://www.codeproject.com/info/cpol10.aspx
DEVINST GetDeviceInstanceFromDeviceNumber(ULONG deviceNumber)
{
const GUID* guid = reinterpret_cast<const GUID*>(&GUID_DEVINTERFACE_DISK);
// Get device interface info set handle for all devices attached to system
DWORD deviceInformationFlags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
HDEVINFO deviceInformation = SetupDiGetClassDevs(guid,
NULL, NULL,
deviceInformationFlags);
if (deviceInformation == INVALID_HANDLE_VALUE)
{
return 0;
}
DWORD memberIndex = 0;
BYTE buffer[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)buffer;
SP_DEVINFO_DATA deviceInformationData;
DWORD requiredSize;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (true)
{
if (!SetupDiEnumDeviceInterfaces(deviceInformation,
NULL,
guid,
memberIndex,
&deviceInterfaceData))
{
break;
}
requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInformation,
&deviceInterfaceData,
NULL, 0,
&requiredSize, NULL);
if (requiredSize == 0 || requiredSize > sizeof(buffer))
{
memberIndex++;
continue;
}
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ZeroMemory((PVOID)&deviceInformationData, sizeof(SP_DEVINFO_DATA));
deviceInformationData.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL result = SetupDiGetDeviceInterfaceDetail(deviceInformation,
&deviceInterfaceData,
deviceInterfaceDetailData,
sizeof(buffer),
&requiredSize,
&deviceInformationData);
if (!result) {
memberIndex++;
continue;
}
LPCTSTR devicePath = deviceInterfaceDetailData->DevicePath;
HANDLE driveHandle = CreateVolumeHandleFromDevicePath(devicePath, 0);
if (driveHandle == INVALID_HANDLE_VALUE) {
memberIndex++;
continue;
}
ULONG currentDriveDeviceNumber =
GetDeviceNumberFromVolumeHandle(driveHandle);
CloseHandle(driveHandle);
if (!currentDriveDeviceNumber) {
memberIndex++;
continue;
}
if (deviceNumber == currentDriveDeviceNumber) {
SetupDiDestroyDeviceInfoList(deviceInformation);
return deviceInformationData.DevInst;
}
memberIndex++;
}
SetupDiDestroyDeviceInfoList(deviceInformation);
return 0;
}
BOOL EjectFixedDriveByDeviceNumber(ULONG deviceNumber)
{
DEVINST deviceInstance = GetDeviceInstanceFromDeviceNumber(deviceNumber);
if (!deviceInstance)
{
MYTRACE(L"Couldn't get instance from device number");
return FALSE;
}
CONFIGRET status;
PNP_VETO_TYPE vetoType = PNP_VetoTypeUnknown;
WCHAR szVetoName[MAX_PATH];
// It's often seen that the removal fails on the first
// attempt but works on the second attempt.
// See https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal
for (size_t tries = 0; tries < 3; tries++)
{
if (tries != 0) {
MYTRACE(L"Retrying");
Sleep(500);
}
MYTRACE(L"Ejecting device instance");
status = CM_Request_Device_Eject(deviceInstance,
&vetoType,
szVetoName,
MAX_PATH,
0);
if (status == CR_SUCCESS)
{
MYTRACE(L"Ejected device instance successfully");
return TRUE;
}
MYTRACE(L"Ejecting was vetoed");
// We use this as an indicator that the device driver
// is not setting the `SurpriseRemovalOK` capability.
// See https://msdn.microsoft.com/en-us/library/windows/hardware/ff539722(v=vs.85).aspx
if (status == CR_REMOVE_VETOED &&
vetoType == PNP_VetoIllegalDeviceRequest)
{
MYTRACE(L"Removing subtree");
status = CM_Query_And_Remove_SubTree(deviceInstance,
&vetoType,
szVetoName,
MAX_PATH,
CM_REMOVE_NO_RESTART);
if (status == CR_ACCESS_DENIED) {
return FALSE;
}
if (status == CR_SUCCESS) {
return TRUE;
}
MYTRACE(L"Couldn't eject device instance");
return FALSE;
}
}
return FALSE;
}4. 获取设备数
bool GetDeviceNumber(HANDLE deviceHandle, STORAGE_DEVICE_NUMBER& deviceNumber) {
DWORD bytesReturned = 0;
BOOL result = DeviceIoControl(
deviceHandle,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,
0,
&deviceNumber,
sizeof(STORAGE_DEVICE_NUMBER),
&bytesReturned,
NULL
);
return result != 0;
}5. 获取设备ID
bool GetDeviceInstanceId(HDEVINFO deviceInfoSet, SP_DEVINFO_DATA& deviceInfoData, std::wstring& deviceInstanceId) {
WCHAR buffer[1024];
DWORD requiredSize = 0;
BOOL result = SetupDiGetDeviceInstanceIdW(
deviceInfoSet,
&deviceInfoData,
buffer,
sizeof(buffer) / sizeof(buffer[0]),
&requiredSize
);
if (result) {
deviceInstanceId = buffer;
}
return result != 0;
}