实战DeviceIoControl.docx

上传人:b****5 文档编号:29862043 上传时间:2023-07-27 格式:DOCX 页数:51 大小:42.85KB
下载 相关 举报
实战DeviceIoControl.docx_第1页
第1页 / 共51页
实战DeviceIoControl.docx_第2页
第2页 / 共51页
实战DeviceIoControl.docx_第3页
第3页 / 共51页
实战DeviceIoControl.docx_第4页
第4页 / 共51页
实战DeviceIoControl.docx_第5页
第5页 / 共51页
点击查看更多>>
下载资源
资源描述

实战DeviceIoControl.docx

《实战DeviceIoControl.docx》由会员分享,可在线阅读,更多相关《实战DeviceIoControl.docx(51页珍藏版)》请在冰豆网上搜索。

实战DeviceIoControl.docx

实战DeviceIoControl

实战DeviceIoControl

实战DeviceIoControl之一:

通过API访问设备驱动程序

问题:

在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢?

回答:

在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。

利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。

DeviceIoControl的函数原型为

BOOLDeviceIoControl(

HANDLEhDevice,//设备句柄

DWORDdwIoControlCode,//控制码

LPVOIDlpInBuffer,//输入数据缓冲区指针

DWORDnInBufferSize,//输入数据缓冲区长度

LPVOIDlpOutBuffer,//输出数据缓冲区指针

DWORDnOutBufferSize,//输出数据缓冲区长度

LPDWORDlpBytesReturned,//输出数据实际长度单元长度

LPOVERLAPPEDlpOverlapped//重叠操作结构指针);

设备句柄用来标识你所访问的设备。

发送不同的控制码,可以调用设备驱动程序的不同类型的功能。

在头文件winioctl.h中,预定义的标准设备控制码,都以IOCTL或FSCTL开头。

例如,

IOCTL_DISK_GET_DRIVE_GEOMETRY是对物理驱动器取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)的控制码,FSCTL_LOCK_VOLUME是对逻辑驱动器的卷加锁的控制码。

输入输出数据缓冲区是否需要,是何种结构,以及占多少字节空间,完全由不同设备的不同操作类型决定。

在头文件winioctl.h中,已经为标准设备预定义了一些输入输出数据结构。

重叠操作结构指针设置为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计。

问题:

设备句柄是从哪里获得的?

回答:

设备句柄可以用API函数CreateFile获得。

它的原型为

