您的位置:首页 > 其它

获取磁盘列表以及磁盘信息的一些WIN32 API

2014-05-05 09:09 471 查看
转自:http://www.cnblogs.com/imlee/archive/2007/09/26/906323.html

 

1.获取所有的驱动器

利用函数

GetLogicalDriveStrings

The GetLogicalDriveStrings function fills a buffer with strings that specify valid drives in the system.

DWORD GetLogicalDriveStrings(

  DWORD nBufferLength,  // size of buffer

  LPTSTR lpBuffer       // drive strings buffer

);

很简单的一个函数,msdn有详细的说明

需要注意的一点是

lpBuffer中最后获得的数据是这样c:/<null>d:/<null><null>,每两个路径之间都间隔一个 null-terminated,

所以,如果你直接cout<<lpBuffer 的话,那么得到的是C:/,很是令人郁闷,于是要想办法把这些路径一个一个取得

所以,有了如下代码

TCHAR szBuf[100];

memset(szBuf,0,100);

DWORD len = GetLogicalDriveStrings(sizeof(szBuf)/sizeof(TCHAR),szBuf);

for (TCHAR* s = szBuf; *s; s += _tcslen(s)+1)

{

 LPCTSTR sDrivePath = s;

 cout<<sDrivePath

}

那么这个sDrivePath 就是一个一个的类似于C:/,D:/那样的字符窜

 

2.获取驱动器类型

现在获得了驱动器的路径了,如C:/,D:/

那么如何区分他们呢,

有这个函数

GetDriveType

The GetDriveType function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive.

UINT GetDriveType(

  LPCTSTR lpRootPathName   // root directory

);

UINT uDriveType = GetDriveType(sDrivePath);

调用以后,这个函数的返回值有

Value Meaning 

DRIVE_UNKNOWN                The drive type cannot be determined. 

DRIVE_NO_ROOT_DIR            The root path is invalid. For example, no volume is mounted at the path. 

DRIVE_REMOVABLE               The disk can be removed from the drive. 

DRIVE_FIXED                     The disk cannot be removed from the drive. 

DRIVE_REMOTE                 The drive is a remote (network) drive. 

DRIVE_CDROM                   The drive is a CD-ROM drive. 

DRIVE_RAMDISK               The drive is a RAM disk.

但是,靠这个函数,很多东西,都是区分不了了,比如软驱,和插入的U盘,都是DRIVE_REMOVABLE ,而硬盘和插入的移动硬盘,都是DRIVE_FIXED 

靠:(

我们一个一个来试试吧

3.获取光驱

先捏软柿子:)

UINT uDriveType = GetDriveType(sDrivePath);

if (uDriveType == DRIVE_CDROM)

{

 这个就是咯

}

要注意的是,虽然写的是DRIVE_CDROM

但是dvd 光驱也能获得(这不废话吗),另外,虚拟光驱也能获得,比如俺机器上安装了Alcohol 120%,设置的虚拟光驱也获得了

4.区分软驱和U盘

先把代码贴出来吧

#define MEDIA_INFO_SIZE    sizeof(GET_MEDIA_TYPES)+15*sizeof(DEVICE_MEDIA_INFO)

BOOL GetDriveGeometry(const TCHAR * filename, DISK_GEOMETRY * pdg)

