VC 驱动器 DeviceIoControl

实战DeviceIoControl 实战DeviceIoControl 之一Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢? A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访 阅读详情

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.youkuaiyun.com/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的,嘿嘿

VC++驱动开发全攻略:源代码与实践 本文还有配套的精品资源,点击获取 简介:VC++驱动源程序对于Windows系统底层驱动程序的开发至关重要,它要求开发者熟悉Visual C++以及Driver Development Kit (DDK) 或Windows Driver Kit (WDK)。驱动程序是连接硬件与操作系统的桥梁,负责处理输入输出和设备控制。本文将深入探讨VC++驱动程序的关键组成部分,如Dri... 阅读详情

相关推荐

Moveit +Gazebo:搭建单臂机械臂仿真平台

Moveit +Gazebo:搭建单臂机械臂仿真平台

magic_invaid的博客 5290

VC下获取各个驱动器路径,分类及其获取其信息的资料整理

 1.获取所有的驱动器利用函数GetLogicalDriveStringsThe GetLogicalDriveStrings function fills a buffer with strings that specify valid drives in the system. DWORD GetLogicalDriveStrings(  DWORD nBufferLength,  /

毛毛(handsomerun)的专栏 5197

Unity轻量级框架QFramework:四层架构与命令事件驱动的实战指南

在Unity游戏开发中,软件架构是确保项目可维护性和可扩展性的核心。通过分层架构(如MVC、DDD)和事件驱动设计,开发者能够有效管理代码复杂度,实现模块间的解耦与高效通信。QFramework作为一个轻量级框架,精准地运用了这些原理,通过严格定义的四层架构(表现层、系统层、数据层、工具层)和命令/事件通信规则,为中小型项目提供了“约束下的自由”。其核心价值在于以极简的代码(不足1000行)强制实施清晰的职责分离,如使用命令模式集中管理状态变更,并通过事件驱动实现响应式更新。这种设计特别适用于解决项目规模扩

weixin_42521032的博客 262

《实用C++》第20课 字符数组

本文转载自:VC驿站 https://www.cctry.com/thread-288729-1-1.html 1、什么是字符数组?说白了,字符数组就是数组中存放的是字符,即 char 类型。例如:char szbuf[50];因为字符串本身就是有一个一个的字符组合而成的,所以,字符数组可以理解为是一个字符串。在以后的C++编程过程中会遇到各种各样对字符串的操作。2、字符数组的初始化:方式①:...

net_syc的专栏 488

Halcon 20.11在WPF中的交互式绘图:完整实现矩形ROI的创建、拖动与坐标获取

本文详细介绍了如何在WPF框架下利用Halcon 20.11实现交互式矩形ROI的创建、拖动与坐标获取。通过HDrawingObject和HSmartWindowControlWPF控件,开发者可以高效构建机器视觉应用,提升项目实战中的开发效率。文章涵盖环境配置、事件处理、坐标获取及性能优化等关键内容。

weixin_29266007的博客 427

使用SpringBoot+Vue3开发项目(1)---- 设计用户注册和登录的接口及页面

本文基于黑马大事件项目介绍如何使用SpringBoot+Vue3来实现前后端联调的登录与注册操作。

记得开心一点嘛的博客 3643

调用DeviceIoControl引发的几个程序崩溃总结

为了程序的兼容性,调用DeviceIoControl时不要传入空指针。

qq_26196217的博客 982

数据分析—用户行为数据分析

一般价值用户(R高F高M低):用户处于购买活跃期,感兴趣的商品多,购买次数少 → 针对该部分客户,目的就是要让他们购买,所以可以和运营部门沟通,降低利润,给出有力折扣促进购买,进而转为重要价值用户。重要价值用户(R高F高M高)维护:用户处于购买活跃期,感兴趣的商品多,购买次数也多 → 针对兴趣产品,保持一定频率的触达,持续维护。

m0_74091312的博客 1419

实战DeviceIoControl之一:通过API访问设备驱动程序

Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢?A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。 DeviceIoCon

benny5609的专栏 844

lammps教程:ovito免费输出高清图片方法

基本原理是调用ovito软件包中的TachyonRenderer模块,该模块可实现Tachyon渲染,达到和ovito 2.9 Tachyon完全相同的效果。这种方法在后来的ovito版本中已经不能使用,但是ovito 2.9版本在后处理方面功能较少,使用起来也不是特别方便。在之前的推文中,曾介绍过使用ovito 2.9版本更换Tachyon渲染器实现高清图片的输出。这个方法只需要配置ovito模块即可,完全免费,不需要购买ovito pro版。具体的配置参数可到ovito官网查询。大家好,我是小马老师。

lammps_jiayou的博客 2766

第二大脑的觉醒:一个寄生在代码里的小生命,如何悄无声息地接管我的工作流

所有记忆都存在本地。

步子哥的博客 1064

实战DeviceIoControl 之一:通过API访问设备驱动程序

Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢? A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。 DeviceIoCont...

weixin_33964094的博客 103

手把手入门YOLO到改进优化教程 | 【P5进阶篇】YOLOv8损失函数改进实战-损失函数IoU之KLD Loss

在本节,将从 KLD Loss(Kullback–Leibler Divergence Loss)的理论到实战代码实现,带你把 KLD Loss融合进 YOLOv8 的训练框架中。并通过训练日志与实验结果,验证 KLD Loss 在实际工程中的优势。

嵌入式阿齐Archie 2万+

实战DeviceIoControl 之中的一个:通过API訪问设备驱动程序

P.bhw98 { PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 9pt; PADDING-BOTTOM: 0px; MARGIN: 10px 0px 5px; LINE-HEIGHT: normal; PADDING-TOP: 0px; F...

weixin_30270889的博客 74

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

DeviceIOcontrol(1)

Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢?A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。DeviceIoCont

MannHello的专栏 1091

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【转帖】实战DeviceIoControl 系列

实战DeviceIoControl 之一:通过API访问设备驱动程序Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢? A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问―获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制

floweronwarmbed的专栏 1849

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

DeviceIoControl

实战DeviceIoControl 之一:通过API访问设备驱动程序 Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢? A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确

Liang4的专栏 9873

实战DeviceIoControl系列 之一:通过API访问设备驱动程序

实战DeviceIoControl系列 之一:通过API访问设备驱动程序

Welcom to zougangx's blog 843
上一篇: 如何结束线程?
下一篇: C#程序实现动态调用DLL的研究
vrix
博客等级 码龄24年 673粉丝 167原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值