关于IOCTL_STORAGE_QUERY_PROPERTY控制码在Vista下的一个奇怪问题

本文介绍了在Visual Studio 2008环境下使用 IOCTL_STORAGE_QUERY_PROPERTY 控制码进行存储设备查询时遇到的问题及解决办法,并讨论了在不同操作系统上出现的数据结构变化情况。

众所周知,IOCTL_STORAGE_QUERY_PROPERTY控制码是用于列举系统中已安装的存储设备,在通过CreateFile打开设备后,通常的调用方式如下:

这段代码在VC 6.0中运行没有问题,但是当移植到VS 2008中运行时,DeviceIoControl将失败,返回错误代码为ERROR_BAD_LENGTH,令人百思不得其解,查了MSDN也没提到这样的问题,只好自己动手实验,结果发现把sizeof(query)这个参数加上3以上的数的时候,在Vista+VS 2008的平台上运行就正常了,具体原因为何会这样,还需要进一步的研究。

 

[后续研究]

2010年4月,我们发现在Vista/Win 7等系统中,VS 2008编译的版本会导致采用这种方法获取到硬盘的某个数据结构发生变化,主要是DISK_INT13_INFO这个结构,原本应该记录在SectorsPerTrack中的数据跑到了MaxHeads中,根据测试的情况,可能是MS修改了数据结构但是没有改头文件,如果真是这样,真的让人很无语啊。

