用DeviceIoControl获取系统磁盘信息

本文介绍了一个C++程序,该程序利用Windows API函数获取物理硬盘的基本信息,包括硬盘大小、柱面数、磁盘类型等,并通过特定设备控制命令读取分区布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://www.cppblog.com/dingding/archive/2008/09/23/62570.html


代码:
#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
 SECURITY_ATTRIBUTES secStru;
 secStru.bInheritHandle=0;
 secStru.lpSecurityDescriptor=0;
 secStru.nLength=0; 
 HANDLE hDevice=CreateFile("\\\\.\\PhysicalDrive0",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);

 if(hDevice==INVALID_HANDLE_VALUE)
 {
  return -1;
 }

 //DWORD outBuff[1000];
 GET_LENGTH_INFORMATION infoStruct;

 memset(&infoStruct,0,sizeof(infoStruct));
 DWORD bytesReturned;
 if(DeviceIoControl(hDevice,IOCTL_DISK_GET_LENGTH_INFO,NULL,0,&infoStruct,sizeof(infoStruct),&bytesReturned,NULL)==0)
 {
  cout<<"Failed to get disk information."<<endl;
  DWORD error;
  error=GetLastError();
  HRESULT hRe=HRESULT_FROM_WIN32(error);
  char errorData[10];
  sprintf(errorData,"%x",hRe);
  cout<<"Error code:"<</*hRe*/errorData<<endl;
  CloseHandle(hDevice);
  return -1;
 }

 DISK_GEOMETRY_EX geoStruct;
 memset(&geoStruct,0,sizeof(geoStruct));
 if(DeviceIoControl(hDevice,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ,NULL,0,&geoStruct,sizeof(geoStruct),&bytesReturned,NULL)==0)
 {
  cout<<"Failed to get disk information."<<endl;
  DWORD error;
  error=GetLastError();
  HRESULT hRe=HRESULT_FROM_WIN32(error);
  char errorData[10];
  sprintf(errorData,"%x",hRe);
  cout<<"Error code:"<</*hRe*/errorData<<endl;
  CloseHandle(hDevice);
  return -1;
 }

 cout<<"The disk's size is:"<<infoStruct.Length.QuadPart/1024/1024/1024<<" G Bytes."<<endl;
 cout<<"The disk's cylinder number:"<<geoStruct.Geometry.Cylinders.QuadPart<<endl;
 cout<<"The disk's media type:"<<geoStruct.Geometry.MediaType<<endl;
 cout<<"Number of tracks per cylinder:"<<geoStruct.Geometry.TracksPerCylinder<<endl;
 cout<<"Number of sectors per track:"<<geoStruct.Geometry.SectorsPerTrack<<endl;
 cout<<"Number of bytes per sector:"<<geoStruct.Geometry.BytesPerSector<<endl;

 PDISK_PARTITION_INFO  partitionInfo=DiskGeometryGetPartition(&geoStruct);

 DRIVE_LAYOUT_INFORMATION_EX layOutInfo[20];

 memset(&layOutInfo,0,sizeof(DRIVE_LAYOUT_INFORMATION_EX)*20);

 //layOutInfo.PartitionEntry=*(new PARTITION_INFORMATION_EX[10]);

 if(DeviceIoControl(hDevice,IOCTL_DISK_GET_DRIVE_LAYOUT_EX,NULL,0,&layOutInfo,sizeof(DRIVE_LAYOUT_INFORMATION_EX)*20,&bytesReturned,NULL)==0)
 {
  cout<<"Failed to get disk information."<<endl;
  DWORD error;
  error=GetLastError();
  HRESULT hRe=HRESULT_FROM_WIN32(error);
  char errorData[10];
  sprintf(errorData,"%x",hRe);
  cout<<"Error code:"<</*hRe*/errorData<<endl;
  CloseHandle(hDevice);
  return -1;
 }

 int partitionCount=layOutInfo[0].PartitionCount;
 cout<<"Number of partitions:"<<layOutInfo[0].PartitionCount<<endl;
 cout<<"Partitions' information:"<<endl;
 for(int i=0;i<partitionCount;i++)
 {
  //PDISK_PARTITION_INFO pParInfo=partitionInfo+i*sizeof(DISK_PARTITION_INFO);
  if(layOutInfo[i].PartitionEntry[0].PartitionNumber!=0)
  {
   cout<<"Partition "<<layOutInfo[i].PartitionEntry[0].PartitionNumber<<",  partition size is "<<layOutInfo[i].PartitionEntry[0].PartitionLength.QuadPart/1024/1024/1024<<" G Bytes, partition style is "<<layOutInfo[i].PartitionEntry[0].PartitionStyle<<endl;
  }
 }

 //cout<<"The type of partition:"<<((partitionInfo.PartitionStyle==PARTITION_STYLE_MBR) ?"MBR":((partitionInfo.PartitionStyle==PARTITION_STYLE_GPT )?"GPT":((partitionInfo.PartitionStyle==PARTITION_STYLE_RAW)?"RAW":"")))<<endl;

 CloseHandle(hDevice);

 return 0;
}
<think>好的,用户问的是关于DeviceIoControl获取物理硬盘信息失败的问题。首先,我需要回忆一下这个函数的基本用法和常见问题。DeviceIoControl是Windows API中用来与设备驱动程序通信的函数,常用于获取硬件信息或控制设备。当用户调用这个函数失败时,可能有多种原因。 首先,权限问题。因为访问物理磁盘需要管理员权限,如果程序没有以管理员身份运行,可能会失败。这时候应该检查是否以管理员权限启动应用程序,或者在代码中请求提升权限。 其次,句柄是否正确打开。用户可能在调用CreateFile时参数有误,比如路径是否正确(比如应该是\\.\PhysicalDrive0),访问权限是否正确(GENERIC_READ或GENERIC_WRITE),共享模式是否设置为FILE_SHARE_READ | FILE_SHARE_WRITE,以及创建方式是否正确(OPEN_EXISTING)。此外,句柄关闭问题也可能导致后续操作失败。 然后是控制码是否正确。不同的操作需要不同的IOCTL码,比如获取磁盘信息常用的是IOCTL_DISK_GET_DRIVE_LAYOUT_EX等。如果控制码错误,函数会返回失败。需要确认使用的控制码是否适用于目标设备和操作。 接下来是缓冲区的问题。输入和输出缓冲区是否正确分配,大小是否足够。特别是当返回的数据结构较大时,比如有多个分区的情况,缓冲区不足会导致获取数据不完整或失败。此外,DWORD对齐问题也可能影响结果,特别是在64位系统上,需要确保结构体对齐正确。 还有驱动程序或系统兼容性问题。某些旧版本系统或驱动可能不支持特定的IOCTL,或者存在bug导致调用失败。这时候需要查阅相关文档,确认兼容性,或者更新驱动程序。 错误处理方面,用户需要检查GetLastError返回的具体错误码。比如ERROR_INVALID_FUNCTION可能表示控制码不支持,ERROR_ACCESS_DENIED是权限问题,ERROR_INSUFFICIENT_BUFFER是缓冲区不足,ERROR_NOT_SUPPORTED可能是驱动不支持该操作。根据错误码可以更快定位问题。 另外,64位系统需要注意指针精度问题,编译时应使用正确的目标平台(x64),避免32位程序在64位系统上访问高地址内存出错。还有防病毒软件或磁盘加密工具可能拦截API调用,导致失败,可以尝试临时禁用这些软件进行测试。 调试建议方面,先简化代码,确认最基本的调用流程是否成功,逐步添加功能定位问题。使用工具如WinDbg或Process Monitor跟踪系统调用,查看是否有权限拒绝或路径错误。同时参考微软的官方文档和示例代码,确保参数和用法正确。 总结下来,可能的原因包括权限不足、句柄错误、控制码错误、缓冲区问题、系统兼容性、防病毒软件干扰等。用户需要逐一排查这些方面,结合错误码和调试工具来解决问题。另外,提供示例代码可以帮助用户检查自己的实现是否有误,特别是CreateFile和DeviceIoControl的参数设置是否正确。</think>当使用Windows API中的`DeviceIoControl`函数获取物理硬盘信息失败时,可能是由多种原因导致的。以下是逐步排查和解决的思路: --- ### **1. 权限问题** - **现象**:调用`CreateFile`打开物理磁盘句柄时返回`INVALID_HANDLE_VALUE`。 - **原因**:访问物理磁盘(如`\\.\PhysicalDrive0`)需要管理员权限。 - **解决方案**: - 以管理员身份运行程序。 - 在代码中请求提升权限(通过清单文件添加`<requestedExecutionLevel level="requireAdministrator"/>`)。 --- ### **2. 错误的句柄操作** - **现象**:`DeviceIoControl`返回`FALSE`,`GetLastError`显示`ERROR_INVALID_HANDLE`。 - **可能原因**: - `CreateFile`参数错误: ```c // 正确示例:打开第一个物理磁盘 HANDLE hDevice = CreateFile( L"\\\\.\\PhysicalDrive0", // 路径 GENERIC_READ, // 访问权限 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享模式 NULL, // 安全属性 OPEN_EXISTING, // 创建方式 0, // 标志 NULL ); ``` - 未正确关闭句柄。 - **解决方案**:检查`CreateFile`参数和句柄生命周期。 --- ### **3. 错误的控制码(IOCTL)** - **现象**:`DeviceIoControl`返回`FALSE`,错误码为`ERROR_INVALID_FUNCTION`(1)。 - **原因**:使用了不支持的IOCTL代码。 - **常见IOCTL码**: - 获取磁盘信息:`IOCTL_DISK_GET_DRIVE_LAYOUT_EX` - 获取磁盘属性:`IOCTL_DISK_GET_DRIVE_GEOMETRY` - **解决方案**:确认IOCTL码是否适用于物理磁盘设备。 --- ### **4. 缓冲区问题** - **现象**:错误码为`ERROR_INSUFFICIENT_BUFFER`(122)或数据损坏。 - **原因**: - 输出缓冲区大小不足(例如分区表信息过长)。 - 缓冲区未按DWORD对齐(某些IOCTL需要对齐)。 - **解决方案**: - 动态分配足够大的缓冲区。 - 使用`VirtualAlloc`确保内存对齐: ```c LPVOID buffer = VirtualAlloc(NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE); ``` --- ### **5. 驱动程序或系统兼容性问题** - **现象**:在特定系统版本或硬件上失败。 - **可能原因**: - 旧版Windows不支持某些IOCTL。 - 磁盘驱动程序未正确处理请求。 - **解决方案**: - 查阅[微软文档](https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol)确认IOCTL兼容性。 - 更新磁盘驱动程序。 --- ### **6. 错误码分析** 通过`GetLastError()`获取具体错误码: - **`ERROR_ACCESS_DENIED`(5)**:权限不足。 - **`ERROR_NOT_SUPPORTED`(50)**:设备不支持此操作。 - **`ERROR_INVALID_PARAMETER`(87)**:输入参数错误。 --- ### **7. 防病毒/磁盘加密软件干扰** - **现象**:在特定环境下失败。 - **原因**:第三方软件可能拦截磁盘访问。 - **解决方案**:临时禁用安全软件测试。 --- ### **8. 64位系统注意事项** - 编译程序时需选择**x64平台**,避免32位程序访问物理地址空间受限。 --- ### **调试建议** 1. **简化代码**:仅保留`CreateFile`和`DeviceIoControl`调用,逐步验证。 2. **使用WinDbg**:通过内核调试跟踪IRP请求。 3. **参考示例代码**:微软官方示例[PhysicalDisk.cpp](https://github.com/microsoft/Windows-classic-samples)提供参考实现。 --- ### **示例代码片段** ```c #include <windows.h> #include <stdio.h> int main() { HANDLE hDevice = CreateFile( L"\\\\.\\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hDevice == INVALID_HANDLE_VALUE) { printf("CreateFile failed, Error: %d\n", GetLastError()); return 1; } DISK_GEOMETRY_EX diskGeometry = {0}; DWORD bytesReturned = 0; BOOL result = DeviceIoControl( hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &diskGeometry, sizeof(diskGeometry), &bytesReturned, NULL ); if (!result) { printf("DeviceIoControl failed, Error: %d\n", GetLastError()); CloseHandle(hDevice); return 1; } printf("Disk Size: %llu bytes\n", diskGeometry.DiskSize.QuadPart); CloseHandle(hDevice); return 0; } ``` --- 通过逐步检查权限、句柄、IOCTL码、缓冲区和系统兼容性,结合错误码分析,通常可以定位问题根源。若仍无法解决,建议提供具体的错误码和代码片段进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值