Windows 驱动之间的通信

来源:互联网 发布:购物车的数据库设计 编辑:程序博客网 时间:2024/06/05 09:44

本文主要介绍windows NT驱动之间利用CTL_CODE如何通信。一般来讲,用户态的应用程序通过调用CreateFile和DeviceIOControl就可以和内核态驱动之间进行通信,如果是内核态的一个驱动程序想和另外一个驱动程序进行类似操作又如何实现呢,接下来会做详细的说明。

主要的思路是首先得到另外一个驱动的handle,再构建一个IRP,赋予必要的参数,再把这个IRP发送给另外一个驱动,等待另外一个驱动处理完毕后获取返回的数据。具体代码如下: 

PIRP SMBIrp;
PIO_STACK_LOCATION      irpStack;

RtlInitUnicodeString(
&usDeviceToFilter, L"/Device/AdvSMBus");
status 
= IoGetDeviceObjectPointer(&usDeviceToFilter,FILE_WRITE_DATA,&SMBusObject,&g_LM87Data.SmbHc);
if!NT_SUCCESS(status) )
{
  KdPrint((
"LM87: Can't get SMBus host! "));
}

SMBIrp 
= IoAllocateIrp (g_LM87Data.SmbHc->StackSize, FALSE);
if(!SMBIrp)
{
  KdPrint((
"LM87: Allocate irp failed! "));
}

irpStack 
= IoGetNextIrpStackLocation(SMBIrp);            
g_LM87Data.SMBusHostData.Address 
= LM87_SMBUS_ADDRESS;
g_LM87Data.SMBusHostData.Offset 
= LM87_INTER_TEMP_REGISTER;
g_LM87Data.SMBusHostData.Data 
= 0x0;             
irpStack
->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpStack
->Parameters.DeviceIoControl.IoControlCode      = IOCTL_SMBUS_READ_BYTE;
irpStack
->Parameters.DeviceIoControl.InputBufferLength  = sizeof(SMBUS_HOST);
irpStack
->Parameters.DeviceIoControl.OutputBufferLength = sizeof(SMBUS_HOST);
SMBIrp
->AssociatedIrp.SystemBuffer = &g_LM87Data.SMBusHostData;                    
IoSetCompletionRoutine (SMBIrp, LM87RequestComplete, 
&g_LM87Data.SyncEvent, TRUE, TRUE, TRUE);
IoCallDriver (g_LM87Data.SmbHc, SMBIrp);
KeWaitForSingleObject(
&g_LM87Data.SyncEvent, Executive, KernelMode, FALSE, NULL);
KdPrint((
"LM87: query result is [%X] ",g_LM87Data.SMBusHostData.Data));
result[
1= g_LM87Data.SMBusHostData.Data * 10//compatible with DiagAnywhere
IoFreeIrp(SMBIrp);    

 在上面的这段代码中,我们先用IoGetDeviceObjectPointer得到另外一个驱动的handle,然后利用IoAllocateIrp生成一个IRP,在赋完必要的参数之后通过IoCallDriver发送给另外一个驱动,这里需要注意的是在IoCallDriver之前有IoSetCompletionRoution的调用,当另外一个驱动处理完这个IRP之后进入它所设定的Roution之中,通过一个Event我们就知道IRP已经处理完毕,我们可以获取相要的数据了。

NTSTATUS
LM87RequestComplete (
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp,
    IN PVOID                Context
    )
{
    PKEVENT         Event;

    Event 
= (PKEVENT) Context;
    KeSetEvent (Event, IO_NO_INCREMENT, FALSE);
    
return STATUS_MORE_PROCESSING_REQUIRED;
}

这样就实现了在内核态的一个驱动程序和另外一个驱动程序的通信。另外还有一种实现的方式是通过WorKItem和IoBuildDeviceIoControlRequest来实现,这里就不做详细的介绍了。