⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comspy.c

📁 串口过滤驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	case IRP_MN_QUERY_INTERFACE: 
	case IRP_MN_QUERY_CAPABILITIES: 
	case IRP_MN_QUERY_DEVICE_TEXT: 
	case IRP_MN_QUERY_RESOURCES: 
	case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 
	case IRP_MN_READ_CONFIG: 
	case IRP_MN_WRITE_CONFIG: 
	case IRP_MN_EJECT: 
	case IRP_MN_SET_LOCK: 
	case IRP_MN_QUERY_ID: 
	case IRP_MN_QUERY_PNP_DEVICE_STATE: 
	
	default: 
		IoSkipCurrentIrpStackLocation(Irp); 
		status = IoCallDriver(devExt->TargetDeviceObject, Irp); 
		break; 
	} 
    DbgPrint("- ComSpy_Pnp Exit 0x%0x \r\n", status);
	
	return status; 
} 

/*
1. If *you* delay completion of the IRP yourself, do this: 

IoMarkIrpPending(); 
return STATUS_PENDING; 

2. If you want to pass the IRP to another driver and have no interest in 
the result, do this: 

IoSkipCurrentIrpStackLocation(); 
return IoCallDriver(...); 

3. If you *do* care about the result, or if you need to release some 
resource or another, do this: 

IoCopyCurrentIrpStackLocationToNext(); 
IoSetCompletionRoutine(); 
return IoCallDriver(...); 

NTSTATUS CompletionRoutine() 
{ 
if (Irp->PendingReturned) IoMarkIrpPending(); 
... 
return <anything except STATUS_MORE_PROCESSING_REQUIRED>; 
} 

4. If *you* complete the request, do this: 

Irp->IoStatus.Status = <anything but STATUS_PENDING> 
Irp->IoStatus.Information = <something> 
IoCompleteRequest(); 
return <same status you stored in the IRP> 

5. If you want to pass the request down, wait it for it to complete, and 
continue processing in PASSIVE_MODE, do this (but only in a 
non-arbitrary thread context where you know you're allowed to block): 

IoCopyCurrentIrpStackLocationToNext(); 
IoSetCompletionRoutine(Irp, CompletionRoutine, &event, TRUE, TRUE, TRUE); 
if (IoCallDriver() == STATUS_PENDING) KeWaitForSingleObject(&event,...); 

NTSTATUS CompletionRoutine(..., PKEVENT pev) 
{ 
KeSetEvent(pev, ...); 
return STATUS_MORE_PROCESSING_REQUIRED; 
}
*/


/*
RtlInitUnicodeString( &SerialDeviceName,L\"\\\\Device\\\\Serial0\" ); 
// open a handle to SERIAL.SYS & obtain a DEVICE_OBJECT 
status = IoGetDeviceObjectPointer( &SerialDeviceName, 
																	FILE_ALL_ACCESS, 
																	&pFile, 
																	&pSerialDO);//保存在此 
status = ObReferenceObjectByPointer( 
pSerialDO, 
FILE_ALL_ACCESS, 
NULL, 
KernelMode); 

ObDereferenceObject(pFile); 

//然后构建一个irp,发送给获得的串口指针 
KeInitializeEvent( 
&Event, 
NotificationEvent, 
FALSE 
); 
// Build irp to be sent to serial driver 
DeviceControlIrp = IoBuildDeviceIoControlRequest( 
IOCTL_SERIAL_SET_TIMEOUTS,//以此为例子 
pSerialDO, 
RequestBuffer, 
RequestBufferLength, 
ReplyBuffer, 
ReplyBufferLength, 
FALSE, 
&Event, 
&IoStatusBlock 
); 
//发送给获得的串口指针 
status = IoCallDriver(pSerialDO, DeviceControlIrp ); 
就在上面的代码出出错 返回10。 
(1) IoGetDeviceObjectPointer处估计是正确的 
(2) 可能是错在对获得的pSerialDO的使用上,对于这种IoGetDeviceObjectPointer获得的DEVICE_OBJECT,怎么构建irp发送给它呢?有什么规范吗? 
*/



