`

【DeviceIOControl】 二、获取软盘/硬盘/光盘的参数

阅读更多
在上面那个例子中,将设备名换成“A:”取A盘参数,先用资源管理器读一下盘,再运行这个程序可以成功,但换一张盘后就失败;换成“CDROM0”取CDROM参数,无论如何都不行。这个问题如何解决呢?

取软盘参数是从软盘上读取格式化后的信息,也就是必须执行读操作,这一点与硬盘不同。将CreateFile中的访问方式改为GENERIC_READ就行了。IOCTL_DISK_GET_DRIVE_GEOMETRY这个I/O控制码,对软盘和硬盘有效,但对一些可移动媒介如CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数,还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问题。

DeviceIoControl使用这两个控制码时,都不需要输入数据。IOCTL_DISK_GET_DRIVE_GEOMETRY直接输出一个DISK_GEOMETRY结构:

typedef struct _DISK_GEOMETRY { 
    LARGE_INTEGER    Cylinders; // 柱面数 
    MEDIA_TYPE    MediaType;    // 介质类型
    DWORD    TracksPerCylinder;    // 每柱面的磁道数
    DWORD    SectorsPerTrack;         // 每磁道的扇区数
    DWORD    BytesPerSector;    // 每扇区的字节数
} DISK_GEOMETRY; 

IOCTL_STORAGE_GET_MEDIA_TYPES_EX输出一个GET_MEDIA_TYPES结构:

typedef struct _GET_MEDIA_TYPES {
    DWORD DeviceType;     // 设备类型
    DWORD MediaInfoCount;     // 介质信息条数
    DEVICE_MEDIA_INFO MediaInfo[1]; // 介质信息
} GET_MEDIA_TYPES;


让我们来看一下DEVICE_MEDIA_INFO结构的定义:
typedef struct _DEVICE_MEDIA_INFO {
      union {
          struct {
              LARGE_INTEGER Cylinders;    // 柱面数 
              STORAGE_MEDIA_TYPE MediaType;    // 介质类型
              DWORD TracksPerCylinder;     // 每柱面的磁道数
              DWORD SectorsPerTrack;    // 每磁道的扇区数
              DWORD BytesPerSector;     // 每扇区的字节数
              DWORD NumberMediaSides;    // 介质面数
              DWORD MediaCharacteristics;    // 介质特性
          } DiskInfo;      // 硬盘信息
          struct {
              LARGE_INTEGER Cylinders;    // 柱面数
              STORAGE_MEDIA_TYPE MediaType;    // 介质类型
              DWORD TracksPerCylinder;     // 每柱面的磁道数
              DWORD SectorsPerTrack;    // 每磁道的扇区数
              DWORD BytesPerSector;     // 每扇区的字节数
              DWORD NumberMediaSides;    // 介质面数
              DWORD MediaCharacteristics;    // 介质特性
          } RemovableDiskInfo;     // “可移动盘”信息
          struct {
              STORAGE_MEDIA_TYPE MediaType;    // 介质类型
              DWORD     MediaCharacteristics;    // 介质特性
              DWORD     CurrentBlockSize;     // 块的大小
          } TapeInfo;      // 磁带信息
      } DeviceSpecific;
} DEVICE_MEDIA_INFO;


其中CD-ROM属于“可移动盘”的范围。请注意,GET_MEDIA_TYPES结构本身只定义了一条DEVICE_MEDIA_INFO,额外的DEVICE_MEDIA_INFO需要紧接此结构的另外的空间。


现在就演示一下如何取软盘/硬盘/光盘的参数。测试时,记得要有软盘/光盘插在驱动器里喔!

首先,用MFC AppWizard生成一个单文档的应用程序,取名为DiskGeometry,让它的View基于CEditView。
然后,添加以下的.h和.cpp文件。
//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.h
//////////////////////////////////////////////////////////////////////////////

#if !defined(GET_DISK_GEOMETRY_H__)
#define GET_DISK_GEOMETRY_H__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <winioctl.h>

BOOL GetDriveGeometry(const char* filename, DISK_GEOMETRY *pdg);

#endif // !defined(GET_DISK_GEOMETRY_H__)


//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.cpp
//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "GetDiskGeometry.h"

// IOCTL_STORAGE_GET_MEDIA_TYPES_EX可能返回不止一条DEVICE_MEDIA_INFO,故定义足够的空间
#define MEDIA_INFO_SIZE    sizeof(GET_MEDIA_TYPES)+15*sizeof(DEVICE_MEDIA_INFO)

// filename -- 用于设备的文件名
// pdg -- 参数缓冲区指针
BOOL GetDriveGeometry(const char* 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);
}

然后,在Toolbar的IDR_MAINFRAME上添加一个按钮,ID为ID_GET_DISK_GEOMETRY。打开ClassWizard,在DiskGeometryView中

添加ID_GET_DISK_GEOMETRY的映射函数OnGetDiskGeometry。打开DiskGeometryView.cpp,包含头文件GetDiskGeometry.h。

在OnGetDiskGeometry中,添加以下代码

const char *szDevName[]=
{
    "\\\\.\\A:",
    "\\\\.\\B:",
    "\\\\.\\PhysicalDrive0",
    "\\\\.\\PhysicalDrive1",
    "\\\\.\\PhysicalDrive2",
    "\\\\.\\PhysicalDrive3",
    "\\\\.\\Cdrom0",
    "\\\\.\\Cdrom1",
};
DISK_GEOMETRY dg;
ULONGLONG DiskSize;
BOOL bResult;
CString strMsg;
CString strTmp;


for(int i=0; i<sizeof(szDevName)/sizeof(char*); i++)
{
    bResult = GetDriveGeometry(szDevName[i], &dg);
  
    strTmp.Format("\r\n%s    result = %s\r\n", szDevName[i], bResult ? "success" : "failure");
    strMsg+=strTmp;

    if(!bResult) continue;

    strTmp.Format("      Media Type = %d\r\n", dg.MediaType);
    strMsg+=strTmp;

    strTmp.Format("      Cylinders = %I64d\r\n", dg.Cylinders);
    strMsg+=strTmp;

    strTmp.Format("      Tracks per cylinder = %ld\r\n", (ULONG) dg.TracksPerCylinder);
    strMsg+=strTmp;

    strTmp.Format("      Sectors per track = %ld\r\n", (ULONG) dg.SectorsPerTrack);
    strMsg+=strTmp;

    strTmp.Format("      Bytes per sector = %ld\r\n", (ULONG) dg.BytesPerSector);
    strMsg+=strTmp;

    DiskSize = dg.Cylinders.QuadPart * (ULONG)dg.TracksPerCylinder *
     (ULONG)dg.SectorsPerTrack * (ULONG)dg.BytesPerSector;
    strTmp.Format("      Disk size = %I64d (Bytes) = %I64d (Mb)\r\n", DiskSize, DiskSize / (1024 *1024));
    strMsg+=strTmp;
} 

CEdit& Edit = GetEditCtrl();

Edit.SetWindowText(strMsg);


最后,最后干什么呢?编译,运行......

分享到:
评论

相关推荐

    C++获取电脑MAC/CPU/BIOS/硬盘等硬件信息

    在Windows下,可以通过`CreateFile`打开`\\.\PhysicalDriveX`(X为硬盘编号),然后使用`DeviceIoControl`函数传递`IOCTL_STORAGE_QUERY_PROPERTY`控制代码来获取硬盘属性,包括序列号。在Linux中,可以读取`/dev/...

    易语言DeviceIoControl取硬盘序列号源码

    本主题主要关注如何使用易语言来通过DeviceIoControl函数获取硬盘的序列号。 硬盘序列号是每个硬盘的唯一标识符,通常用于识别和追踪硬盘。在Windows操作系统中,我们可以利用设备I/O控制(DeviceIoControl)函数来...

    c#通过系统api获取硬盘序列号

    在Windows API中,获取硬盘序列号的常用函数是 `DeviceIoControl`,它允许应用程序向设备发送控制代码。要使用这个函数,我们需要定义以下几点: 1. **设备句柄**:通过 `CreateFile` 函数获得,该函数接收设备名...

    易语言DeviceIoControl取硬盘序列号

    易语言DeviceIoControl取硬盘序列号源码,DeviceIoControl取硬盘序列号,倒序排列,DeviceIoControl,CreateFileA,CloseHandle,GetLastError,LocalAlloc,LocalFree

    DeviceIoControl取硬盘序列号.rar

    DeviceIoControl取硬盘序列号.rar

    DeviceIoControl、CreateFile,结合WMI读取物理硬盘网卡mac特征码,完整源码工程实例

    功能:结合WMI和DeviceIoControl获取网卡原生MAC地址和当前MAC地址 入口参数: iQueryType:需要获取的网卡类型 0:包括USB网卡 1:不包括USB网卡 pMacAddress:存储网卡MAC地址 uSize:可存储的最大网卡...

    获取设备和硬盘的代码

    3. `DeviceIoControl`函数:这个函数允许你向设备发送控制代码,从而获取更深入的设备信息,如硬盘的型号、容量、分区信息等。通过指定不同的控制代码(IOCTLs),可以获取不同的设备属性。 除了上述API,可能还会...

    VB6.0获取硬盘序列号的代码

    "VB6.0获取硬盘序列号的代码" VB6.0 获取硬盘序列号的代码是使用 Visual Basic 6.0 编程语言开发的一种获取硬盘序列号的方法。本文将对该代码进行详细的解释和分析。 代码结构 该代码主要由四部分组成: 1. 常量...

    C语言获取硬件信息(CPU序列号,硬盘序列号,网卡IP、MAC地址、是否插入网线).zip

    本文将详细讲解如何使用C语言在Linux和Windows操作系统下获取CPU序列号、硬盘序列号以及网卡的相关信息,如网卡名称、IP地址、MAC地址和网络连接状态。 首先,让我们关注CPU序列号的获取。在Windows系统中,可以...

    易语言DeviceIoControl取硬盘序列号源码-易语言

    在这个“易语言DeviceIoControl取硬盘序列号源码”教程中,我们将深入探讨如何利用易语言来获取硬盘的序列号,这是一个进阶的编程实践,涉及到系统底层的I/O控制。 首先,`DeviceIoControl`是一个Windows API函数,...

    vc 获取硬盘序列号

    在VC++编程环境中,获取硬盘序列号是一项常见的需求,特别是在软件授权、系统识别或数据安全等领域。硬盘序列号是每个硬盘制造商在生产过程中赋予的独特标识,通常存储在硬盘的固件区域。本篇将深入探讨如何使用VC++...

    delphi 获取计算机硬盘所有分区盘符

    4. **解析结果**:根据DeviceIoControl的返回值,我们可以获取到硬盘的分区信息,包括每个分区的起始位置、结束位置等。结合这些信息,我们可以确定每个分区的盘符。 5. **处理分区信息**:最后,将每个分区的盘符...

    Delphi获取CPU、硬盘等硬件温度.rar

    在Delphi中,可以通过访问SMART数据来获取硬盘温度,这通常需要调用特定的硬盘驱动程序接口,如`CreateFile`函数打开硬盘设备,然后使用`DeviceIoControl`进行控制操作。 此外,内存温度的获取相对复杂,因为没有...

    DeviceIoControl SMART硬盘取温度和使用时间-易语言

    使用DeviceIoControl APi 获取 IOCTL_STORAGE_PREDICT_FAILURE 产品信息中的 VendorSpecific 也可以使用 命名空间root/wmi下MSStorageDriver_ATAPISmartData类的子集VendorSpecific内存放了硬盘内部芯片存储的所有...

    Delphi获取硬盘序列号(支持IDE和SCSI硬盘)

    接着,分配内存并再次调用`DeviceIoControl`来获取硬盘的存储标识符,其中包括序列号。最后,从返回的缓冲区中提取序列号字符串。 需要注意的是,硬盘序列号通常包含非打印字符,因此在处理时应确保正确解码和显示...

    GetHardDiskSerialID.rar_GetHardDiskSerialID_MAC 硬盘_c++获取dns_硬盘序列

    在C++中,我们可以利用`#include &lt;windows.h&gt;`头文件,然后调用`CreateFile`函数打开硬盘设备,再通过`DeviceIoControl`函数发送控制代码IOCTL_STORAGE_QUERY_PROPERTY来获取硬盘属性,其中包含序列号信息。...

    vc++获取磁盘smart信息

    在IT领域,获取硬盘的SMART(Self-Monitoring, Analysis, and Reporting Technology)信息是一项重要的任务,这有助于预测硬盘可能出现的故障,及时采取备份措施。SMART技术是硬盘自我监测、分析和报告的一种机制,...

    C#4种方式获取硬盘物理序列号

    例如,可以调用`DeviceIoControl`函数配合`IOCTL_STORAGE_QUERY_PROPERTY`控制代码来获取硬盘信息。这需要定义一些结构体,如STORAGE_PROPERTY_QUERY和STORAGE_DEVICE_DESCRIPTOR,然后解析返回的设备描述符,从中...

    实战DeviceIoControl:通过API访问设备驱动程序.rar

    在Windows操作系统中,DeviceIoControl是一个非常重要的API,它提供了应用程序与设备驱动程序之间通信的桥梁。本实战教程将深入探讨如何使用DeviceIoControl来直接操控设备,从而实现对硬件的高级控制。以下是对这个...

Global site tag (gtag.js) - Google Analytics