`
yexin218
  • 浏览: 958143 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

驱动和应用层的异步通信

阅读更多

作 者: sislcb
时 间: 2008-01-28,11:13:28
链 接: http://bbs.pediy.com/showthread.php?t=59015

这里来简单的讲解下驱动和应用层的异步通信,上次我写了驱动和应用层的三种基本通信方法,但是那三种方法都是通过同步的方法来实现的,就是说,在应用层向驱动层发送消息后,就堵死在那里等待驱动层的返回了,而异步的概念就是,应用层向驱动发送消息后,就马上返回了,而在驱动层的消息触发后,再将该消息反馈给应用层。

给个网上的例子:
同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。
异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。

其实在明白了三种通信方式后,很容易使用异步方式来通信。

在调用DeviceIoControl时,不指定FILE_FLAG_OVERLAPPED标志,表示以同步方式调用,调用线程将被阻塞直到控制操作完成.
当指定FILE_FLAG_OVERLAPPED标志调用DeviceIoControl,表示以异步方式调用,调用线程不立即阻塞,直到调用线程需要结果时,调用者调用事件等待函数,等待驱动发出事件.
在异步调用时,得使用事件(event)来通信.

下面看应用层的代码:

// 初始化时创建设备
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  //创建设备
  try
    m_hCommDevice := CreateFile('\\.\Overlapp',  GENERIC_READ or GENERIC_WRITE,  FILE_SHARE_READ, nil,
                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0);
    //执行异步I/O的设备必须用FILE_FLAG_OVERLAPPED标志打开

    hEvent := CreateEvent( nil, False, False, nil);     //创建自动重置的事件
  except
    MessageBox(Handle, '创建设备失败', '驱动应用层通信', MB_OK + MB_ICONWARNING);
  end;
end;

//异步通信按钮,创建线程和驱动通信
procedure TfrmMain.btnBufferdClick(Sender: TObject);
var
  hThread:THandle;
  dwThreadID:DWORD;
begin
  hThread  := CreateThread(nil, 0, @WaitForNotify, self, 0, dwThreadID);
  CloseHandle(hThread);
end;

//线程的处理代码
//初始化一个OVERLAPPED 结构,然后用DeviceIoControl来通信
//在WaitForSingleObject等待返回
procedure WaitForNotify;
var
  dwReturn: DWORD;
  inData:array[0..1023] of char;
  outData:array[0..1023] of char;
  ol:OVERLAPPED ;
begin
  StrPCopy(inData, Trim(frmMain.edtBufferd_in.Text));

  //OVERLAPPED结构的Offset,OffsetHigh和hEvent成员必须被初始化。在这里初始化为0
  FillMemory(@ol, sizeof(OVERLAPPED), 0);
  ol.hEvent := frmMain.hEvent;

  if frmMain.m_hCommDevice <> 0 then
    DeviceIoControl(frmMain.m_hCommDevice, IOCTL_OVERLAP_BUFFERED_IO, @inData,  Length(inData), @outData, Length(outData), dwReturn, @ol);


  //调用WaitForSingleObject并传递设备内核对象的句柄。WaitForSingleObject会挂起调用线程直至内核对象变成有信号态。
  //设备驱动在它完成I/O后使内核对象有信号。在WaitForSingleObject返回后,I/O被完成 .
  while WaitForSingleObject(frmMain.hEvent,  100) = WAIT_TIMEOUT do
  begin
  end;

  GetOverlappedResult(frmMain.m_hCommDevice, ol, dwReturn, TRUE);
  frmMain.edtBufferd_out.Text := outData;
end;

//这里触发驱动将数据传输回来,异步消息得以完成
procedure TfrmMain.btnNotifyClick(Sender: TObject);
var
  dwReturn:DWORD;
begin
  if m_hCommDevice <> 0 then
    DeviceIoControl(m_hCommDevice, IOCL_OVERLAP_NOTIFY, nil, 0, nil, 0, dwReturn, nil);
end;

//退出时,关闭句柄,这时候如果irp还未处理,即btnNotifyClick这个函数没有触发
//则驱动中会触发取消irp的请求。
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if(m_hCommDevice <> 0) then
    CloseHandle(m_hCommDevice);
  if (hEvent <> 0) then
    CloseHandle(hEvent);
end;

 驱动层代码

//接受到消息的处理函数
NTSTATUS Overlap_IoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS status = STATUS_NOT_SUPPORTED;
    PIO_STACK_LOCATION irpStack = NULL;
    UINT sizeofWrite = 0;

    DbgPrint("Overlap_IoControl\r\n");

    irpStack = IoGetCurrentIrpStackLocation(Irp);    

    if(irpStack)
    {
        switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
        {
            case IOCTL_OVERLAP_BUFFERED_IO:   //异步通信消息
         status = Irp->IoStatus.Status = STATUS_PENDING; 
         Irp->IoStatus.Information = 0;
         IoMarkIrpPending(Irp); 
         gUserMessageIrp = Irp;//保存请求的irp
         IoSetCancelRoutine(Irp, DriverCancelIrp); //设置irp取消例程,在应用程序退出时,触发
         return status; 
      case IOCL_OVERLAP_NOTIFY:                                //获取数据事件 
         COMM_BufferedIo(gUserMessageIrp, irpStack);         //处理原来的irp,将传进来的数据传输出去
                 return status;
      default:
        return status;
        }
    }

  return status;
}

//当通知要获取数据时,获得异步的irp,然后传输数据
NTSTATUS COMM_BufferedIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PVOID pInputBuffer, pOutputBuffer;
  ULONG  outputLength, inputLength;

    DbgPrint("COMM_BufferedIo\r\n");

  outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
    inputLength  = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;
    pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;   //输出缓冲区
    pInputBuffer = Irp->AssociatedIrp.SystemBuffer;    //输入缓冲区

    if(pInputBuffer && pOutputBuffer)
    {              
    DbgPrint("COMM_BufferedIo UserModeMessage = '%s'", pInputBuffer);
        RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);
    Irp->IoStatus.Status = STATUS_SUCCESS; 
    Irp->IoStatus.Information = sizeof(pOutputBuffer); 
    IoCompleteRequest(Irp,IO_NO_INCREMENT); //设置该irp已经完成
        status = STATUS_SUCCESS;
    }
    return status;
}

//取消irp的例程
VOID DriverCancelIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) 
{ 
  //UNREFERENCED_PARAMETER这个宏用于去掉一个函数的参数未用或函数中定义了一个局部变量却从未用过的编译警告
    UNREFERENCED_PARAMETER(DeviceObject);

    KdPrint(("UserMessageCancelIrp....\n"));
    
    if ( Irp == gUserMessageIrp)
        gUserMessageIrp = NULL; 

    Irp->IoStatus.Status = STATUS_CANCELLED; 
    Irp->IoStatus.Information = 0; 
    IoCompleteRequest(Irp,IO_NO_INCREMENT); 
} 

 流程如下:
1、
应用层:
   通知异步消息
   等待返回
驱动层:
   收到消息
   设置irp取消例程
   保存该irp

2、
应用层:
   通知获取数据,即完成异步消息
驱动层:
   拷贝数据到输出缓冲区,完成该irp

在这里我是通过手动的方式来触发异步消息的完成,而不是由系统的消息触发的。主要是为了演示的方便

分享到:
评论

相关推荐

    运用事件应用程序和驱动通讯同步

    应用程序和驱动通讯同步

    windows驱动开发技术详解-part2

    要介绍Windows操作系统内核的基本概念,同时还介绍应用程序和驱动程序之间的通信方法。  2.1 Windows操作系统概述  2.1.1 Windows家族  2.1.2 Windows特性  2.1.3 用户模式和内核模式  2.1.4 操作系统与...

    Windows驱动开发技术详解的光盘-part1

    本章主要介绍Windows操作系统内核的基本概念,同时还介绍应用程序和驱动程序之间的通信方法。  2.1 Windows操作系统概述  2.1.1 Windows家族  2.1.2 Windows特性  2.1.3 用户模式和内核模式  2.1.4 操作...

    win2000驱动程序设计指南

    网络驱动程序设计指南的向导 3 第二章 内核模式驱动程序的网络结构 6 2.1 Windows 2000 网络结构和OSI模型 6 2.2 NDIS驱动程序 7 2.2.1 NDIS微端口驱动程序 7 2.2.2 NDIS中间层驱动程序 8 2.2.3 ...

    网络驱动程序设计指南

    第三部分NDIS中间层驱动程序和TDI驱动程序 189 第一章 NDIS中间层驱动程序 189 1.1中间层驱动程序的DriverEntry函数 191 1.1.1 注册NDIS中间层驱动程序 191 1.1.1.1注册中间层驱动程序的Miniport 192 1.1.1.2注册...

    LINUX设备驱动第三版_588及代码.rar

    总线、设备和驱动程序 类 各环节的整合 热插拔 处理固件 快速索引 第十五章 内存映射和DMA Linux的内存管理 mmap设备操作 执行直接I/O访问 直接内存访问 快速参考 第十六章 块设备驱动程序 注册 块...

    Android驱动开发权威指南

    11.2.1在virtualfifo驱动中增加异步通知 11.2.2在用户空间验证virtualfifo的异步通知 第12章Linux块设备驱动 12.1块设备的I/O操作特点 12.2 Linux块设备驱动结构 12.2.1 block_device_operations结构体 12.2.2 ...

    Windows内核安全驱动开发(随书光盘)

    8.5.4 端口驱动和类驱动之间的协作机制 129 8.5.5 找到关键的回调函数的条件 129 8.5.6 定义常数和数据结构 130 8.5.7 打开两种键盘端口驱动寻找设备 131 8.5.8 搜索在KbdClass类驱动中的地址 133 8.6 Hook键盘...

    Windows内核安全与驱动开发光盘源码

    8.5.4 端口驱动和类驱动之间的协作机制 129 8.5.5 找到关键的回调函数的条件 129 8.5.6 定义常数和数据结构 130 8.5.7 打开两种键盘端口驱动寻找设备 131 8.5.8 搜索在KbdClass类驱动中的地址 133 8.6 Hook键盘...

    visual C++_Turbo C串口通信编程实践

    6.1 PC机异步通信适配器8250及其编程操作 6.1.1 INS8250内部寄存器及其选择方式 6.1.2 波特率设置 6.1.3数据位、奇偶校验、停止位等数据格式设置 6.1.4 查询I/O方式相关设置 6.1.5 中断I/O通信方式相关...

    Visual C++/Turbo C串口通信编程实践及源代码-3

    6.1 pc机异步通信适配器8250及其编程操作 169 6.1.1 ins8250内部寄存器及其选择方式 169 6.1.2 波特率设置 169 6.1.3 数据位、奇偶校验、停止位等数据格式设置 170 6.1.4 查询i/o方式相关设置 171 6.1.5 中断i/...

    Visual C++_Turbo C 串口通信编程实践.(电子工业.龚建伟.熊光明) 第二版 电子版

    6.1 PC机异步通信适配器8250及其编程操作 169 6.1.1 INS8250内部寄存器及其选择方式 169 6.1.2 波特率设置 169 6.1.3 数据位、奇偶校验、停止位等数据格式设置 170 6.1.4 查询I/O方式相关设置 171 6.1.5 中断I/O通信...

    寒江独钓-Windows内核安全编程(高清完整版).part1

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part2

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part7

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part4

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part6

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part5

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

    寒江独钓-Windows内核安全编程(高清完整版).part3

    13.1.3 NDIS中间层驱动的应用 438 13.1.4 NDIS包描述符结构深究 439 13.2 中间层驱动的入口与绑定 442 13.2.1 中间层驱动的入口函数 442 13.2.2 动态绑定NIC设备 443 13.2.3 小端口初始化(MpInitialize) 445 13.3 ...

Global site tag (gtag.js) - Google Analytics