实战DeviceIoControl.docx

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

实战DeviceIoControl.docx

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

实战DeviceIoControl.docx

实战DeviceIoControl

实战DeviceIoControl之一:

通过API访问设备驱动程序

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

A在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将进行阻塞调用;否则,应在编程时按异步操作设计。

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

A设备句柄可以用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。

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

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

大体列出如下软盘驱动器A:

B:

 

硬盘逻辑分区C:

D:

E:

... 

物理驱动器PHYSICALDRIVEx 

CD-ROM,DVD/ROMCDROMx 

磁带机TAPEx 

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

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

x=0,1,2……

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

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

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

/*ThecodeofinterestisinthesubroutineGetDriveGeometry.The

 codeinmainshowshowtointerprettheresultsoftheIOCTLcall.*/

 

#include

#include

 

BOOLGetDriveGeometry(DISK_GEOMETRY*pdg)

{

  HANDLEhDevice;       //handletothedrivetobeexamined

  BOOLbResult;        //resultsflag

  DWORDjunk;         //discardresults

 

  hDevice=CreateFile("\\.\PhysicalDrive0", //drivetoopen

          0,        //noaccesstothedrive

          FILE_SHARE_READ|//sharemode

          FILE_SHARE_WRITE,

          NULL,      //defaultsecurityattributes

          OPEN_EXISTING,  //disposition

          0,        //fileattributes

          NULL);      //donotcopyfileattributes

 

  if(hDevice==INVALID_HANDLE_VALUE)//cannotopenthedrive

  {

    return(FALSE);

  }

 

  bResult=DeviceIoControl(hDevice,  //devicetobequeried

    IOCTL_DISK_GET_DRIVE_GEOMETRY,  //operationtoperform

          NULL,0,       //noinputbuffer

          pdg,sizeof(*pdg),  //outputbuffer

          &junk,        //#bytesreturned

          (LPOVERLAPPED)NULL); //synchronousI/O

 

  CloseHandle(hDevice);

 

  return(bResult);

}

 

intmain(intargc,char*argv[])

{

  DISK_GEOMETRYpdg;      //diskdrivegeometrystructure

  BOOLbResult;        //genericresultsflag

  ULONGLONGDiskSize;     //sizeofthedrive,inbytes

 

  bResult=GetDriveGeometry(&pdg);

 

  if(bResult)

  {

    printf("Cylinders=%I64dn",pdg.Cylinders);

    printf("Trackspercylinder=%ldn",(ULONG)pdg.TracksPerCylinder);

    printf("Sectorspertrack=%ldn",(ULONG)pdg.SectorsPerTrack);

    printf("Bytespersector=%ldn",(ULONG)pdg.BytesPerSector);

 

    DiskSize=*(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);

}

Q如果将设备名换成“A:

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

A这个问题暂不做回答。

请动手试一下。

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

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

实战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控制码,需要什么样的输入输出数据格式呢?

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

  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需要紧接此结构的另外的空间。

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

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

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

  首先,用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_SIZEsizeof(GET_MEDIA_TYPES)+15*sizeof(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_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*)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].;

  //pdg->Cylinders=pmt->MediaInfo[0].;

  //pdg->TracksPerCylinder=pmt->MediaInfo[0].;

  //......

  :

:

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",

  "\\

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

当前位置:首页 > 经管营销 > 经济市场

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

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