被调用的标准驱动源码和exe的测试代码不变,windows驱动之间同步调用实例 测试代码需要修改打开设备的名称
(一)创建同步IRP实现通讯实例:
演示代码主要仍然是IRP_MJ_READ的派遣函数,
(1)首先是通过iogetdeviceobjectpointer获得标准驱动的设备对象指针和文件对象指针。
(2)使用iobuildsynchornousFsdRequest创建同步的IRP
(3)获得新IRP的下一层堆栈的指针,设备io堆栈的文件对象指针。
(4)调用iocalldriver将新irp发送给打开的设备。
(5)文件对象指针计数减一
(6)派遣函数返回的收尾处理
IRP_MJREAD派遣函数代码:
NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
//获取设备对象指针
UNICODE_STRING usDevName;
RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");
PDEVICE_OBJECT pDevObject;
PFILE_OBJECT pFileObject;
status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
if (!NT_SUCCESS(status))
{
status = STATUS_UNSUCCESSFUL;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
//创建同步IRP
LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
IO_STATUS_BLOCK ioSb;
PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);
//设置io堆栈的文件对象指针
PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);
pNextStack->FileObject = pFileObject;
//调用接口发送irp
status = IoCallDriver(pDevObject,pReadIrp);
if (status == STATUS_PENDING)
{
KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have Returned.."));
status = ioSb.Status;
}
//引用计数减一
ObDereferenceObject(pFileObject);
//收尾操作
status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
KdPrint(("CreateIrp:ReadDispath leave..."));
return status;
}
(二)创建异步IRP实现驱动通讯
创建异步irp使用的函数为iobuildAsynchornousFsdrequest,和iobuildsynchornousfasrequest不同之处便是参数少了Kevent指针,此指针可以通过新创建的IRP的userevent成员传进去,当调用iocompleterequest时,系统将判断irp的userevent子域是否为NULL,若不为NULL则置为有效状态。
代码如下:
NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
//获取设备对象指针
UNICODE_STRING usDevName;
RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");
PDEVICE_OBJECT pDevObject;
PFILE_OBJECT pFileObject;
status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
if (!NT_SUCCESS(status))
{
status = STATUS_UNSUCCESSFUL;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
//创建同步IRP
LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
IO_STATUS_BLOCK ioSb;
//PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);
PIRP pReadIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&ioSb);
pReadIrp->UserEvent = &kEvent;
//设置io堆栈的文件对象指针
PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);
pNextStack->FileObject = pFileObject;
//调用接口发送irp
status = IoCallDriver(pDevObject,pReadIrp);
if (status == STATUS_PENDING)
{
KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have Returned.."));
status = ioSb.Status;
}
//引用计数减一
ObDereferenceObject(pFileObject);
//收尾操作
status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
KdPrint(("CreateIrp:ReadDispath leave..."));
return status;
}
(三)使用通用的ioallocateirp创建irp实现驱动通讯
创建IRP的方式有三种:IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest、IoBuildDeviceIoControlRequest 、IoAllocateIrp等四种方式。其中前三个函数的内部都是调用IoAllocateIrp来实现irp的创建。
IoAllocateIrp创建参数很简单,设备的栈大小和是否在磁盘分配配额。 创建完irp后,需要手动添加irp的众多子域。
代码示例:
NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
//获取设备对象指针
UNICODE_STRING usDevName;
RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");
PDEVICE_OBJECT pDevObject;
PFILE_OBJECT pFileObject;
status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
if (!NT_SUCCESS(status))
{
status = STATUS_UNSUCCESSFUL;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
//创建同步IRP
LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
//PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);
//PIRP pReadIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&ioSb);
PIRP pReadIrp = IoAllocateIrp(pDevObject->StackSize,FALSE);
pReadIrp->UserEvent = &kEvent;
IO_STATUS_BLOCK ioSb;
pReadIrp->UserIosb = &ioSb;
pReadIrp->Tail.Overlay.Thread = PsGetCurrentThread();
//因为被调用的标准驱动的读写方式为DO_BUFFER_IO
pReadIrp->AssociatedIrp.SystemBuffer = NULL;
PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);//设置io堆栈的文件对象指针
pNextStack->MajorFunction = IRP_MJ_READ;//主IRP号
pNextStack->MinorFunction = IRP_MN_NORMAL;//次IRP号
pNextStack->FileObject = pFileObject;//文件对象指针
//调用接口发送irp
status = IoCallDriver(pDevObject,pReadIrp);
if (status == STATUS_PENDING)
{
KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have Returned.."));
status = ioSb.Status;
}
//引用计数减一
ObDereferenceObject(pFileObject);
//收尾操作
status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
KdPrint(("CreateIrp:ReadDispath leave..."));
return status;
}