HANDLECreateFile(

LPCTSTRlpFileName,//文件名/设备路径

DWORDdwDesiredAccess,//访问方式

DWORDdwShareMode,//共享方式

LPSECURITY_ATTRIBUTESlpSecurityAttributes,//安全描述符指针

DWORDdwCreationDisposition,//创建方式

DWORDdwFlagsAndAttributes,//文件属性及标志

HANDLEhTemplateFile//模板文件的句柄);

CreateFile这个函数用处很多,这里我们用它“打开”设备驱动程序,得到设备的句柄。

操作完成后用CloseHandle关闭设备句柄。

与普通文件名有所不同,设备驱动的“文件名”(常称为“设备路径”)形式固定为“\\.\DeviceName”(注意在C程序中该字符串写法为“\\\\.\\DeviceName”),DeviceName必须与设备驱动程序内定义的设备名称一致。

一般地,调用CreateFile获得设备句柄时,访问方式参数设置为0或GENERIC_READ|GENERIC_WRITE,

共享方式参数设置为FILE_SHARE_READ|FILE_SHARE_WRITE,创建方式参数设置为OPEN_EXISTING,其它参数设置为0或NULL。

问题:

可是,我怎么知道设备名称是什么呢?

回答:

一些存储设备的名称是微软定义好的,不可能有什么变化。

大体列出如下

软盘驱动器A:

B:

硬盘逻辑分区C:

D:

E:

...

物理驱动器PHYSICALDRIVEx

CD-ROM,DVD/ROMCDROMx

磁带机TAPExIDE是什么?

接口吗?

其中,物理驱动器不包括软驱和光驱。

逻辑驱动器可以是IDE/SCSI/PCMCIA/USB接口的硬盘分区(卷)、光驱、MO、CF卡等,甚至是虚拟盘。

x=0,1,2……

其它的设备名称需通过驱动接口的GUID调用设备管理函数族取得,这里暂不讨论。

驱动接口的GUIDS是什么意思?

问题:

请举一个简单的例子说明如何通过DeviceIoControl访问设备驱动程序。

回答:

这里有一个从MSDN上摘抄来的demo程序,演示在NT/2000/XP中如何通过DeviceIoControl获取硬盘的基本参数。

/*ThecodeofinterestisinthesubroutineGetDriveGeometry.

ThecodeinmainshowshowtointerprettheresultsoftheIOCTLcall.*/

#include

#include

BOOLGetDriveGeometry(DISK_GEOMETRY*pdg)

{

HANDLEhDevice;//handletothedrivetobeexamined

BOOLbResult;

DWORDjunk;//discardresults__junk垃圾,discard丢弃

hDevice=CreateFile("\\\\.\\PhysicalDrive0",0,FILE_SHARE_READ

//微软定义的,本来就有

|FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,NULL);

if(hDevice==INVALID_HANDLE_VALUE)

return(FALSE);

bResult=DeviceIoControl(hDevice,IOCTL_DISK_GET_DRIVE_GEOMETRY,

NULL,0,pdg,sizeof(*pdg),&junk,(LPOVERLAPPED)NULL);

CloseHandle(hDevice);

return(bResult);

}

intmain(intargc,char*argv[])

{

DISK_GEOMETRYpdg;//diskdrivegeometrystructure

BOOLbResult;//genericresultsflag

ULONGLONGDiskSize;//sizeofthedrive,inbytes64位,因为Cylinders是LARGE_INTEGER的数据类型

bResult=GetDriveGeometry(&pdg);

if(bResult)

{

printf("Cylinders=%I64d\n",pdg.Cylinders);

printf("Trackspercylinder=%ld\n",(ULONG)pdg.TracksPerCylinder);

printf("Sectorspertrack=%ld\n",(ULONG)pdg.SectorsPerTrack);

printf("Bytespersector=%ld\n",(ULONG)pdg.BytesPerSector);

DiskSize=pdg.Cylinders.QuadPart*(ULONG)pdg.TracksPerCylinder

*(ULONG)pdg.SectorsPerTrack*(ULONG)pdg.BytesPerSector;

printf("Disksize=%I64d(Bytes)=%I64d(Mb)\n",

DiskSize,DiskSize/(1024*1024));

}

else

{

printf("GetDriveGeometryfailed.Error%ld.\n",GetLastError());

}

return((int)bResult);

}

问题:

如果将设备名换成“A:

”就可以取A盘参数,换成“CDROM0”就可以取CDROM参数,是这样吗?

回答:

这个问题暂不做回答。

请动手试一下。

现在我们总结一下通过DeviceIoControl访问设备驱动程序的“三步曲”:

首先用CreateFile取得设备句柄,然后用DeviceIoControl与设备进行I/O,最后别忘记用CloseHandle关闭设备句柄。

实战DeviceIoControl之二:

获取软盘/硬盘/光盘的参数

问题:

在MSDN的那个demo中,将设备名换成“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能够帮我们解决问题。

问题:

使用这些I/O控制码,需要什么样的输入输出数据格式呢?

回答:

DeviceIoControl使用这两个控制码时,都不需要输入数据。

IOCTL_DISK_GET_DRIVE_GEOMETRY直接输出一个DISK_GEOMETRY结构:

typedefstruct_DISK_GEOMETRY

{

LARGE_INTEGERCylinders;//柱面数

MEDIA_TYPEMediaType;//介质类型

DWORDTracksPerCylinder;//每柱面的磁道数

DWORDSectorsPerTrack;//每磁道的扇区数

DWORDBytesPerSector;//每扇区的字节数

}DISK_GEOMETRY;

IOCTL_STORAGE_GET_MEDIA_TYPES_EX输出一个GET_MEDIA_TYPES结构:

typedefstruct_GET_MEDIA_TYPES

{

DWORDDeviceType;//设备类型

DWORDMediaInfoCount;//介质信息条数

DEVICE_MEDIA_INFOMediaInfo[1];//介质信息

}GET_MEDIA_TYPES;

让我们来看一下DEVICE_MEDIA_INFO结构的定义:

typedefstruct_DEVICE_MEDIA_INFO

{

union

{

struct

{

LARGE_INTEGERCylinders;//柱面数

STORAGE_MEDIA_TYPEMediaType;//介质类型

DWORDTracksPerCylinder;//每柱面的磁道数

DWORDSectorsPerTrack;//每磁道的扇区数

DWORDBytesPerSector;//每扇区的字节数

DWORDNumberMediaSides;//介质面数

DWORDMediaCharacteristics;//介质特性

}DiskInfo;//硬盘信息

struct

{

LARGE_INTEGERCylinders;//柱面数

STORAGE_MEDIA_TYPEMediaType;//介质类型

DWORDTracksPerCylinder;//每柱面的磁道数

DWORDSectorsPerTrack;//每磁道的扇区数

DWORDBytesPerSector;//每扇区的字节数

DWORDNumberMediaSides;//介质面数

DWORDMediaCharacteristics;//介质特性

}RemovableDiskInfo;//“可移动盘”信息

struct

{

STORAGE_MEDIA_TYPEMediaType;//介质类型

DWORDMediaCharacteristics;//介质特性

DWORDCurrentBlockSize;//块的大小

}TapeInfo;//磁带信息

}DeviceSpecific;

}DEVICE_MEDIA_INFO;

其中CD-ROM属于“可移动盘”的范围。

请注意,GET_MEDIA_TYPES结构本身只定义了一条DEVICE_MEDIA_INFO,额外的DEVICE_MEDIA_INFO需要紧接此结构的另外的空间。

问题:

调用方法我了解了,请用VC举个例子来实现我所期待已久的功能吧?

回答:

好,现在就演示一下如何取软盘/硬盘/光盘的参数。

测试时,记得要有软盘/光盘插在驱动器里喔!

首先,用MFCAppWizard生成一个单文档的应用程序,取名为DiskGeometry,让它的View基于CEditView。

然后,添加以下的.h和.cpp文件。

//GetDiskGeometry.h#if!

defined(GET_DISK_GEOMETRY_H__)

#defineGET_DISK_GEOMETRY_H__

#if_MSC_VER>1000

#pragmaonce

#endif//_MSC_VER>1000

#include

BOOLGetDriveGeometry(constchar*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,故定义足够的空间

#defineMEDIA_INFO_SIZE

sizeof(GET_MEDIA_TYPES)+15*sizeof(DEVICE_MEDIA_INFO)//16个DEVICE_MEDIA_INFO

//filename--用于设备的文件名

//pdg--参数缓冲区指针

BOOLGetDriveGeometry(constchar*filename,DISK_GEOMETRY*pdg)

{

HANDLEhDevice;//设备句柄

BOOLbResult;//DeviceIoControl的返回结果

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

DWORDdwOutBytes;//输出数据长度

//打开设备hDevice=:

:

CreateFile(filename,//文件名

GENERIC_READ,//软驱需要读盘

FILE_SHARE_READ|FILE_SHARE_WRITE,//共享方式

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

OPEN_EXISTING,//创建方式

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

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

if(hDevice==INVALID_HANDLE_VALUE)

{//设备无法打开...

returnFALSE;

}

//用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数

//少了好多参数啊~~,不行啊~~

bResult=:

:

DeviceIoControl(hDevice,//设备句柄磁盘结构体

IOCTL_GET_DISK_DRIVE_GEOMETRY,

NULL,0,

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

&dwOutBytes,//输出数据长度

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

上面的也可以获得介质类型啊pdg->MediaType?

?

?

;不过只能获得磁盘的下面的什么类型都可以知道了。

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

if(!

bResult)

{

pmt=(GET_MEDIA_TYPES*)newBYTE[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));

}

deletepmt;

}

//关闭设备句柄

:

:

CloseHandle(hDevice);

return(bResult);

}

然后,在Toolbar的IDR_MAINFRAME上添加一个按钮,ID为ID_GET_DISK_GEOMETRY。

打开ClassWizard,在DiskGeometryView中

添加ID_GET_DISK_GEOMETRY的映射函数OnGetDiskGeometry。

打开DiskGeometryView.cpp,包含头文件GetDiskGeometry.h。

在OnGetDiskGeometry中,添加以下代码

constchar*szDevName[]={"\\\\.\\A:

","\\\\.\\B:

","\\\\.\\PhysicalDrive0","\\\\.\\PhysicalDrive1","\\\\.\\PhysicalDrive2","\\\\.\\PhysicalDrive3","\\\\.\\Cdrom0","\\\\.\\Cdrom1",};DISK_GEOMETRYdg;

ULONGLONGDiskSize;

BOOLbResult;

CStringstrMsg;

CStringstrTmp;

for(inti=0;i

{

bResult=GetDriveGeometry(szDevName[i],&dg);

strTmp.Format("\r\n%sresult=%s\r\n",szDevName[i],bResult?

"success":

"failure");

strMsg+=strTmp;

if(!

bResult)

continue;

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

strMsg+=strTmp;

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

strMsg+=strTmp;

strTmp.Format("Trackspercylinder=%ld\r\n",(ULONG)dg.TracksPerCylinder);

strMsg+=strTmp;

strTmp.Format("Sectorspertrack=%ld\r\n",(ULONG)dg.SectorsPerTrack);

strMsg+=strTmp;

strTmp.Format("Bytespersector=%ld\r\n",(ULONG)dg.BytesPerSector);

strMsg+=strTmp;

DiskSize=dg.Cylinders.QuadPart*(ULONG)dg.TracksPerCylinder*

(ULONG)dg.SectorsPerTrack*(ULONG)dg.BytesPerSector;

strTmp.Format("Disksize=%I64d(Bytes)=%I64d(Mb)\r\n",DiskSize,DiskSize/(1024*1024));

strMsg+=strTmp;

}

CEdit&Edit=GetEditCtrl();

Edit.SetWindowText(strMsg);

最后,最后干什么呢?

编译,运行......

实战DeviceIoControl之三:

制作磁盘镜像文件

问题:

DOS命令DISKCOPY给我很深的印象,现在也有许多“克隆”软件,可以对磁盘进行全盘复制。

我想,要制作磁盘镜像文件,DeviceIoControl应该很有用武之地吧?

回答:

是的。

这里举一个制作软盘镜像文件,功能类似于“DISKCOPY”的例子。

本例实现其功能的核心代码如下:

//打开磁盘

HANDLEOpenDisk(LPCTSTRfilename)

{

HANDLEhDisk;

//打开设备

hDisk=:

:

CreateFile(filename,//文件名

GENERIC_READ|GENERIC_WRITE,//读写方式

FILE_SHARE_READ|FILE_SHARE_WRITE,//共享方式

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

OPEN_EXISTI

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 国外设计风格

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1