{

 HANDLE hDevice;         // 设备句柄

 BOOL bResult;           // DeviceIoControl的返回结果

 GET_MEDIA_TYPES *pmt;   // 内部用的输出缓冲区

 DWORD dwOutBytes;       // 输出数据长度

 // 打开设备

 hDevice = ::CreateFile(filename,           // 文件名

  GENERIC_READ,                          // 软驱需要读盘

  FILE_SHARE_READ | FILE_SHARE_WRITE,    // 共享方式

  NULL,                                  // 默认的安全描述符

  OPEN_EXISTING,                         // 创建方式

  0,                                     // 不需设置文件属性

  NULL);                                 // 不需参照模板文件

 if (hDevice == INVALID_HANDLE_VALUE)

 {

  // 设备无法打开...

  return FALSE;

 }

 // 用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数

 bResult = ::DeviceIoControl(hDevice,       // 设备句柄

  IOCTL_DISK_GET_DRIVE_GEOMETRY,         // 取磁盘参数

  NULL, 0,                               // 不需要输入数据

  pdg, sizeof(DISK_GEOMETRY),            // 输出数据缓冲区

  &dwOutBytes,                           // 输出数据长度

  (LPOVERLAPPED)NULL);                   // 用同步I/O

 // 如果失败,再用IOCTL_STORAGE_GET_MEDIA_TYPES_EX取介质类型参数

 if (!bResult)

 {

  pmt = (GET_MEDIA_TYPES *)new BYTE[MEDIA_INFO_SIZE];

  bResult = ::DeviceIoControl(hDevice,    // 设备句柄

   IOCTL_STORAGE_GET_MEDIA_TYPES_EX,   // 取介质类型参数

   NULL, 0,                            // 不需要输入数据

   pmt, MEDIA_INFO_SIZE,               // 输出数据缓冲区

   &dwOutBytes,                        // 输出数据长度

   (LPOVERLAPPED)NULL);                // 用同步I/O

  if (bResult)

  {

   // 注意到结构DEVICE_MEDIA_INFO是在结构DISK_GEOMETRY的基础上扩充的

   // 为简化程序,用memcpy代替如下多条赋值语句:

   // pdg->MediaType = (MEDIA_TYPE)pmt->MediaInfo[0].DeviceSpecific.DiskInfo.MediaType;

   // pdg->Cylinders = pmt->MediaInfo[0].DeviceSpecific.DiskInfo.Cylinders;

   // pdg->TracksPerCylinder = pmt->MediaInfo[0].DeviceSpecific.DiskInfo.TracksPerCylinder;

   // ... ...

   ::memcpy(pdg, pmt->MediaInfo, sizeof(DISK_GEOMETRY));

  }

  delete pmt;

 }

 // 关闭设备句柄

 ::CloseHandle(hDevice);

 return (bResult);

}

 

然后

DISK_GEOMETRY dg;

TCHAR szPath[100] = _T("////.//");

::_tcscat(szPath,sDrivePath);

int nSize = ::_tcslen(szPath);

szPath[nSize-1] = '/0';

BOOL bRetVal = GetDriveGeometryszPath,&dg);

if(dg.MediaType == RemovableMedia)

{

   这就是U盘

}

这段代码,哇哦,好麻烦阿,好多看不懂,慢慢来

先看DISK_GEOMETRY 这个结构体

其中的MEDIA_TYPE是个枚举类型

好多阿

具体就不列出来了,可以到msdn上察看到所有的

这里有一个很重要的函数,就是::DeviceIoControl,他可以获得很多属性

第一个参数是一个handle,我们要打开一个handle

调用::CreateFile,我晕,这不创建一个文件吗:)

其实这个函数,并不象我们想像中的那样,只能创建一个传统意义上的文件哦

这里我们用它“打开”设备驱动程序,得到设备的句柄。操作完成后用CloseHandle关闭设备句柄。

这里有以下小小的变化,如果路径是选择的是驱动器,那么这个路径的格式是要

//./DeviceName

比如

//./C:

真够bt的,

所以有了

TCHAR szPath[100] = _T("////.//");

::_tcscat(szPath,sDrivePath);

int nSize = ::_tcslen(szPath);

szPath[nSize-1] = '/0';

这些代码

把C:/ => //./C:

关于::DeviceIoControl这个函数的用法,我不多说了,可以参考
http://dev.csdn.net/article/55/55510.shtm这个系列,我也是参考这个的 ^+^

