实战 DeviceIoControl 系列 之二:获取软盘/硬盘/光盘的参数

本文介绍如何使用DeviceIoControl函数获取软盘、硬盘和光盘的参数,并提供了VC代码示例。

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

实战 DeviceIoControl 之二:获取软盘/硬盘/光盘的参数  

 

 

 

Q 在 MSDN的那个 demo 中,将设备名换成“A:”取 A 盘参数,先用资源管理
器读一下盘,再运行这个程序可以成功,但换一张盘后就失败;换成“CDROM0”
取 CDROM参数,无论如何都不行。这个问题如何解决呢? 
A 取软盘参数是从软盘上读取格式化后的信息,也就是必须执行读操作,这一
点与硬盘不同。将CreateFile中的访问方式改为 GENERIC_READ 就行了。 
IOCTL_DISK_GET_DRIVE_GEOMETRY这个 I/O 控制码,对软盘和硬盘有效,但
对一些可移动媒介如 CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数,
还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问
题。 

 

Q 使用这些 I/O 控制码,需要什么样的输入输出数据格式呢? 
A 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 需要紧
接此结构的另外的空间。 


Q 调用方法我了解了,请用 VC举个例子来实现我所期待已久的功能吧? 
A 好,现在就演示一下如何取软盘/硬盘/光盘的参数。测试时,记得要有软盘/
光盘插在驱动器里喔! 
首先,用 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);
最后,最后干什么呢?编译,运行...... 

 

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 华为移动服务(Huawei Mobile Services,简称 HMS)是一个全面开放的移动服务生态系统,为企业和开发者提供了丰富的工具和 API,助力他们构建、运营和推广应用。其中,HMS Scankit 是华为推出的一款扫描服务 SDK,支持快速集成到安卓应用中,能够提供高效且稳定的二维码和条形码扫描功能,适用于商品扫码、支付验证、信息获取等多种场景。 集成 HMS Scankit SDK 主要包括以下步骤:首先,在项目的 build.gradle 文件中添加 HMS Core 库和 Scankit 依赖;其次,在 AndroidManifest.xml 文件中添加相机访问和互联网访问权限;然后,在应用程序的 onCreate 方法中调用 HmsClient 进行初始化;接着,可以选择自定义扫描界面或使用 Scankit 提供的默认扫描界面;最后,实现 ScanCallback 接口以处理扫描成功和失败的回调。 HMS Scankit 内部集成了开源的 Zxing(Zebra Crossing)库,这是一个功能强大的条码和二维码处理库,提供了解码、生成、解析等多种功能,既可以单独使用,也可以与其他扫描框架结合使用。在 HMS Scankit 中,Zxing 经过优化,以更好地适应华为设备,从而提升扫描性能。 通常,ScanKitDemoGuide 包含了集成 HMS Scankit 的示例代码,涵盖扫描界面的布局、扫描操作的启动和停止以及扫描结果的处理等内容。开发者可以参考这些代码,快速掌握在自己的应用中实现扫码功能的方法。例如,启动扫描的方法如下: 处理扫描结果的回调如下: HMS Scankit 支持所有安卓手机,但在华为设备上能够提供最佳性能和体验,因为它针对华为硬件进行了
标题基于SpringBoot+Vue的社区便民服务平台研究AI更换标题第1章引言介绍社区便民服务平台的研究背景、意义,以及基于SpringBoot+Vue技术的研究现状和创新点。1.1研究背景与意义分析社区便民服务的重要性,以及SpringBoot+Vue技术在平台建设中的优势。1.2国内外研究现状概述国内外在社区便民服务平台方面的发展现状。1.3研究方法与创新点阐述本文采用的研究方法和在SpringBoot+Vue技术应用上的创新之处。第2章相关理论介绍SpringBoot和Vue的相关理论基础,以及它们在社区便民服务平台中的应用。2.1SpringBoot技术概述解释SpringBoot的基本概念、特点及其在便民服务平台中的应用价值。2.2Vue技术概述阐述Vue的核心思想、技术特性及其在前端界面开发中的优势。2.3SpringBoot与Vue的整合应用探讨SpringBoot与Vue如何有效整合,以提升社区便民服务平台的性能。第3章平台需求分析与设计分析社区便民服务平台的需求,并基于SpringBoot+Vue技术进行平台设计。3.1需求分析明确平台需满足的功能需求和性能需求。3.2架构设计设计平台的整体架构,包括前后端分离、模块化设计等思想。3.3数据库设计根据平台需求设计合理的数据库结构,包括数据表、字段等。第4章平台实现与关键技术详细阐述基于SpringBoot+Vue的社区便民服务平台的实现过程及关键技术。4.1后端服务实现使用SpringBoot实现后端服务,包括用户管理、服务管理等核心功能。4.2前端界面实现采用Vue技术实现前端界面,提供友好的用户交互体验。4.3前后端交互技术探讨前后端数据交互的方式,如RESTful API、WebSocket等。第5章平台测试与优化对实现的社区便民服务平台进行全面测试,并针对问题进行优化。5.1测试环境与工具介绍测试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值