以下代码有没有问题: // 功能:通过U盘盘符得到U盘的ID 包含pid, vid // 入口参数: // [out] csDeviceID:设备ID信息, 如 USB\VID_17EF&PID_3801\907117000F7F // [in] csDiskSymbol:可移动设备的盘符 单个字母 如 H // 返回值: // 成功返回true // 失败返回false BOOL GetDiskDeviceIDBySymbol(PCHAR csDiskSymbol, PCHAR csDeviceID) { //判断该盘符对应的磁盘类型 //WriteLog("csDiskSymbol1", FALSE); //WriteLog(csDiskSymbol, TRUE); HANDLE hVolume = CreateFile(csDiskSymbol, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); if (hVolume == INVALID_HANDLE_VALUE) { return FALSE; } //WriteLog("csDiskSymbol2", FALSE); //WriteLog(csDiskSymbol, TRUE); //通过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) { return FALSE; } //WriteLog("csDiskSymbol3", FALSE); //WriteLog(csDiskSymbol, TRUE); // //已根据盘符得到设备的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 //WriteLog("csDiskSymbol4", FALSE); //WriteLog(csDiskSymbol, TRUE); //枚举所有设备 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; } //WriteLog("csDiskSymbol5", FALSE); //WriteLog(csDiskSymbol, TRUE); 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); sprintf(csDeviceID, "%s", buffer); //csDeviceID.Format(_T("%s"), buffer); //找到的设备的ID, 我也不知道有没有可能两个设备这个ID是相同的 //csDeviceID.MakeUpper(); //WriteLog("csDiskSymbol6", FALSE); //WriteLog(csDiskSymbol, TRUE); return TRUE; }
最新发布
11-06
2025-10-28 10:20:53 [INFO] 可靠SMART数据应用程序初始化完成 - 版本 6.3 2025-10-28 10:20:53 [INFO] 界面初始化完成 2025-10-28 10:20:53 [INFO] 开始真实SMART数据扫描 2025-10-28 10:20:53 [INFO] 开始可靠SMART数据磁盘扫描 2025-10-28 10:20:53 [INFO] 处理磁盘 1: Samsung SSD 980 PRO 2TB 2025-10-28 10:20:53 [INFO] WMI找到盘符: C: 对于磁盘 1 2025-10-28 10:20:53 [INFO] WMI找到盘符: D: 对于磁盘 1 2025-10-28 10:20:54 [INFO] WMI找到卷名: C:[无卷名] 对于磁盘 1 2025-10-28 10:20:54 [INFO] WMI找到卷名: D:[无卷名] 对于磁盘 1 2025-10-28 10:20:54 [INFO] WMI找到卷名: C:[无卷名] 对于磁盘 1 2025-10-28 10:20:54 [INFO] WMI找到卷名: D:[无卷名] 对于磁盘 1 2025-10-28 10:20:54 [INFO] 成功读取磁盘 1 的基本信息 2025-10-28 10:20:54 [INFO] 尝试获取磁盘 1 的可靠SMART数据 2025-10-28 10:20:54 [ERROR] ParseVendorSpecificData 错误: 类型不匹配 2025-10-28 10:20:55 [INFO] 设置基本预测数据属性 2025-10-28 10:20:55 [INFO] 从MSStorageDriver_FailurePredictData成功解析预测数据 2025-10-28 10:20:55 [INFO] 改进WMI方法成功获取磁盘 1 的SMART数据 2025-10-28 10:20:55 [INFO] 添加有效磁盘: Samsung SSD 980 PRO 2TB (编号: 1) 2025-10-28 10:20:55 [INFO] 处理磁盘 0: ST4000DM004-2CV104 2025-10-28 10:20:55 [INFO] WMI找到盘符: E: 对于磁盘 0 2025-10-28 10:20:56 [INFO] WMI找到卷名: E:[新加卷] 对于磁盘 0 2025-10-28 10:20:56 [INFO] WMI找到卷名: E:[新加卷] 对于磁盘 0 2025-10-28 10:20:56 [INFO] 成功读取磁盘 0 的基本信息 2025-10-28 10:20:56 [INFO] 尝试获取磁盘 0 的可靠SMART数据 2025-10-28 10:20:56 [ERROR] ParseVendorSpecificData 错误: 类型不匹配 2025-10-28 10:20:56 [INFO] 设置基本预测数据属性 2025-10-28 10:20:56 [INFO] 从MSStorageDriver_FailurePredictData成功解析预测数据 2025-10-28 10:20:56 [INFO] 改进WMI方法成功获取磁盘 0 的SMART数据 2025-10-28 10:20:56 [INFO] 添加有效磁盘: ST4000DM004-2CV104 (编号: 0) 2025-10-28 10:20:56 [INFO] 处理磁盘 2: Seagate Expansion SCSI Disk Device 2025-10-28 10:20:57 [INFO] WMI找到盘符: G: 对于磁盘 2 2025-10-28 10:20:57 [INFO] WMI找到盘符: H: 对于磁盘 2 2025-10-28 10:20:57 [INFO] WMI找到卷名: G:[SHINE] 对于磁盘 2 2025-10-28 10:20:57 [INFO] WMI找到卷名: H:[新加卷] 对于磁盘 2 2025-10-28 10:20:57 [INFO] WMI找到卷名: G:[SHINE] 对于磁盘 2 2025-10-28 10:20:57 [INFO] WMI找到卷名: H:[新加卷] 对于磁盘 2 2025-10-28 10:20:57 [INFO] 成功读取磁盘 2 的基本信息 2025-10-28 10:20:57 [INFO] 通过可移动属性检测到USB设备: Seagate Expansion SCSI Disk Device 2025-10-28 10:20:57 [INFO] 过滤USB设备: Seagate Expansion SCSI Disk Device (编号: 2) 2025-10-28 10:20:57 [INFO] 扫描完成: 2 个有效磁盘, 1 个USB设备, 0 个虚拟设备 2025-10-28 10:20:57 [INFO] SMART扫描完成,发现 2 个有效的物理磁盘 2025-10-28 10:21:00 [INFO] 用户选择磁盘 0 2025-10-28 10:21:01 [INFO] WMI找到盘符: E: 对于磁盘 0 2025-10-28 10:21:01 [INFO] WMI找到卷名: E:[新加卷] 对于磁盘 0 2025-10-28 10:21:01 [INFO] WMI找到卷名: E:[新加卷] 对于磁盘 0 2025-10-28 10:21:01 [INFO] 成功读取磁盘 0 的基本信息 2025-10-28 10:21:01 [INFO] 成功重新加载磁盘 0 的详细信息 2025-10-28 10:21:01 [INFO] 开始检测磁盘 0 的真实SMART健康状态 2025-10-28 10:21:01 [INFO] 磁盘 0 的真实SMART健康状态检测成功 2025-10-28 10:21:02 [INFO] 用户选择磁盘 1 2025-10-28 10:21:03 [INFO] WMI找到盘符: C: 对于磁盘 1 2025-10-28 10:21:03 [INFO] WMI找到盘符: D: 对于磁盘 1 2025-10-28 10:21:03 [INFO] WMI找到卷名: C:[无卷名] 对于磁盘 1 2025-10-28 10:21:03 [INFO] WMI找到卷名: D:[无卷名] 对于磁盘 1 2025-10-28 10:21:04 [INFO] WMI找到卷名: C:[无卷名] 对于磁盘 1 2025-10-28 10:21:04 [INFO] WMI找到卷名: D:[无卷名] 对于磁盘 1 2025-10-28 10:21:04 [INFO] 成功读取磁盘 1 的基本信息 2025-10-28 10:21:04 [INFO] 成功重新加载磁盘 1 的详细信息 2025-10-28 10:21:04 [INFO] 开始检测磁盘 1 的真实SMART健康状态 2025-10-28 10:21:04 [INFO] 磁盘 1 的真实SMART健康状态检测成功 VB6我只想要硬盘健康数据,上面代码怎么获取不到真实的数据,不知道问题在那里
10-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值