当然,这段代码,关于区分软驱和U盘,还有好多可以值得商榷的地方,比如,有人提出,软驱么,都在A:的,比下路径不就得了,或者看大小1.44m

另外,软驱和U盘区分了,那么如果usb口上插的是别的东西呢,如读卡器,摄像头,怎么区分呢??

关于这个,确实还有很多值得我们去学习~~~~

4.区分移动硬盘和硬盘

我说了,移动硬盘也是DRIVE_FIXED ,真够bt的,这个没做过的话,很难想像的,太bt了

那怎么区分

用DeviceIoControl对卷下IOCTL_STORAGE_QUERY_PROPERTY进行获取信息

取返回STORAGE_DEVICE_DESCRIPTOR结构里面的STORAGE_BUS_TYPE

代码

#include <dbt.h>

#include <winioctl.h>

// IOCTL control code

#define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)

typedef enum _STORAGE_PROPERTY_ID {

  StorageDeviceProperty = 0,

  StorageAdapterProperty,

  StorageDeviceIdProperty

} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

typedef enum _STORAGE_QUERY_TYPE {

  PropertyStandardQuery = 0, 

  PropertyExistsQuery, 

  PropertyMaskQuery, 

  PropertyQueryMaxDefined 

} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

typedef struct _STORAGE_PROPERTY_QUERY {

  STORAGE_PROPERTY_ID  PropertyId;

  STORAGE_QUERY_TYPE  QueryType;

  UCHAR  AdditionalParameters[1];

} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;

 

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;

 

HANDLE hDevice;         // 设备句柄

 BOOL bResult;           // DeviceIoControl的返回结果

 // 打开设备

 hDevice = ::CreateFile(szPath,           // 文件名

  GENERIC_READ,                          // 软驱需要读盘

  FILE_SHARE_READ | FILE_SHARE_WRITE,    // 共享方式

  NULL,                                  // 默认的安全描述符

  OPEN_EXISTING,                         // 创建方式

  0,                                     // 不需设置文件属性

  NULL);

    if (hDevice == INVALID_HANDLE_VALUE)

 {

     return FALSE;

 }

 STORAGE_PROPERTY_QUERY Query; // input param for query

    DWORD dwOutBytes; // IOCTL output length

 Query.PropertyId = StorageDeviceProperty;

 Query.QueryType = PropertyStandardQuery;

 STORAGE_DEVICE_DESCRIPTOR pDevDesc;

 pDevDesc.Size = sizeof(STORAGE_DEVICE_DESCRIPTOR);

 // 用 IOCTL_STORAGE_QUERY_PROPERTY

 bResult = ::DeviceIoControl(hDevice, // device handle

     IOCTL_STORAGE_QUERY_PROPERTY, // info of device property

     &Query, sizeof(STORAGE_PROPERTY_QUERY), // input data buffer

    &pDevDesc, pDevDesc.Size, // output data buffer

     &dwOutBytes, // out's length

      (LPOVERLAPPED)NULL);

   UINT Type = pDevDesc.BusType;

//             Unknown                                                           0x00   

  //             SCSI                                                                 0x01   

  //             ATAPI                                                               0x02   

  //             ATA                                                                   0x03   

  //             IEEE1394                                                         0x04   

  //             SSA(Serial   storage   architecture)         0x05   

  //             Fibre   Channel,                                             0x06   

  //             USB,                                                                 0x07   

  //             RAID,                 0x08  

这样,就能区分USB硬盘和普通硬盘了

参考资料
http://www.codeproject.com/w2k/usbdisks.asp
文章写到这里,我又回过头去试了一下,在3.区分u盘和软驱的时候,说实话,那个办法我不是很满意,感觉有点小题大作了,搞得太复杂了,没办法,小弟实在是愚笨

其实用方法四中的查询,应该也是可以区分的,因为u盘的BusType是USB, 而软驱,我没法试了,因为机器上木有软驱

但是我相信不会是USB的,嘿嘿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: