应用程序对设备的同步异步操作

  大部分IRP都是由应用程序的Win32API函数发起的。这些Win32API本身就支持同步和异步操作。例如,ReadFile、WriteFile、和DeviceIoControl等,这些都有两种操作方式,一种是同步操作,另一种是异步操作。

1)同步操作设备

  如果需要同步操作设备,在打开设备的时候就要指定以“同步”的方式打开设备。打开设备用CreateFile函数,其函数声明如下:

HANDLE CreateFile(

LPCTSTR lpFileName,                  //设备名

DWORD dwDesiredAccess,         //访问权限

DWORD dwShareMode,              //共享模式

LPSECURITY_ATTRIBUTES lpSecurityAttributes,    //安全属性

DWORD dwCreationDisposition,               //如何创建

DWORD dwFlagsAndAttributes,                //设备属性

HANDLE   hTemplateFile                           //文件模板

);

其中第六个参数dwFlagsAndAttributes是同步异步操作的关键。如果这个参数中没有设置FILE_FLAG_OVERLAPPED,则以后对该设备的操作都是同步操作,否则所有操作作为异步操作。

  对设备操作的WIn32API,例如ReadFile, WriteFile和deviceIOControl函数,都会提供一个OVERLAP参数,如:

BOOL ReadFile(

HANDLE hFile,                                      //设备句柄

LPVOID lpBuffer,                                  //读取的缓冲区

DWORD nNumberOfBytesToRead,       //读取的大小

LPDWORD lpNumberOfBytesRead,      //实际读取的大小

LPOVERLAPPED lpOverlapped             //overlapp参数

);

 在同步操作设备时,其lpoverlapped参数设置为NULL。下面的代码演示了应用程序如何对设备进行同步读取。

int main()

{

  //打开设备,这里以文件作为例子

 HANDLE hDevice = CreateFile("test.dat",

                                               GENERIC_READ|GENERIC_WRITE,

                                               0,

                                               NULL,

                                               OPEN_EXISTING,

                                               FILE_ATTRIBUTE_HIDDEN,

                                               NULL);

//判断是否打开成功

if(hDevice == INVALID_HANDLE_VALUE)

{

       printf("Read Error/n");

        return 1;

}

UCHAR buffer[BUFFER_SIZE];

DWORD dwRead;

ReadFile(hDevice,  buffer, BUFFER_SIZE,&dwRead, NULL);

CloseHandle(hDevice);

return 0;

}

 

2)异步操作方式一

异步操作设备时主要需要设置OVERLAP参数,Windows中用一种数据结构OVERLAPPED表示。

typedef struct _OVERLAPPED{

ULONG_PTR   Internal;

ULONG_PTR   InternalHigh;

DWORD          Offset;

DWORD          OffsetHigh;

HANDLE          hEvent;

}OVERLAPPED;

 

第三个参数Offset:操作设备会指定一个偏移量,从设备的偏移量进行读取。

第五个参数hEvent:这个事件用于该操作完成后通知应用程序。程序员可以初始化该事件为未激发,当操作设备结束后,即在驱动中调用IoCompleteRequest后,设置该设备为激发态。示例代码

int main()

{

 HANDLE hDevice = CreateFile("test.dat",

                                               GENERIC_READ|GENERIC_WRITE,

                                               0,

                                               NULL,

                                               OPEN_EXISTING,

                                               FILE_ATTRIBUTE_HIDDEN|FILE_FLAG_OVERLAPPED,

                                               NULL);

//判断是否打开成功

if(hDevice == INVALID_HANDLE_VALUE)

{

       printf("Read Error/n");

        return 1;

}

UCHAR buffer[BUFFER_SIZE];

DWORD dwRead;

 

OVERLAPPED overlap = {0};

overlap.hEvent = CreateEvent((NULL, FALSE, FALSE, NULL);

ReadFile(hDevice, buffer, BUFFER_SIZE,&dwRead, &overlap);

WaitForSingleObject(overlap.hEvent, INFINITE);

CloseHandle(hDevice);

return 0;

}

 

3)异步操作二

  除了ReadFile和WriteFile函数外,还有两个API也可以实现异步读写,这就是ReadFileEx和WriteFileEx函数。

BOOL ReadFileEx(

HANDLE hFile,                                //设备句柄

LPVOID lpBuffer,                            //读取缓冲区

DWORD nNumberOfBytesToRead, //读取的字节数

LPOVERLAPPED lpOverlapped,                  

LPOVERLAPPED_COMMPLETION_ROUTINE lpCompletionRoutine  //完成函数

);

第五个参数lpCompletioRoutine:完成例程。

需要注意的是这里提供的OVERLAPPED不需要提供事件句柄。ReadFileEx将读请求传递到驱动程序后立刻返回。驱动程序在结束读操作后,会通过调用ReadFileEx提供的回调例程。这里是一个软中断,也就是当读操作结束后,系统立刻回调例程。Windows将这种机制称为异步过程调用(APC)。

  然而,APC的回调函数被调用是有条件的。只有线程处于警惕状态时,回调函数才有可能被调用。有多个API可以使系统进入警惕状态,如SleepEx,WaitForSingleObjectEx,WaitForMultipleObjectEx函数等。这些Win32 API都会有一个BOOL型的参数bAlertable,当设置为TRUE时,就进入警惕 模式。

  当系统进入警惕模式后,操作系统会枚举当前线程的APC队列。驱动程序一旦结束读取操作,就会把ReadFileEx提供的完成例程插入到APC队列。回调例程的声明:

VOID CALLBACK FileIOCompletionRoutine(

DWORD dwErrorCode,

DWORD dwNumberOfBytesTransferred,

LPOVERLAPPED lpOverlapped

);

示例代码:

VOID CALLBACK MyFileIOCompletionRoutine(

DWORD dwErrorCode,

DWORD dwNumberOfBytesTransferred,

LPOVERLAPPED lpOverlapped

)

{

printf("IO operation end!/n");

}

 

int main()

{

 HANDLE hDevice = CreateFile("test.dat",

                                               GENERIC_READ|GENERIC_WRITE,

                                               0,

                                               NULL,

                                               OPEN_EXISTING,

                                               FILE_ATTRIBUTE_HIDDEN|FILE_FLAG_OVERLAPPED,

                                               NULL);

//判断是否打开成功

if(hDevice == INVALID_HANDLE_VALUE)

{

       printf("Read Error/n");

        return 1;

}

UCHAR buffer[BUFFER_SIZE];

OVERLAPPED overlap = {0};

ReadFileEx(hDevice, buffer, BUFFER_SIZE, &overlap, MyFileIOCompletionRoutine);

SleepEx(0, TRUE);

CloseHandle(hDevice);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值