DeviceIoControl的使用说明

来源:互联网 发布:app ui 制作软件 编辑:程序博客网 时间:2024/05/22 12:08








          



DeviceIoControl的使用说明

        应用程序和驱动程序的通信过程是:应用程序使用CreateFile函数打开设备,然后用DeviceIoControl与驱动程序进行通信,包括读和写两种操作。还可以用ReadFile读数据用WriteFile写数据。操作完毕时用CloseHandle关闭设备。我们比较常用的就是用DeviceIoControl对设备进行读写操作。先看看DeviceIoControl是怎么定义的:

BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);Parameters(参数)
hDevice (CreateFile返回的设备句柄)
[in] Handle to the device that is to perform the operation. To obtain a device handle, call the CreateFile function.
dwIoControlCode (应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs )
[in] IOCTL for the operation. This value identifies the specific operation to perform and the type of device on which to perform the operation. There are no specific values defined for the dwIoControlCode parameter. However, you can define custom IOCTL_XXX IOCTLs with the CTL_CODE macro. You can then advertise these IOCTLs and an application can use these IOCTLs with DeviceIoControl to perform the driver-specific functions.
lpInBuffer (应用程序传递给驱动程序的数据缓冲区地址)
[in] Long pointer to a buffer that contains the data required to perform the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data.
nInBufferSize (应用程序传递给驱动程序的数据缓冲区大小,字节数)
[in] Size, in bytes, of the buffer pointed to by lpInBuffer.
lpOutBuffer (驱动程序返回给应用程序的数据缓冲区地址)
[out] Long pointer to a buffer that receives the output data for the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.
nOutBufferSize (驱动程序返回给应用程序的数据缓冲区大小,字节数)
[out] Size, in bytes, of the buffer pointed to by lpOutBuffer.
lpBytesReturned (驱动程序实际返回给应用程序的数据字节数地址)
[out] Long pointer to a variable that receives the size, in bytes, of the data stored in lpOutBuffer. The DeviceIoControl function may unnecessarily use this parameter. For example, if an operation does not produce data for lpOutBuffer and lpOutBuffer is NULL, the value of lpBytesReturned is meaningless.
lpOverlapped (重叠操作结构)
[in] Ignored; set to NULL.
Return Values(返回值)

Nonzero indicates success. Zero indicates failure. To obtain extended error information, call the GetLastError function. (非0成功,0失败)

具体使用我们看看列子:

1,向设备传递数据,我们定义一个函数来实现

bool CDeviceOperDlg::SendKeyData(HANDLE handle, BYTE *bData, int iSize)
{
ULONG nOutput;
BYTE bTemp[512];

//将数据放置到发送数组
memset(bTemp,0,sizeof(bTemp));
memcpy(bTemp,&bData[0],iSize);
//向设备发送
if (!DeviceIoControl(handle,         
       ATST2004_IOCTL_WRITE,     //根据具体的设备有相关的定义
       bTemp,                                        //向设备传递的数据地址
       iSize,                                            //数据大小,字节数
       NULL,                                          //没有返回的数据,置为NULL
       0,                                                  //没有返回的数据,置为0

       &nOutput,
       NULL)
    )
{
   return false;
}

return true;
}

2,从设备读取数据


bool CDeviceOperDlg::ReviceKeyData(HANDLE handle, BYTE *bData, int iSize)
{

ULONG nOutput;
BYTE bTemp[512];
//数组清零
memset(bTemp,0,sizeof(bTemp));
//向设备发送
if (!DeviceIoControl(handle,
       ATST2004_IOCTL_READ,           //根据具体的设备有相关的定义
       NULL,                                              //没有向设备传递的数据,置为NULL
       0,                                                      //没有向设备传递的数据,置为NULL
       bTemp,                                            //读取设备的数据返回地址
       iSize,                                                //读取数据的字节数
       &nOutput,
       NULL)
    )
{
   return false;
}
//放置到公用数组
memcpy(&bData[0],&bTemp[0],iSize);
return true;
}


原文网址:http://hi.baidu.com/dylan_li/item/90b061dcb3d9a1df251f4097


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

A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。

DeviceIoControl的函数原型为

BOOL DeviceIoControl(    HANDLE hDevice,              // 设备句柄    DWORD dwIoControlCode,       // 控制码    LPVOID lpInBuffer,           // 输入数据缓冲区指针    DWORD nInBufferSize,         // 输入数据缓冲区长度    LPVOID lpOutBuffer,          // 输出数据缓冲区指针    DWORD nOutBufferSize,        // 输出数据缓冲区长度    LPDWORD lpBytesReturned,     // 输出数据实际长度单元长度    LPOVERLAPPED lpOverlapped    // 重叠操作结构指针);

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

发送不同的控制码,可以调用设备驱动程序的不同类型的功能。在头文件winioctl.h中,预定义的标准设备控制码,都以IOCTL或FSCTL开头。例如,IOCTL_DISK_GET_DRIVE_GEOMETRY是对物理驱动器取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)的控制码,FSCTL_LOCK_VOLUME是对逻辑驱动器的卷加锁的控制码。

输入输出数据缓冲区是否需要,是何种结构,以及占多少字节空间,完全由不同设备的不同操作类型决定。在头文件winioctl.h中,已经为标准设备预定义了一些输入输出数据结构。重叠操作结构指针设置为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计。

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

A 设备句柄可以用API函数CreateFile获得。它的原型为

HANDLE CreateFile(    LPCTSTR lpFileName,                         // 文件名/设备路径    DWORD dwDesiredAccess,                      // 访问方式    DWORD dwShareMode,                          // 共享方式    LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全描述符指针    DWORD dwCreationDisposition,                // 创建方式    DWORD dwFlagsAndAttributes,                 // 文件属性及标志    HANDLE hTemplateFile                        // 模板文件的句柄);

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:, ...物理驱动器PHYSICALDRIVExCD-ROM, DVD/ROMCDROMx磁带机TAPEx

其中,物理驱动器不包括软驱和光驱。逻辑驱动器可以是IDE/SCSI/PCMCIA/USB接口的硬盘分区(卷)、光驱、MO、CF卡等,甚至是虚拟盘。x=0,1,2 ……

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

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

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

/* The code of interest is in the subroutine GetDriveGeometry. The   code in main shows how to interpret the results of the IOCTL call. */  #include <windows.h>#include <winioctl.h>  BOOL GetDriveGeometry(DISK_GEOMETRY *pdg){    HANDLE hDevice;               // handle to the drive to be examined    BOOL bResult;                 // results flag    DWORD junk;                   // discard results      hDevice = CreateFile("////.//PhysicalDrive0",  // drive to open                    0,                // no access to the drive                    FILE_SHARE_READ | // share mode                    FILE_SHARE_WRITE,                    NULL,             // default security attributes                    OPEN_EXISTING,    // disposition                    0,                // file attributes                    NULL);            // do not copy file attributes      if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive    {        return (FALSE);    }      bResult = DeviceIoControl(hDevice,     // device to be queried        IOCTL_DISK_GET_DRIVE_GEOMETRY,     // operation to perform                    NULL, 0,               // no input buffer                    pdg, sizeof(*pdg),     // output buffer                    &junk,                 // # bytes returned                    (LPOVERLAPPED) NULL);  // synchronous I/O      CloseHandle(hDevice);      return (bResult);}  int main(int argc, char *argv[]){    DISK_GEOMETRY pdg;            // disk drive geometry structure    BOOL bResult;                 // generic results flag    ULONGLONG DiskSize;           // size of the drive, in bytes      bResult = GetDriveGeometry (&pdg);      if (bResult)    {        printf("Cylinders = %I64d/n", pdg.Cylinders);        printf("Tracks per cylinder = %ld/n", (ULONG) pdg.TracksPerCylinder);        printf("Sectors per track = %ld/n", (ULONG) pdg.SectorsPerTrack);        printf("Bytes per sector = %ld/n", (ULONG) pdg.BytesPerSector);          DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *            (ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;        printf("Disk size = %I64d (Bytes) = %I64d (Mb)/n", DiskSize,            DiskSize / (1024 * 1024));    }    else    {        printf("GetDriveGeometry failed. Error %ld./n", GetLastError());    }      return ((int)bResult);}

Q 如果将设备名换成“A:”就可以取A盘参数,换成“CDROM0”就可以取CDROM参数,是这样吗?

A 这个问题暂不做回答。请动手试一下。

现在我们总结一下通过DeviceIoControl访问设备驱动程序的“三步曲”:首先用CreateFile取得设备句柄,然后用DeviceIoControl与设备进行I/O,最后别忘记用CloseHandle关闭设备句柄。

以上网址:http://blog.csdn.net/bhw98/article/details/19660
原创粉丝点击