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

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

实战 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/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
本系统采用微信小程序作为前端交互界面,结合Spring Boot与Vue.js框架实现后端服务及管理后台的构建,形成一套完整的电子商务解决方案。该系统架构支持单一商户独立运营,亦兼容多商户入驻的平台模式,具备高度的灵活性与扩展性。 在技术实现上,后端以Java语言为核心,依托Spring Boot框架提供稳定的业务逻辑处理与数据接口服务;管理后台采用Vue.js进行开发,实现了直观高效的操作界面;前端微信小程序则为用户提供了便捷的移动端购物体验。整套系统各模块间紧密协作,功能链路完整闭环,已通过严格测试与优化,符合商业应用的标准要求。 系统设计注重业务场景的全面覆盖,不仅包含商品展示、交易流程、订单处理等核心电商功能,还集成了会员管理、营销工具、数据统计等辅助模块,能够满足不同规模商户的日常运营需求。其多店铺支持机制允许平台方对入驻商户进行统一管理,同时保障各店铺在品牌展示、商品销售及客户服务方面的独立运作空间。 该解决方案强调代码结构的规范性与可维护性,遵循企业级开发标准,确保了系统的长期稳定运行与后续功能迭代的可行性。整体而言,这是一套技术选型成熟、架构清晰、功能完备且可直接投入商用的电商平台系统。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值