/*
总结应用和驱动之间用事件通讯的办法     
  作者:yansm     
  总结应用和驱动之间用事件通讯的办法     
  1.   驱动中IoCreateNotificationEvent,KeClearEvent     
        应用中OpenEvent(SYNCHRONIZE,   FALSE,   EVENT_NAME)     
        这样,只能在应用中WaitForSingleObject,而不能SetEvent,ResetEvent     
        驱动中可以KeSetEvent,(而且必须紧接着KeClearEvent,因为在应用中不能修改核心态创建的对象的状态,只能在这个时候清除状态了),即只能由驱动通知应用,在某些应用只需要等待通知的场合足够了,如应用等待数据准备好的通知,这时可以在中断处理函数中设置事件有信号     
        注意,OpenEvent第一个参数不能为EVENT_ALL_ACCESS,因为应用没有这么大权限操作在系统上下文创建的事件     
    
  2.在驱动中创建事件,并把时间句柄传给应用,应用不必OpenEvent。应用程序可以随意set,reset事件,这样可以和驱动中的系统线程进行同步     
      这种方法的前提条件是,event是在应用的进程上下文(在系统上下文创建的话就不可以)创建,并传给应用的,比如可以在某个IOCtl分支中创建事件并传给应用。     
  解释:在使用EVENT的PROCESS   context中创的HANDLE就在这个进程的句柄表里,经检验没有权限限制,可以由应用直接使用;而在system   context中创建的HANDLE当然就在SYSTEM进程里啦,若单单传句柄值给应用,而句柄表里根本就没有对应的句柄,当然不成功了。     
    
  代码如下     
  驱动中:     
  void   ppppp(PVOID   event)     
  {     
  KeWaitForSingleObject((PKEVENT)event,Executive,UserMode,0,0);     
  //......验证处     
  }     
  ......     
  WCHAR   wEventNameBuf[]=L"\\BaseNamedObjects\\SharedEvent";     
  UNICODE_STRING   uEventName;     
  PKEVENT   pEvent;     
  HANDLE   hEvent,hThread;     
  ......     
  case   IOCTL_******:     
  RtlInitUnicodeString(&uEventName,wEventNameBuf);     
  pEvent   =   IoCreateNotificationEvent(&uEventName,&hEvent);     
  KeResetEvent(pEvent);     
  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,&hEvent,4);     
  PsCreateSystemThread(&hThread,THREAD_ALL_ACCESS,0,0,0,ppppp,pEvent);     
    
    
  应用中:     
  if(!DeviceIoControl(hDevice,IOCTL_******,0,0,&Handle,4,&Bytes,0))     
  MessageBox("DeviceIo   Error!");     
  esle{     
  wsprintf(str,"%x,%x,%x",hDevice,Bytes,Handle);     
  MessageBox(str);     
  if(!SetEvent((HANDLE)Handle))     
  ......     
  }     
  会看到,点击MessageBox   OK后ppppp的确继续执行了。     
    
  3.在应用中创建事件,然后通过ioctl传给驱动,驱动中ObReferenceObjectByHandle来引用该事件对象。     
  这样应用和驱动中都可以检查和修改事件状态。     
  应用程序:     
  HANDLE   m_hCommEvent   =   CreateEvent(NULL,     
                                                                      false,     
                                                                      false,     
                                                                      NULL);     
  //   download   event   object   to   device   driver,     
  //   m_hCommDevice   is   the   device   object     
    
  DeviceIoControl(m_hCommDevice,     
                                  IO_REFERENCE_EVENT,     
                                  (LPVOID)   m_hCommEvent,     
                                  0,     
                                  NULL,     
                                  0,     
                                  dwReturn,     
                                  NULL);     
  在需要的地方等待     
  while(true)     
  {     
        WaitForSingleObject(m_hCommEvent,   INFINITE);     
        //   After   this   function,   the   event   is   set   to     
        //   non   signaled.   Get   information   and   deal   with   it.     
  }     
    
  驱动程序:     
  case   IO_REFERENCE_EVENT:     
      hEvent   =   (HANDLE)   irpStack->     
                Parameters.DeviceIoControl.Type3InputBuffer;     
    
      status   =   ObReferenceObjectByHandle(hEvent,     
                                                                            GENERIC_ALL,     
                                                                            NULL,     
                                                                            KernelMode,     
                                                                            &gpEventObject,     
                                                                            &objHandleInfo);     
  the   gpEventObject   is   a   PRKEVENT   object,   so   we   can   use   KeEventXXX   and   KeWaitForXXX   to   operate   it.     
  当事件发生时,置信号     
  KeSetEvent(gpEventObject,   0,   FALSE);     
  当不再需要事件对象时:     
  case   IO_DEREFERENCE_EVENT:     
      if(gpEventObject)     
              ObDereferenceObject(gpEventObject);     
      
  

Top
3楼  codewarrior   (会思考的草)   回复于 2004-07-20 16:23:32  得分 0 
怎样在驱动层和应用层建立准消息机制     
  作者:TigerZD     
  怎样在驱动层和应用层建立准消息机制     
  TigerZD     
  驱动程序与应用程序运行与不同的环境又紧密合作,但是应用程序通知驱动程序易(IOCTL等),驱动程序通知应用程序却不易。一般的方法是单纯通过EVENT来进行,但是这种方法有其缺点:     
  1、EVENT只有信号态和非信号态两种区别,不能有附带的参数,因此一个EVENT只能对应一种事件,同时很多时候EVENT并不是在信号态,此时就需要应用程序在线程中等待,一旦事件较多那么线程就会较多,不但线程同步困难,程序也不易读写。     
  2、Windows   98对EVENT操作没有完全支持,像IoCreateXxxEvent并不被支持,因此要获得应用程序创建的事件句柄并不简单,这样驱动程序的通用性也被破坏了。     
  基于以上原因,单纯使用EVENT并不好,那么应该怎么做呢?经过实践,我总结出了一个较好的方法,原理是利用OVERLAPPED的异步调用、同时它又可以带参数的特性。具体做法如下:     
  1、在驱动程序的设备扩展中定义一个IRP变量,并在适当时候(调用IoCreateDevice初始化设备扩展后)初始化其为NULL。如     
  PIRP   UserMessageIrp;     
  2、定义一个IOCTL,如:     
  #define   IOCTL_DRIVER_USERMESSAGE   CTL_CODE(FILE_DEVICE_UNKNOWN,   \     
  0x801,\     
  METHOD_BUFFERED,   \     
  FILE_ANY_ACCESS)     
  3、应用程序在启动或要监控驱动程序的状态时发送该IOCTL到驱动程序,注意应用程序在用CreateFile打开设备连接时一定要带FILE_FLAG_OVERLAPPED参数。     
    
  HANDLE   FileIOWaiter   =   CreateEvent(   NULL,   TRUE,   FALSE,   NULL);     
  if(   FileIOWaiter==NULL)     
  return   GetLastError();     
  OVERLAPPED   ol;     
  ol.Offset   =   0;     
  ol.OffsetHigh   =   0;     
  ol.hEvent   =   FileIOWaiter;     
    
  ULONG   PnpMessage,nBytes;     
  if(!DeviceIoControl(hDevice,//设备句柄     
  IOCTL_DRIVER_USERMESSAGE     
  NULL,     
  0,     
  &PnpMessage,     
  sizeof(PnpMessage),     
  &nBytes,     
  &ol))     
  {     
  if(GetLastError()==ERROR_IO_PENDING)     
  {     
  while(WaitForSingleObject(FileIOWaiter,   100)==WAIT_TIMEOUT)     
  {//驱动程序没有消息传过来,循环等待     
  if(bInstanceisExit   ==   TRUE)//应用程序退出标志     
  {     
  CancelIo(hDevice);//见5     
  }     
  }     
  GetOverlappedResult(hDevice,   &ol,   &nBytes,   FALSE);//     
  //驱动程序有消息传过来,见6,得到数据。     
  }     
  }     
  //处理得到的数据,接7。     
    
  4、驱动程序在接到此IOCTL时如下处理:     
  ioControlCode   =   irpStack->Parameters.DeviceIoControl.IoControlCode;     
  switch(   ioControlCode)     
  {     
  ...     
  case   IOCTL_DRIVER_USERMESSAGE     
  ntStatus   =     
  Irp->IoStatus.Status   =   STATUS_PENDING;     
  Irp->IoStatus.Information   =   0;     
  IoMarkIrpPending(Irp);     
  IoSetCancelRoutine(Irp,DriverUserMessageCancelIrp);//见5     
  deviceExtension->UserMessageIrp   =   Irp;     
  return   STATUS_PENDING;     
  ...     
  }     
    
  5、定义IRP的Cancel例程,这是在应用程序要退出而驱动程序并没有完成该IRP时调用。     
  VOID   DriverUserMessageCancelIrp(     
  IN   PDEVICE_OBJECT   DeviceObject,     
  IN   PIRP   Irp)     
  {     
  PDEVICE_EXTENSION   deviceExtension;     
    
  deviceExtension   =   (PDEVICE_EXTENSION)     
  DeviceObject->DeviceExtension;     
    
  IoReleaseCancelSpinLock(Irp->CancelIrql);     
    
  //   If   this   is   our   queued   read,   then   unqueue   it     
  if(   Irp==deviceExtension->UserMessageIrp)     
  {     
  deviceExtension->UserMessageIrp   =   NULL;     
  }     
  //   Whatever   Irp   it   is,   just   cancel   it     
  Irp->IoStatus.Status   =   STATUS_CANCELLED;     
  Irp->IoStatus.Information   =   0;     
  IoCompleteRequest(Irp,IO_NO_INCREMENT);     
  }     
  6、在驱动程序需要通知应用程序时,举个例子,设备拔出时在处理IRP_MN_REMOVE_DEVICE时,在调用IoDetachDevice之前:     
  (#define   PNP_REMOVE_DEVICE   0   //驱动程序和应用程序共同定义的消息类型)     
  ...     
  ntStatus   =   DriverProcessUserMessageIrp(DeviceObject,PNP_REMOVE_DEVICE);     
  ...     
  //DriverProcessUserPnpIrp的定义如下:     
  NTSTATUS     
  DriverProcessUserMessageIrp(     
  IN   PDEVICE_OBJECT   DeviceObject,     
  ULONG   ProcessReason)     
  {     
  NTSTATUS   ntStatus;     
  PVOID   ioBuffer;     
  ULONG   outputBufferLength;     
  PIO_STACK_LOCATION   irpStack;     
  PIRP   Irp;     
  PDEVICE_EXTENSION   deviceExtension;     
    
  deviceExtension   =   (PDEVICE_EXTENSION)     
  DeviceObject->DeviceExtension;     
    
  Irp   =   deviceExtension->UserMessageIrp;     
  if(Irp   ==   NULL)     
  return   STATUS_SUCCESS;//这种情况是在设备启动后,应用程序并没有发送     
  //过该IRP,设备又要卸载时出现。     
    
  irpStack   =   IoGetCurrentIrpStackLocation   (Irp);     
    
  //   get   pointers   and   lengths   of   the   caller's   (user's)   IO   buffer     
  ioBuffer   =   Irp->AssociatedIrp.SystemBuffer;     
  outputBufferLength   =   irpStack->Parameters.DeviceIoControl.OutputBufferLength;     
    
  if(ioBuffer!=NULL   &&   sizeof(ProcessReason)<=outputBufferLength)     
  {     
  RtlCopyMemory(ioBuffer,     
  &ProcessReason,     
  sizeof(ProcessReason));     
  }     
  Irp->IoStatus.Status   =   STATUS_SUCCESS;     
  Irp->IoStatus.Information   =   sizeof(ProcessReason);     
    
  IoSetCancelRoutine(Irp,NULL);//取消Cancel例程。     
  IoCompleteRequest(Irp,IO_NO_INCREMENT);     
  return   STATUS_SUCCESS;     
  }     
  7、此时应用程序的OVERLAPPED的EVENT会置位,WaitForSingleObject结束等待,应用程序应如此处理:     
  switch(PnpMessage)//定义见3,是不是很像Windows消息处理例程?:)     
  {     
  ...     
  case   PNP_REMOVE_DEVICE:     
  //处理过程就不必写了吧。     
  break;     
  ...     
  }     
  至此驱动程序和应用程序就完成了一次消息传递,其余可类似循环。     
  以上程序段在98和2000下都经过测试。     
  TigerZD   .2002.7.11.(完) 
*/

/*
驱动程序里:
// 分配与应用程序共享的内存
   SystemVirtualAddress = ExAllocatePool(NonPagedPool, 1500);
   Mdl = IoAllocateMdl(SystemVirtualAddress, 1500, FALSE, FALSE, NULL);
   MmBuildMdlForNonPagedPool(Mdl);


// 将分配的内存映射到用户进程地址空间,并返回地址。
case IO_GET_SHAREMEMORY_ADDR:
                       try
           {
               UserVirtualAddress = MmMapLockedPages(Mdl, UserMode); 
               *((PVOID *)(Irp->AssociatedIrp.SystemBuffer)) = UserVirtualAddress;
               Irp->IoStatus.Status = STATUS_SUCCESS; 
               Irp->IoStatus.Information = sizeof(PVOID);
           }
           except(EXCEPTION_EXECUTE_HANDLER){}

在应用程序里:
DeviceIoControl(m_hDevice, 
                       IO_GET_SHAREMEMORY_ADDR, 
                       NULL, 
                       NULL, 
                       szOutputBuffer, 
                       sizeof(szOutputBuffer), 
                       &dwReturn, 
                       NULL 
                       );
psharememory = *((PVOID *)szOutputBuffer);
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -